]> git.saurik.com Git - apple/libsecurity_codesigning.git/commitdiff
libsecurity_codesigning-55004.tar.gz mac-os-x-107 mac-os-x-1071 mac-os-x-1072 v55004
authorApple <opensource@apple.com>
Tue, 5 Apr 2011 22:43:25 +0000 (22:43 +0000)
committerApple <opensource@apple.com>
Tue, 5 Apr 2011 22:43:25 +0000 (22:43 +0000)
97 files changed:
APPLE_LICENSE [new file with mode: 0644]
Info-security_codesigning.plist [new file with mode: 0644]
dtrace/codesign-watch.d [new file with mode: 0755]
dtrace/reqint.d [new file with mode: 0755]
lib/CSCommon.h
lib/CSCommonPriv.h [new file with mode: 0644]
lib/Code.cpp
lib/Code.h
lib/CodeSigner.cpp
lib/CodeSigner.h
lib/Requirements.cpp
lib/Requirements.h
lib/SecCode.cpp
lib/SecCode.h
lib/SecCodeHost.cpp
lib/SecCodeHost.h
lib/SecCodeHostLib.c
lib/SecCodeHostLib.h
lib/SecCodePriv.h [new file with mode: 0644]
lib/SecCodeSigner.cpp
lib/SecCodeSigner.h
lib/SecIntegrityLib.c
lib/SecRequirement.cpp
lib/SecRequirement.h
lib/SecRequirementPriv.h [new file with mode: 0644]
lib/SecStaticCode.cpp
lib/SecStaticCode.h
lib/SecStaticCodePriv.h [new file with mode: 0644]
lib/SecTask.c [new file with mode: 0644]
lib/SecTask.h [new file with mode: 0644]
lib/StaticCode.cpp
lib/StaticCode.h
lib/bundlediskrep.cpp
lib/bundlediskrep.h
lib/cdbuilder.cpp
lib/cdbuilder.h
lib/cfmdiskrep.cpp
lib/cfmdiskrep.h
lib/cfmunge.cpp [deleted file]
lib/cfmunge.h [deleted file]
lib/codedirectory.cpp
lib/codedirectory.h
lib/cs.cpp
lib/cs.h
lib/csdatabase.cpp [new file with mode: 0644]
lib/csdatabase.h [new file with mode: 0644]
lib/cserror.cpp
lib/cserror.h
lib/csgeneric.cpp
lib/csgeneric.h
lib/cskernel.cpp
lib/cskernel.h
lib/csutilities.cpp
lib/csutilities.h
lib/detachedrep.cpp [new file with mode: 0644]
lib/detachedrep.h [new file with mode: 0644]
lib/diskrep.cpp
lib/diskrep.h
lib/filediskrep.cpp
lib/filediskrep.h
lib/foreigndiskrep.cpp [deleted file]
lib/foreigndiskrep.h [deleted file]
lib/kerneldiskrep.cpp
lib/kerneldiskrep.h
lib/macho++.cpp [deleted file]
lib/macho++.h [deleted file]
lib/machorep.cpp
lib/machorep.h
lib/renum.cpp
lib/reqdumper.cpp
lib/reqinterp.cpp
lib/reqinterp.h
lib/reqmaker.h
lib/reqparser.cpp
lib/reqparser.h
lib/reqreader.cpp
lib/reqreader.h
lib/requirement.cpp
lib/requirement.h
lib/resources.cpp
lib/resources.h
lib/security_codesigning.d [new file with mode: 0644]
lib/security_codesigning.exp
lib/sigblob.cpp
lib/signer.cpp
lib/signer.h
lib/signerutils.cpp
lib/signerutils.h
lib/singlediskrep.cpp
lib/singlediskrep.h
lib/slcrep.cpp [new file with mode: 0644]
lib/slcrep.h [new file with mode: 0644]
libsecurity_codesigning.xcodeproj/project.pbxproj
req/ppc-host.ireq [new file with mode: 0644]
req/ppc.ireqs [deleted file]
req/workaround.ireqs [deleted file]
requirements.grammar

diff --git a/APPLE_LICENSE b/APPLE_LICENSE
new file mode 100644 (file)
index 0000000..71fe6fd
--- /dev/null
@@ -0,0 +1,335 @@
+APPLE PUBLIC SOURCE LICENSE
+Version 2.0 -  August 6, 2003
+
+Please read this License carefully before downloading this software.  By
+downloading or using this software, you are agreeing to be bound by the terms
+of this License.  If you do not or cannot agree to the terms of this License,
+please do not download or use the software.
+
+Apple Note:  In January 2007, Apple changed its corporate name from "Apple
+Computer, Inc." to "Apple Inc."  This change has been reflected below and
+copyright years updated, but no other changes have been made to the APSL 2.0.
+
+1.     General; Definitions.  This License applies to any program or other
+work which Apple Inc. ("Apple") makes publicly available and which contains a
+notice placed by Apple identifying such program or work as "Original Code" and
+stating that it is subject to the terms of this Apple Public Source License
+version 2.0 ("License").  As used in this License:
+
+1.1     "Applicable Patent Rights" mean:  (a) in the case where Apple is the
+grantor of rights, (i) claims of patents that are now or hereafter acquired,
+owned by or assigned to Apple and (ii) that cover subject matter contained in
+the Original Code, but only to the extent necessary to use, reproduce and/or
+distribute the Original Code without infringement; and (b) in the case where
+You are the grantor of rights, (i) claims of patents that are now or hereafter
+acquired, owned by or assigned to You and (ii) that cover subject matter in
+Your Modifications, taken alone or in combination with Original Code.
+
+1.2    "Contributor" means any person or entity that creates or contributes to
+the creation of Modifications.
+
+1.3     "Covered Code" means the Original Code, Modifications, the combination
+of Original Code and any Modifications, and/or any respective portions thereof.
+
+1.4    "Externally Deploy" means: (a) to sublicense, distribute or otherwise
+make Covered Code available, directly or indirectly, to anyone other than You;
+and/or (b) to use Covered Code, alone or as part of a Larger Work, in any way
+to provide a service, including but not limited to delivery of content, through
+electronic communication with a client other than You.
+
+1.5    "Larger Work" means a work which combines Covered Code or portions
+thereof with code not governed by the terms of this License.
+
+1.6    "Modifications" mean any addition to, deletion from, and/or change to,
+the substance and/or structure of the Original Code, any previous
+Modifications, the combination of Original Code and any previous Modifications,
+and/or any respective portions thereof.  When code is released as a series of
+files, a Modification is:  (a) any addition to or deletion from the contents of
+a file containing Covered Code; and/or (b) any new file or other representation
+of computer program statements that contains any part of Covered Code. 
+
+1.7    "Original Code" means (a) the Source Code of a program or other work as
+originally made available by Apple under this License, including the Source
+Code of any updates or upgrades to such programs or works made available by
+Apple under this License, and that has been expressly identified by Apple as
+such in the header file(s) of such work; and (b) the object code compiled from
+such Source Code and originally made available by Apple under this License
+
+1.8    "Source Code" means the human readable form of a program or other work
+that is suitable for making modifications to it, including all modules it
+contains, plus any associated interface definition files, scripts used to
+control compilation and installation of an executable (object code).
+
+1.9    "You" or "Your" means an individual or a legal entity exercising rights
+under this License.  For legal entities, "You" or "Your" includes any entity
+which controls, is controlled by, or is under common control with, You, where
+"control" means (a) the power, direct or indirect, to cause the direction or
+management of such entity, whether by contract or otherwise, or (b) ownership
+of fifty percent (50%) or more of the outstanding shares or beneficial
+ownership of such entity.
+
+2.     Permitted Uses; Conditions & Restrictions.   Subject to the terms and
+conditions of this License, Apple hereby grants You, effective on the date You
+accept this License and download the Original Code, a world-wide, royalty-free,
+non-exclusive license, to the extent of Apple's Applicable Patent Rights and
+copyrights covering the Original Code, to do the following:
+
+2.1    Unmodified Code.  You may use, reproduce, display, perform, internally
+distribute within Your organization, and Externally Deploy verbatim, unmodified
+copies of the Original Code, for commercial or non-commercial purposes,
+provided that in each instance:
+
+(a)    You must retain and reproduce in all copies of Original Code the
+copyright and other proprietary notices and disclaimers of Apple as they appear
+in the Original Code, and keep intact all notices in the Original Code that
+refer to this License; and
+
+(b)    You must include a copy of this License with every copy of Source Code
+of Covered Code and documentation You distribute or Externally Deploy, and You
+may not offer or impose any terms on such Source Code that alter or restrict
+this License or the recipients' rights hereunder, except as permitted under
+Section 6.
+
+2.2    Modified Code.  You may modify Covered Code and use, reproduce,
+display, perform, internally distribute within Your organization, and
+Externally Deploy Your Modifications and Covered Code, for commercial or
+non-commercial purposes, provided that in each instance You also meet all of
+these conditions:
+
+(a)    You must satisfy all the conditions of Section 2.1 with respect to the
+Source Code of the Covered Code; 
+
+(b)    You must duplicate, to the extent it does not already exist, the notice
+in Exhibit A in each file of the Source Code of all Your Modifications, and
+cause the modified files to carry prominent notices stating that You changed
+the files and the date of any change; and
+
+(c)    If You Externally Deploy Your Modifications, You must make Source Code
+of all Your Externally Deployed Modifications either available to those to whom
+You have Externally Deployed Your Modifications, or publicly available.  Source
+Code of Your Externally Deployed Modifications must be released under the terms
+set forth in this License, including the license grants set forth in Section 3
+below, for as long as you Externally Deploy the Covered Code or twelve (12)
+months from the date of initial External Deployment, whichever is longer. You
+should preferably distribute the Source Code of Your Externally Deployed
+Modifications electronically (e.g. download from a web site).
+
+2.3    Distribution of Executable Versions.  In addition, if You Externally
+Deploy Covered Code (Original Code and/or Modifications) in object code,
+executable form only, You must include a prominent notice, in the code itself
+as well as in related documentation, stating that Source Code of the Covered
+Code is available under the terms of this License with information on how and
+where to obtain such Source Code.  
+
+2.4    Third Party Rights.  You expressly acknowledge and agree that although
+Apple and each Contributor grants the licenses to their respective portions of
+the Covered Code set forth herein, no assurances are provided by Apple or any
+Contributor that the Covered Code does not infringe the patent or other
+intellectual property rights of any other entity. Apple and each Contributor
+disclaim any liability to You for claims brought by any other entity based on
+infringement of intellectual property rights or otherwise. As a condition to
+exercising the rights and licenses granted hereunder, You hereby assume sole
+responsibility to secure any other intellectual property rights needed, if any.
+For example, if a third party patent license is required to allow You to
+distribute the Covered Code, it is Your responsibility to acquire that license
+before distributing the Covered Code.
+
+3.     Your Grants.  In consideration of, and as a condition to, the licenses
+granted to You under this License, You hereby grant to any person or entity
+receiving or distributing Covered Code under this License a non-exclusive,
+royalty-free, perpetual, irrevocable license, under Your Applicable Patent
+Rights and other intellectual property rights (other than patent) owned or
+controlled by You, to use, reproduce, display, perform, modify, sublicense,
+distribute and Externally Deploy Your Modifications of the same scope and
+extent as Apple's licenses under Sections 2.1 and 2.2 above.  
+
+4.     Larger Works.  You may create a Larger Work by combining Covered Code
+with other code not governed by the terms of this License and distribute the
+Larger Work as a single product.  In each such instance, You must make sure the
+requirements of this License are fulfilled for the Covered Code or any portion
+thereof. 
+
+5.     Limitations on Patent License.   Except as expressly stated in Section
+2, no other patent rights, express or implied, are granted by Apple herein.
+Modifications and/or Larger Works may require additional patent licenses from
+Apple which Apple may grant in its sole discretion.  
+
+6.     Additional Terms.  You may choose to offer, and to charge a fee for,
+warranty, support, indemnity or liability obligations and/or other rights
+consistent with the scope of the license granted herein ("Additional Terms") to
+one or more recipients of Covered Code. However, You may do so only on Your own
+behalf and as Your sole responsibility, and not on behalf of Apple or any
+Contributor. You must obtain the recipient's agreement that any such Additional
+Terms are offered by You alone, and You hereby agree to indemnify, defend and
+hold Apple and every Contributor harmless for any liability incurred by or
+claims asserted against Apple or such Contributor by reason of any such
+Additional Terms. 
+
+7.     Versions of the License.  Apple may publish revised and/or new versions
+of this License from time to time.  Each version will be given a distinguishing
+version number.  Once Original Code has been published under a particular
+version of this License, You may continue to use it under the terms of that
+version. You may also choose to use such Original Code under the terms of any
+subsequent version of this License published by Apple.  No one other than Apple
+has the right to modify the terms applicable to Covered Code created under this
+License.  
+
+8.     NO WARRANTY OR SUPPORT.  The Covered Code may contain in whole or in
+part pre-release, untested, or not fully tested works.  The Covered Code may
+contain errors that could cause failures or loss of data, and may be incomplete
+or contain inaccuracies.  You expressly acknowledge and agree that use of the
+Covered Code, or any portion thereof, is at Your sole and entire risk.  THE
+COVERED CODE IS PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR SUPPORT OF
+ANY KIND AND APPLE AND APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE"
+FOR THE PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM
+ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY, OF
+SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY, OF
+QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.  APPLE AND EACH
+CONTRIBUTOR DOES NOT WARRANT AGAINST INTERFERENCE WITH YOUR ENJOYMENT OF THE
+COVERED CODE, THAT THE FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR
+REQUIREMENTS, THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR
+ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED.  NO ORAL OR
+WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE AUTHORIZED
+REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY.  You acknowledge
+that the Covered Code is not intended for use in the operation of nuclear
+facilities, aircraft navigation, communication systems, or air traffic control
+machines in which case the failure of the Covered Code could lead to death,
+personal injury, or severe physical or environmental damage.
+
+9.     LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO
+EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL, SPECIAL,
+INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO THIS LICENSE OR
+YOUR USE OR INABILITY TO USE THE COVERED CODE, OR ANY PORTION THEREOF, WHETHER
+UNDER A THEORY OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE), PRODUCTS
+LIABILITY OR OTHERWISE, EVEN IF APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL
+PURPOSE OF ANY REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF
+LIABILITY OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT
+APPLY TO YOU. In no event shall Apple's total liability to You for all damages
+(other than as may be required by applicable law) under this License exceed the
+amount of fifty dollars ($50.00).
+
+10.    Trademarks.  This License does not grant any rights to use the
+trademarks or trade names  "Apple", "Mac", "Mac OS", "QuickTime", "QuickTime
+Streaming Server" or any other trademarks, service marks, logos or trade names
+belonging to Apple (collectively "Apple Marks") or to any trademark, service
+mark, logo or trade name belonging to any Contributor.  You agree not to use
+any Apple Marks in or as part of the name of products derived from the Original
+Code or to endorse or promote products derived from the Original Code other
+than as expressly permitted by and in strict compliance at all times with
+Apple's third party trademark usage guidelines which are posted at
+http://www.apple.com/legal/guidelinesfor3rdparties.html.  
+
+11.    Ownership. Subject to the licenses granted under this License, each
+Contributor retains all rights, title and interest in and to any Modifications
+made by such Contributor.  Apple retains all rights, title and interest in and
+to the Original Code and any Modifications made by or on behalf of Apple
+("Apple Modifications"), and such Apple Modifications will not be automatically
+subject to this License.  Apple may, at its sole discretion, choose to license
+such Apple Modifications under this License, or on different terms from those
+contained in this License or may choose not to license them at all.  
+
+12.    Termination.  
+
+12.1   Termination.  This License and the rights granted hereunder will
+terminate:
+
+(a)    automatically without notice from Apple if You fail to comply with any
+term(s) of this License and fail to cure such breach within 30 days of becoming
+aware of such breach;
+(b)    immediately in the event of the circumstances described in Section
+13.5(b); or
+(c)    automatically without notice from Apple if You, at any time during the
+term of this License, commence an action for patent infringement against Apple;
+provided that Apple did not first commence an action for patent infringement
+against You in that instance.
+
+12.2   Effect of Termination.  Upon termination, You agree to immediately stop
+any further use, reproduction, modification, sublicensing and distribution of
+the Covered Code.  All sublicenses to the Covered Code which have been properly
+granted prior to termination shall survive any termination of this License.
+Provisions which, by their nature, should remain in effect beyond the
+termination of this License shall survive, including but not limited to
+Sections 3, 5, 8, 9, 10, 11, 12.2 and 13.  No party will be liable to any other
+for compensation, indemnity or damages of any sort solely as a result of
+terminating this License in accordance with its terms, and termination of this
+License will be without prejudice to any other right or remedy of any party.
+
+13.    Miscellaneous.
+
+13.1   Government End Users.   The Covered Code is a "commercial item" as
+defined in FAR 2.101.  Government software and technical data rights in the
+Covered Code include only those rights customarily provided to the public as
+defined in this License. This customary commercial license in technical data
+and software is provided in accordance with FAR 12.211 (Technical Data) and
+12.212 (Computer Software) and, for Department of Defense purchases, DFAR
+252.227-7015 (Technical Data -- Commercial Items) and 227.7202-3 (Rights in
+Commercial Computer Software or Computer Software Documentation).  Accordingly,
+all U.S. Government End Users acquire Covered Code with only those rights set
+forth herein.
+
+13.2   Relationship of Parties.  This License will not be construed as
+creating an agency, partnership, joint venture or any other form of legal
+association between or among You, Apple or any Contributor, and You will not
+represent to the contrary, whether expressly, by implication, appearance or
+otherwise.
+
+13.3   Independent Development.   Nothing in this License will impair Apple's
+right to acquire, license, develop, have others develop for it, market and/or
+distribute technology or products that perform the same or similar functions
+as, or otherwise compete with, Modifications, Larger Works, technology or
+products that You may develop, produce, market or distribute.
+
+13.4   Waiver; Construction.  Failure by Apple or any Contributor to enforce
+any provision of this License will not be deemed a waiver of future enforcement
+of that or any other provision.  Any law or regulation which provides that the
+language of a contract shall be construed against the drafter will not apply to
+this License.
+
+13.5   Severability.  (a) If for any reason a court of competent jurisdiction
+finds any provision of this License, or portion thereof, to be unenforceable,
+that provision of the License will be enforced to the maximum extent
+permissible so as to effect the economic benefits and intent of the parties,
+and the remainder of this License will continue in full force and effect.  (b)
+Notwithstanding the foregoing, if applicable law prohibits or restricts You
+from fully and/or specifically complying with Sections 2 and/or 3 or prevents
+the enforceability of either of those Sections, this License will immediately
+terminate and You must immediately discontinue any use of the Covered Code and
+destroy all copies of it that are in your possession or control.
+
+13.6   Dispute Resolution.  Any litigation or other dispute resolution between
+You and Apple relating to this License shall take place in the Northern
+District of California, and You and Apple hereby consent to the personal
+jurisdiction of, and venue in, the state and federal courts within that
+District with respect to this License. The application of the United Nations
+Convention on Contracts for the International Sale of Goods is expressly
+excluded.
+
+13.7   Entire Agreement; Governing Law.  This License constitutes the entire
+agreement between the parties with respect to the subject matter hereof.  This
+License shall be governed by the laws of the United States and the State of
+California, except that body of California law concerning conflicts of law. 
+
+Where You are located in the province of Quebec, Canada, the following clause
+applies:  The parties hereby confirm that they have requested that this License
+and all related documents be drafted in English. Les parties ont exigé que le
+présent contrat et tous les documents connexes soient rédigés en anglais. 
+
+EXHIBIT A. 
+
+"Portions Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.
+
+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." 
+
diff --git a/Info-security_codesigning.plist b/Info-security_codesigning.plist
new file mode 100644 (file)
index 0000000..0c67376
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict/>
+</plist>
diff --git a/dtrace/codesign-watch.d b/dtrace/codesign-watch.d
new file mode 100755 (executable)
index 0000000..64aa5fd
--- /dev/null
@@ -0,0 +1,368 @@
+#!/usr/sbin/dtrace -q -s
+/*
+ * Demonstration D script for watching Code Signing activity in the system
+ *
+ * As presented, this script will record and report all Code Signing activity
+ * in one process (argument=pid), or all processes (argument='*').
+ * You are encouraged to modify it as you will. (A good start is to comment out
+ * the print statements you don't like to see.)
+ */
+typedef uint64_t DTHandle;             /* generic API handle (NOT a pointer) */
+typedef uint8_t Hash[20];              /* SHA-1 */
+
+typedef struct {                               /* from implementation */
+       uint32_t cputype;
+       uint32_t cpusubtype;
+       off_t offset;
+       uint8_t fileOnly;
+} DiskRepContext;
+
+
+/*
+ * Local variables used for suitable casting (only)
+ */
+self uint8_t *hash;
+
+
+/*
+ * Startup (this may take a while)
+ */
+:::BEGIN
+{
+       printf("Ready...\n");
+}
+
+
+/*
+ * Finishing (add statistics tracers here)
+ */
+:::END
+{
+}
+
+
+/*
+ * Track kernel-related objects.
+ * Each process has their own, and they're usually created very early.
+ */
+struct {
+       DTHandle rep;                           /* DiskRep */
+       DTHandle staticCode;            /* static code */
+       DTHandle code;                          /* dynamic code */
+} kernel[pid_t];
+
+
+/*
+ * Track DiskRep objects.
+ * DiskReps are drivers for on-disk formats. Beyond their natural concerns,
+ * they also carry the path information for StaticCode objects.
+ */
+typedef struct {
+       DTHandle me;                            /* own handle, if valid */
+       string path;                            /* canonical path */
+       string type;                            /* type string */
+       DiskRepContext ctx;                     /* construction context, if any */
+       DTHandle sub;                           /* sub-DiskRep if any */
+} DiskRep;
+DiskRep rep[DTHandle];                 /* all the DiskReps we've seen */
+
+self uint64_t ctx;                             /* passes construction context, NULL if none */
+
+codesign$1:::diskrep-create-*  /* preset none */
+{ self->ctx = 0; }
+
+codesign$1:::diskrep-create-kernel
+{
+       rep[arg0].me = kernel[pid].rep = arg0;
+       rep[arg0].path = "(kernel)";
+       rep[arg0].type = "kernel";
+       printf("%8u %s[%d]%s(%p,KERNEL)\n",
+               timestamp, execname, pid, probename, arg0);
+}
+
+codesign$1:::diskrep-create-macho
+{
+       rep[arg0].me = arg0;
+       rep[arg0].path = copyinstr(arg1);
+       rep[arg0].type = "macho";
+       self->ctx = arg2;
+       printf("%8u %s[%d]%s(%p,%s)\n",
+               timestamp, execname, pid, probename, arg0, rep[arg0].path);
+}
+
+codesign$1:::diskrep-create-bundle-path
+{
+       rep[arg0].me = arg0;
+       rep[arg0].path = copyinstr(arg1);
+       rep[arg0].type = "bundle";
+       self->ctx = arg2;
+       rep[arg0].sub = arg3;
+       printf("%8u %s[%d]%s(%p,%s,%p)\n",
+               timestamp, execname, pid, probename,
+               arg0, rep[arg0].path, rep[arg0].sub);
+}
+
+codesign$1:::diskrep-create-bundle-ref
+{
+       rep[arg0].me = arg0;
+       rep[arg0].path = "(from ref)";
+       rep[arg0].type = "bundle";
+       self->ctx = arg2;
+       rep[arg0].sub = arg3;
+       printf("%8u %s[%d]%s(%p,%s,%p)\n",
+               timestamp, execname, pid, probename,
+               arg0, rep[arg0].path, rep[arg0].sub);
+}
+
+codesign$1:::diskrep-create-file
+{
+       rep[arg0].me = arg0;
+       rep[arg0].path = copyinstr(arg1);
+       rep[arg0].type = "file";
+       printf("%8u %s[%d]%s(%p,%s)\n",
+               timestamp, execname, pid, probename, arg0, rep[arg0].path);
+}
+
+self DiskRepContext *ctxp;
+
+codesign$1:::diskrep-create-*
+/ self->ctx /
+{
+       self->ctxp = (DiskRepContext *)copyin(self->ctx, sizeof(DiskRepContext));
+       rep[arg0].ctx = *self->ctxp;
+       printf("%8u %s[%d] ...context: arch=(0x%x,0x%x) offset=0x%x file=%d\n",
+               timestamp, execname, pid,
+               self->ctxp->cputype, self->ctxp->cpusubtype,
+               self->ctxp->offset, self->ctxp->fileOnly);
+}
+
+codesign$1:::diskrep-destroy
+{
+       printf("%8u %s[%d]%s(%p,%s)\n",
+               timestamp, execname, pid, probename, arg0, rep[arg0].path);
+       rep[arg0].me = 0;
+}
+
+
+/*
+ * Track Code Signing API objects
+ */
+typedef struct {
+       DTHandle me;
+       DTHandle host;
+       DTHandle staticCode;    /* lazily acquired */
+       uint8_t *hash;                  /* dynamic hash from identify() */
+} Code;
+Code code[DTHandle];
+
+typedef struct {
+       DTHandle me;
+       DTHandle rep;
+       uint8_t *hash;                  /* static hash from ...::cdHash() */
+} StaticCode;
+StaticCode staticCode[DTHandle];
+
+
+codesign$1:::static-create
+/ arg1 == kernel[pid].rep /
+{
+       staticCode[arg0].me = kernel[pid].staticCode = arg0;
+       staticCode[arg0].rep = arg1;
+       printf("%8u %s[%d]%s(%p=KERNEL[%p])\n",
+               timestamp, execname, pid, probename, arg0, arg1);
+}
+
+codesign$1:::static-create
+/ arg1 != kernel[pid].rep /
+{
+       staticCode[arg0].me = arg0;
+       staticCode[arg0].rep = arg1;
+       printf("%8u %s[%d]%s(%p,%s[%p])\n",
+               timestamp, execname, pid, probename, arg0, rep[arg1].path, arg1);
+}
+
+codesign$1:::dynamic-create
+/ arg1 == 0 /
+{
+       code[arg0].me = kernel[pid].code = arg0;
+       printf("%8u %s[%d]%s(%p=KERNEL)\n",
+               timestamp, execname, pid, probename, arg0);
+}
+
+codesign$1:::dynamic-create
+/ arg1 == kernel[pid].code /
+{
+       code[arg0].me = arg0;
+       printf("%8u %s[%d]%s(%p,<KERNEL>)\n",
+               timestamp, execname, pid, probename, arg0);
+}
+
+codesign$1:::dynamic-create
+/ arg1 != 0 && arg1 != kernel[pid].code /
+{
+       code[arg0].me = arg0;
+       code[arg0].host = arg1;
+       printf("%8u %s[%d]%s(%p,%p)\n",
+               timestamp, execname, pid, probename, arg0, arg1);
+}
+
+security_debug$1:::sec-destroy
+/ code[arg0].me == arg0 /
+{
+       code[arg0].me = 0;
+       printf("%8u %s[%d]destroy code(%p)\n",
+               timestamp, execname, pid, arg0);
+}
+
+security_debug$1:::sec-destroy
+/ staticCode[arg0].me == arg0 /
+{
+       staticCode[arg0].me = 0;
+       printf("%8u %s[%d]destroy staticCode(%p)\n",
+               timestamp, execname, pid, arg0);
+}
+
+
+/*
+ * Identification operations
+ */
+codesign$1:::guest-identify-*
+{
+       printf("%8u %s[%d]%s(%p,%d,%s[%p])\n",
+               timestamp, execname, pid, probename,
+               arg0, arg1, rep[staticCode[arg2].rep].path, arg2);
+       code[arg0].staticCode = arg2;
+}
+
+codesign$1:::guest-cdhash-*
+{
+       self->hash = code[arg0].hash = (uint8_t *)copyin(arg1, sizeof(Hash));
+       printf("%8u %s[%d]%s(%p,H\"%02x%02x%02x...%02x%02x\")\n",
+               timestamp, execname, pid, probename, arg0,
+               self->hash[0], self->hash[1], self->hash[2], self->hash[18], self->hash[19]);
+}
+
+codesign$1:::static-cdhash
+{
+       self->hash = staticCode[arg0].hash = (uint8_t *)copyin(arg1, sizeof(Hash));
+       printf("%8u %s[%d]%s(%p,H\"%02x%02x%02x...%02x%02x\")\n",
+               timestamp, execname, pid, probename, arg0,
+               self->hash[0], self->hash[1], self->hash[2], self->hash[18], self->hash[19]);
+}
+
+
+/*
+ * Guest registry/proxy management in securityd
+ */
+typedef struct {
+       DTHandle guest;
+       string path;
+       uint32_t status;
+       uint8_t *hash;
+} SDGuest;
+SDGuest guests[DTHandle, DTHandle];            /* host x guest */
+
+securityd*:::host-register
+{
+       printf("%8u HOST DYNAMIC(%p,%d)\n",
+               timestamp, arg0, arg1);
+}
+
+securityd*:::host-proxy
+{
+       printf("%8u HOST PROXY(%p,%d)\n",
+               timestamp, arg0, arg1);
+}
+
+securityd*:::host-unregister
+{
+       printf("%8u HOST DESTROYED(%p)\n",
+               timestamp, arg0);
+}
+
+securityd*:::guest-create
+{
+       guests[arg0, arg2].guest = arg2;
+       guests[arg0, arg2].path = copyinstr(arg5);
+       guests[arg0, arg2].status = arg3;
+       printf("%8u GUEST CREATE(%p,%s[0x%x],host=0x%x,status=0x%x,flags=%d)\n",
+               timestamp,
+               arg0, guests[arg0, arg2].path, arg2, arg1, arg3, arg4);
+}
+
+securityd*:::guest-cdhash
+/ arg2 != 0 /
+{
+       self->hash = guests[arg0, arg1].hash = (uint8_t *)copyin(arg2, sizeof(Hash));
+       printf("%8u GUEST HASH(%p,%s[0x%x],H\"%02x%02x%02x...%02x%02x\")\n",
+               timestamp,
+               arg0, guests[arg0, arg1].path, arg1,
+               self->hash[0], self->hash[1], self->hash[2], self->hash[18], self->hash[19]);
+}
+
+securityd*:::guest-cdhash
+/ arg2 == 0 /
+{
+       printf("%8u GUEST HASH(%p,%s[0x%x],NONE)\n",
+               timestamp, arg0, guests[arg0, arg1].path, arg1);
+}
+
+securityd*:::guest-change
+{
+       printf("%8u GUEST CHANGE(%p,%s[0x%x],status=0x%x)\n",
+               timestamp,
+               arg0, guests[arg0, arg1].path, arg1, arg2);
+}
+
+securityd*:::guest-destroy
+{
+       printf("%8u GUEST DESTROY(%p,%s[0x%x])\n",
+               timestamp,
+               arg0, guests[arg0, arg1].path, arg1);
+}
+
+
+/*
+ * Signing Mach-O allocation tracking
+ */
+codesign$1:::allocate-arch
+{
+       printf("%8u %s[%d]%s(%s,%d)\n",
+               timestamp, execname, pid, probename, copyinstr(arg0), arg1);
+}
+
+codesign$1:::allocate-archn
+{
+       printf("%8u %s[%d]%s((0x%x,0x%x),%d)\n",
+               timestamp, execname, pid, probename, arg0, arg1,  arg2);
+}
+
+codesign$1:::allocate-write
+{
+       printf("%8u %s[%d]%s(%s,offset 0x%x,%d of %d)\n",
+               timestamp, execname, pid, probename,
+               copyinstr(arg0), arg1, arg2, arg3);
+}
+
+codesign$1:::allocate-validate
+{
+       printf("%8u %s[%d]%s(%s,%d)\n",
+               timestamp, execname, pid, probename, copyinstr(arg0), arg1);
+}
+
+
+/*
+ * Evaluation tracking
+ */
+codesign$1:::eval-dynamic-start
+{
+       printf("%8u %s[%d]%s(%p,%s)\n",
+               timestamp, execname, pid, probename, arg0, copyinstr(arg1));
+}
+
+codesign$1:::eval-dynamic-end
+{
+       printf("%8u %s[%d]%s(%p)\n",
+               timestamp, execname, pid, probename, arg0);
+}
+
diff --git a/dtrace/reqint.d b/dtrace/reqint.d
new file mode 100755 (executable)
index 0000000..1663261
--- /dev/null
@@ -0,0 +1,133 @@
+#!/usr/sbin/dtrace -q -s
+
+
+string opnames[unsigned];      /* common opcode names */
+
+
+dtrace:::BEGIN
+{
+       printf("ready...\n");
+       opnames[0] = "never";
+       opnames[1] = "always";
+       opnames[2] = "identifier...";
+       opnames[3] = "anchor apple";
+       opnames[4] = "anchor = ...";
+       opnames[5] = "!legacy infokey!";
+       opnames[6] = "AND";
+       opnames[7] = "OR";
+       opnames[8] = "cdhash";
+       opnames[9] = "NOT";
+       opnames[10] = "info[...]";
+       opnames[11] = "cert[subject...]";
+       opnames[12] = "anchor trusted...";
+       opnames[13] = "anchor trusted...";
+       opnames[14] = "cert[field...]";
+       opnames[15] = "anchor apple generic";
+       opnames[16] = "entitlement[...]";
+       opnames[17] = "cert[policy...]";
+       opnames[18] = "anchor NAMED";
+       opnames[19] = "(NAMED)";
+}
+
+
+codesign*:::eval-reqint-start
+{
+       printf("%8u %s[%d] START(%p,%d)\n",
+               timestamp, execname, pid,
+               arg0, arg1);
+}
+
+codesign*:::eval-reqint-end
+{
+       @eval[arg1] = count();
+}
+
+codesign*:::eval-reqint-end
+/ arg1 == 0 /
+{
+       printf("%8u %s[%d] SUCCESS\n",
+               timestamp, execname, pid);
+}
+
+codesign*:::eval-reqint-end
+/ arg1 == 4294900246 /
+{
+       printf("%8u %s[%d] FAIL\n",
+               timestamp, execname, pid);
+}
+
+codesign*:::eval-reqint-end
+/ arg1 != 4294900246 && arg1 != 0 /
+{
+       printf("%8u %s[%d] FAIL(%d)\n",
+               timestamp, execname, pid,
+               arg1);
+}
+
+codesign*:::eval-reqint-unknown*
+{
+       printf("%8u %s[%d] %s(%d)\n",
+               timestamp, execname, pid, probename,
+               arg0);
+}
+
+codesign*:::eval-reqint-fragment-load
+/ arg2 != 0 /
+{
+       printf("%8u %s[%d] frag-load(%s,%s,%p)\n",
+               timestamp, execname, pid,
+               copyinstr(arg0), copyinstr(arg1), arg2);
+       @fragload[copyinstr(arg0), copyinstr(arg1)] = count();
+       @fraguse[copyinstr(arg0), copyinstr(arg1)] = count();
+}
+
+codesign*:::eval-reqint-fragment-load
+/ arg2 == 0 /
+{
+       printf("%8u %s[%d] frag-load(%s,%s,FAILED)\n",
+               timestamp, execname, pid,
+               copyinstr(arg0), copyinstr(arg1));
+       @fragload[copyinstr(arg0), copyinstr(arg1)] = count();
+       @fraguse[copyinstr(arg0), copyinstr(arg1)] = count();
+}
+
+codesign*:::eval-reqint-fragment-hit
+{
+       printf("%8u %s[%d] frag-hit(%s,%s)\n",
+               timestamp, execname, pid,
+               copyinstr(arg0), copyinstr(arg1));
+       @fraguse[copyinstr(arg0), copyinstr(arg1)] = count();
+}
+
+
+/*
+ * Trace opcodes as they're encountered and evaluated
+ */
+codesign*:::eval-reqint-op
+{
+       self->traced = 0;
+       @opcodes[arg0] = count();
+}
+
+codesign*:::eval-reqint-op
+/ !self->traced /
+{
+       printf("%8u %s[%d] %s\n", timestamp, execname, pid,
+               opnames[arg0]);
+}
+
+
+/*
+ * Print out aggregates at the end
+ */
+dtrace:::END
+{
+       printf("\nREQUIREMENT EVALUATIONS:\n");
+       printa("\t%d (%@d)\n", @eval);
+
+       printf("\nREQUIREMENT OPCODES EVALUATED:\n");
+       printa("\t%5d (%@d)\n", @opcodes);
+       
+       printf("\nFRAGMENTS LOADED:\n");
+       printa("\t%s %s (%@d)\n", @fragload);
+}
index 564165f4f95b849dde801db91d59af5b12ae53c3..beaaaf4b5b0aec27d17f33c816ea29b0693baaa1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -42,58 +42,69 @@ extern "C" {
        [Assigned range 0xFFFE_FAxx].
 */
 enum {
-       errSecCSUnimplemented = -67072,         /* unimplemented code signing feature */
-       errSecCSInvalidObjectRef,                       /* invalid API object reference */
-       errSecCSInvalidFlags,                           /* invalid or inapprpopriate API flag(s) specified */
-       errSecCSObjectRequired,                         /* a required pointer argument was NULL */
-       errSecCSStaticCodeNotFound,                     /* cannot find code object on disk */
-       errSecCSUnsupportedGuestAttributes,     /* cannot locate guests using this attribute set */
-       errSecCSInvalidAttributeValues,         /* given attribute values are invalid */
-       errSecCSNoSuchCode,                                     /* host has no guest with the requested attributes */
-       errSecCSMultipleGuests,                         /* host has multiple guests with this attribute value */
-       errSecCSGuestInvalid,                           /* code identity has been invalidated */
-       errSecCSUnsigned,                                       /* code object is not signed */
-       errSecCSSignatureFailed,                        /* code or signature modified */
-       errSecCSSignatureNotVerifiable,                 /* signature cannot be read, e.g., due to a filesystem that maps root to an unprivileged user */
-       errSecCSSignatureUnsupported,           /* unsupported type or version of signature */
-       errSecCSBadDictionaryFormat,            /* a required plist file or resource is malformed */
-       errSecCSResourcesNotSealed,                     /* resources are not sealed by signature */
-       errSecCSResourcesNotFound,                      /* cannot find sealed resources in code */
-       errSecCSResourcesInvalid,                       /* the sealed resource directory is invalid */
-       errSecCSBadResource,                            /* a sealed resource is missing or invalid */
-       errSecCSResourceRulesInvalid,           /* invalid resource selection rule(s) */
-       errSecCSReqInvalid,                                     /* invalid or corrupted code requirement(s) */
-       errSecCSReqUnsupported,                         /* unsupported type or version of code requirement(s) */
-       errSecCSReqFailed,                                      /* failed to satisfy code requirement(s) */
-       errSecCSBadObjectFormat,                        /* object file format invalid or unsuitable */
-       errSecCSInternalError,                          /* internal error in Code Signing subsystem */
-       errSecCSHostReject,                                     /* code rejected its host */
-       errSecCSNotAHost,                                       /* this code is not a host */
-       errSecCSSignatureInvalid,                       /* invalid format for signature */
-       errSecCSHostProtocolRelativePath,       /* host protocol violation - absolute guest path required */
-       errSecCSHostProtocolContradiction,      /* host protocol violation - contradictory hosting modes */
-       errSecCSHostProtocolDedicationError, /* host protocol violation - operation not allowed with/for a dedicated guest */
-       errSecCSHostProtocolNotProxy,           /* host protocol violation - proxy hosting not engaged */
-       errSecCSHostProtocolStateError,         /* host protocol violation - invalid guest state change request */
-       errSecCSHostProtocolUnrelated,          /* host protocol violation - the given guest is not a guest of the given host */
-       errSecCSInvalidOperation,                       /* requested operation is not valid */
-       errSecCSNotSupported,                           /* operation not supported for this type of code */
-       errSecCSCMSTooLarge,                            /* signature too large to embed */
+       errSecCSUnimplemented =                         -67072, /* unimplemented code signing feature */
+       errSecCSInvalidObjectRef =                      -67071, /* invalid API object reference */
+       errSecCSInvalidFlags =                          -67070, /* invalid or inappropriate API flag(s) specified */
+       errSecCSObjectRequired =                        -67069, /* a required pointer argument was NULL */
+       errSecCSStaticCodeNotFound =            -67068, /* cannot find code object on disk */
+       errSecCSUnsupportedGuestAttributes = -67067, /* cannot locate guests using this attribute set */
+       errSecCSInvalidAttributeValues =        -67066, /* given attribute values are invalid */
+       errSecCSNoSuchCode =                            -67065, /* host has no guest with the requested attributes */
+       errSecCSMultipleGuests =                        -67064, /* ambiguous guest specification (host has multiple guests with these attribute values) */
+       errSecCSGuestInvalid =                          -67063, /* code identity has been invalidated */
+       errSecCSUnsigned =                                      -67062, /* code object is not signed at all */
+       errSecCSSignatureFailed =                       -67061, /* invalid signature (code or signature have been modified) */
+       errSecCSSignatureNotVerifiable =        -67060, /* the code cannot be read by the verifier (file system permissions etc.) */
+       errSecCSSignatureUnsupported =          -67059, /* unsupported type or version of signature */
+       errSecCSBadDictionaryFormat =           -67058, /* a required plist file or resource is malformed */
+       errSecCSResourcesNotSealed =            -67057, /* resources are present but not sealed by signature */
+       errSecCSResourcesNotFound =                     -67056, /* code has no resources but signature indicates they must be present */
+       errSecCSResourcesInvalid =                      -67055, /* the sealed resource directory is invalid */
+       errSecCSBadResource =                           -67054, /* a sealed resource is missing or invalid */
+       errSecCSResourceRulesInvalid =          -67053, /* invalid resource specification rule(s) */
+       errSecCSReqInvalid =                            -67052, /* invalid or corrupted code requirement(s) */
+       errSecCSReqUnsupported =                        -67051, /* unsupported type or version of code requirement(s) */
+       errSecCSReqFailed =                                     -67050, /* code failed to satisfy specified code requirement(s) */
+       errSecCSBadObjectFormat =                       -67049, /* object file format unrecognized, invalid, or unsuitable */
+       errSecCSInternalError =                         -67048, /* internal error in Code Signing subsystem */
+       errSecCSHostReject =                            -67047, /* code rejected its host */
+       errSecCSNotAHost =                                      -67046, /* attempt to specify guest of code that is not a host */
+       errSecCSSignatureInvalid =                      -67045, /* invalid or unsupported format for signature */
+       errSecCSHostProtocolRelativePath =      -67044, /* host protocol violation - absolute guest path required */
+       errSecCSHostProtocolContradiction =     -67043, /* host protocol violation - contradictory hosting modes */
+       errSecCSHostProtocolDedicationError = -67042, /* host protocol violation - operation not allowed with/for a dedicated guest */
+       errSecCSHostProtocolNotProxy =          -67041, /* host protocol violation - proxy hosting not engaged */
+       errSecCSHostProtocolStateError =        -67040, /* host protocol violation - invalid guest state change request */
+       errSecCSHostProtocolUnrelated =         -67039, /* host protocol violation - the given guest is not a guest of the given host */
+                                                                        /* -67038 obsolete (no longer issued) */
+       errSecCSNotSupported =                          -67037, /* operation inapplicable or not supported for this type of code */
+       errSecCSCMSTooLarge =                           -67036, /* signature too large to embed (size limitation of on-disk representation) */
+       errSecCSHostProtocolInvalidHash =       -67035, /* host protocol violation - invalid guest hash */
+       errSecCSStaticCodeChanged =                     -67034, /* the code on disk does not match what is running */
+       errSecCSSigDBDenied =                           -67033, /* permission to use the system signature database denied */
+       errSecCSSigDBAccess =                           -67032, /* cannot access system signature database */
+       errSecCSHostProtocolInvalidAttribute = -67031, /* host returned invalid or inconsistent guest attributes */
+       errSecCSInfoPlistFailed =                       -67030, /* invalid Info.plist (plist or signature have been modified) */
+       errSecCSNoMainExecutable =                      -67029, /* the code has no main executable file */
 };
 
 
 /*
  * Code Signing specific CFError "user info" keys.
  * In calls that can return CFErrorRef indications, if a CFErrorRef is actually
- * returned, its "user info" dictionary will contain some (but not all) of the
- * following keys to more closely describe the circumstances of the failure.
+ * returned, its "user info" dictionary may contain some of the following keys
+ * to more closely describe the circumstances of the failure.
+ * Do not rely on the presence of any particular key to categorize a problem;
+ * always use the primary OSStatus return for that. The data contained under
+ * these keys is always supplemental and optional.
  */
+extern const CFStringRef kSecCFErrorArchitecture;      /* CFStringRef: name of architecture causing the problem */
 extern const CFStringRef kSecCFErrorPattern;           /* CFStringRef: invalid resource selection pattern encountered */
 extern const CFStringRef kSecCFErrorResourceSeal;      /* CFTypeRef: invalid component in resource seal (CodeResources) */
 extern const CFStringRef kSecCFErrorResourceAdded;     /* CFURLRef: unsealed resource found */
 extern const CFStringRef kSecCFErrorResourceAltered; /* CFURLRef: modified resource found */
 extern const CFStringRef kSecCFErrorResourceMissing; /* CFURLRef: sealed (non-optional) resource missing */
-extern const CFStringRef kSecCFErrorInfoPlist;         /* CFTypeRef: Info.plist dictionary or component found invalid */
+extern const CFStringRef kSecCFErrorInfoPlist;         /* CFTypeRef: Info.plist dictionary or component thereof found invalid */
 extern const CFStringRef kSecCFErrorGuestAttributes; /* CFTypeRef: Guest attribute set of element not accepted */
 extern const CFStringRef kSecCFErrorRequirementSyntax; /* CFStringRef: compilation error for Requirement source */
 
@@ -126,7 +137,7 @@ typedef struct __SecRequirement *SecRequirementRef; /* code requirement */
        An abstract handle to identify a particular Guest in the context of its Host.
        
        Guest handles are assigned by the host at will, with kSecNoGuest (zero) being
-       reserved as the null value). They can be reused for new children if desired.
+       reserved as the null value. They can be reused for new children if desired.
 */
 typedef u_int32_t SecGuestRef;
 
@@ -136,7 +147,7 @@ enum {
 
 
 /*!
-       @typddef SecCSFlags
+       @typedef SecCSFlags
        This is the type of flags arguments to Code Signing API calls.
        It provides a bit mask of request and option flags. All of the bits in these
        masks are reserved to Apple; if you set any bits not defined in these headers,
@@ -175,7 +186,7 @@ enum {
        @constant kSecCodeSignatureHost
        Indicates that the code may act as a host that controls and supervises guest
        code. If this flag is not set in a code signature, the code is never considered
-       eligible to be a host, and any attempt to act like one will be ignored.
+       eligible to be a host, and any attempt to act like one will be ignored or rejected.
        @constant kSecCodeSignatureAdhoc
        The code has been sealed without a signing identity. No identity may be retrieved
        from it, and any code requirement placing restrictions on the signing identity
@@ -190,10 +201,10 @@ enum {
        Implicitly set the "kill" status bit for the code when it starts running.
        This bit indicates that the code wishes to be terminated with prejudice if
        it is ever invalidated. Since the kill bit is sticky, setting this option bit
-       guarantees that the code will always be valid, since it will die immediately
-       if it becomes invalid.
+       guarantees that the code will always be dynamically valid, since it will die
+       immediately     if it becomes invalid.
        @constant kSecCodeSignatureForceExpiration
-       Forces the kSecCSConsiderExpiration on all validations of the code.
+       Forces the kSecCSConsiderExpiration flag on all validations of the code.
  */
 typedef uint32_t SecCodeSignatureFlags;
 
@@ -202,21 +213,70 @@ enum {
        kSecCodeSignatureAdhoc = 0x0002,                /* must be used without signer */
        kSecCodeSignatureForceHard = 0x0100,    /* always set HARD mode on launch */
        kSecCodeSignatureForceKill = 0x0200,    /* always set KILL mode on launch */
-       kSecCodeSignatureForceExpiration = 0x0400, /* force certificat expiration checks */
+       kSecCodeSignatureForceExpiration = 0x0400, /* force certificate expiration checks */
+};
+
+
+/*!
+       @typedef SecCodeStatus
+       The code signing system attaches a set of status flags to each running code.
+       These flags are maintained by the code's host, and can be read by anyone.
+       A code may change its own flags, a host may change its guests' flags,
+       and root may change anyone's flags.     However, these flags are sticky in that
+       each can change in only one direction (and never back, for the lifetime of the code).
+       Not even root can violate this restriction.
+
+       There are other flags in SecCodeStatus that are not publicly documented.
+       Do not rely on them, and do not ever attempt to explicitly set them.
+
+       @constant kSecCodeStatusValid
+       Indicates that the code is dynamically valid, i.e. it started correctly
+       and has not been invalidated since then. The valid bit can only be cleared.
+       
+       Warning: This bit is not your one-stop shortcut to determining the validity     of code.
+       It represents the dynamic component of the full validity function; if this
+       bit is unset, the code is definitely invalid, but the converse is not always true.
+       In fact, code hosts may represent the outcome of some delayed static validation work in this bit,
+       and thus it strictly represents a blend of (all of) dynamic and (some of) static validity,
+       depending on the implementation of the particular host managing the code. You can (only)
+       rely that (1) dynamic invalidation will clear this bit; and (2) the combination
+       of static validation and dynamic validity (as performed by the SecCodeCheckValidity* APIs)
+       will give a correct answer.
+       
+       @constant kSecCodeStatusHard
+       Indicates that the code prefers to be denied access to resources if gaining access
+       would invalidate it. This bit can only be set.
+       It is undefined whether code that is marked hard and is already invalid will still
+       be denied access to a resource that would invalidate it if it were still valid. That is,
+       the code may or may not get access to such a resource while being invalid, and that choice
+       may appear random.
+       
+       @constant kSecCodeStatusKill
+       Indicates that the code wants to be killed (terminated) if it ever loses its validity.
+       This bit can only be set. Code that has the kill flag set will never be dynamically invalid
+       (and live). Note however that a change in static validity does not necessarily trigger instant
+       death.
+*/
+typedef uint32_t SecCodeStatus;
+enum {
+       kSecCodeStatusValid =   0x0001,
+       kSecCodeStatusHard =    0x0100,
+       kSecCodeStatusKill =    0x0200,
 };
 
 
 /*!
        @typedef SecRequirementType
        An enumeration indicating different types of internal requirements for code.
-*/
+ */
 typedef uint32_t SecRequirementType;
 
 enum {
-       kSecHostRequirementType = 1,                    /* what hosts may run us */
-       kSecGuestRequirementType = 2,                   /* what guests we may run */
-       kSecDesignatedRequirementType = 3,              /* designated requirement */
-       kSecLibraryRequirementType = 4,                 /* what libraries we may link against */
+       kSecHostRequirementType =                       1,      /* what hosts may run us */
+       kSecGuestRequirementType =                      2,      /* what guests we may run */
+       kSecDesignatedRequirementType =         3,      /* designated requirement */
+       kSecLibraryRequirementType =            4,      /* what libraries we may link against */
+       kSecPluginRequirementType =                     5,      /* what plug-ins we may load */
        kSecInvalidRequirementType,                             /* invalid type of Requirement (must be last) */
        kSecRequirementTypeCount = kSecInvalidRequirementType /* number of valid requirement types */
 };
diff --git a/lib/CSCommonPriv.h b/lib/CSCommonPriv.h
new file mode 100644 (file)
index 0000000..e341362
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2006-2010 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@
+ */
+
+/*!
+       @header CSCommonPriv
+       SecStaticCodePriv is the private counter-part to CSCommon. Its contents are not
+       official API, and are subject to change without notice.
+*/
+#ifndef _H_CSCOMMONPRIV
+#define _H_CSCOMMONPRIV
+
+#include <Security/CSCommon.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*!
+       @typedef SecCodeDirectoryFlagTable
+       This constant array can be used to translate between names and values
+       of CodeDirectory flag bits. The table ends with an entry with NULL name.
+       The elements are in no particular order.
+       @field name The official text name of the flag.
+       @field value The binary value of the flag.
+       @field signable True if the flag can be specified during signing. False if it is set
+       internally and can only be read from a signature.
+ */
+typedef struct {
+       const char *name;
+       uint32_t value;
+       bool signable;
+} SecCodeDirectoryFlagTable;
+
+extern const SecCodeDirectoryFlagTable kSecCodeDirectoryFlagTable[];
+
+
+/*!
+       Blob types (magic numbers) for blobs used by Code Signing.
+       
+       @constant kSecCodeMagicRequirement Magic number for individual code requirements.
+       @constant kSecCodeMagicRequirementSet Magic number for a collection of
+       individual code requirements, indexed by requirement type. This is used
+       for internal requirement sets.
+       @constant kSecCodeMagicCodeDirectory Magic number for a CodeDirectory.
+       @constant kSecCodeMagicEmbeddedSignature Magic number for a SuperBlob
+       containing all the signing components that are usually embedded within
+       a main executable.
+       @constant kSecCodeMagicDetachedSignature Magic number for a SuperBlob that
+       contains all the data for all architectures of a signature, including any
+       data that is usually written to separate files. This is the format of
+       detached signatures if the program is capable of having multiple architectures.
+       @constant kSecCodeMagicEntitlement Magic number for a standard entitlement blob.
+       @constant kSecCodeMagicByte The first byte (in NBO) shared by all these magic
+       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 */
+       kSecCodeMagicRequirementSet = 0xfade0c01,       /* requirement set */
+       kSecCodeMagicCodeDirectory = 0xfade0c02,        /* CodeDirectory */
+       kSecCodeMagicEmbeddedSignature = 0xfade0cc0, /* single-architecture embedded signature */
+       kSecCodeMagicDetachedSignature = 0xfade0cc1, /* detached multi-architecture signature */
+       kSecCodeMagicEntitlement = 0xfade7171,          /* entitlement blob */
+       
+       kSecCodeMagicByte = 0xfa                                        /* shared first byte */
+};
+
+
+/*!
+       Types of cryptographic digests (hashes) used to hold code signatures
+       together.
+
+       Each combination of type, length, and other parameters is a separate
+       hash type; we don't understand "families" here.
+
+       These type codes govern the digest links that connect a CodeDirectory
+       to its subordinate data structures (code pages, resources, etc.)
+       They do not directly control other uses of hashes (such as the
+       hash-of-CodeDirectory identifiers used in requirements).
+ */
+enum {
+       kSecCodeSignatureNoHash                                                 =  0,   /* null value */
+       kSecCodeSignatureHashSHA1                                               =  1,   /* SHA-1 */
+       kSecCodeSignatureHashSHA256                                             =  2,   /* SHA-256 */
+       kSecCodeSignatureHashPrestandardSkein160x256    = 32,   /* Skein, 160 bits, 256 bit pool */
+       kSecCodeSignatureHashPrestandardSkein256x512    = 33,   /* Skein, 256 bits, 512 bit pool */
+       
+       kSecCodeSignatureDefaultDigestAlgorithm = kSecCodeSignatureHashSHA1
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_H_CSCOMMON
index d1ad41eb6bd532ada508981a1cc2edc0023a8494..ab5072aec05ac5726d264e54f4de488ae3d2b2c7 100644 (file)
@@ -28,9 +28,8 @@
 #include "StaticCode.h"
 #include <Security/SecCodeHost.h>
 #include "cskernel.h"
-#include "cfmunge.h"
+#include <security_utilities/cfmunge.h>
 #include <security_utilities/debugging.h>
-#include <sys/codesign.h>
 
 namespace Security {
 namespace CodeSigning {
@@ -40,8 +39,9 @@ namespace CodeSigning {
 // Construction
 //
 SecCode::SecCode(SecCode *host)
-       : mHost(host)
+       : mHost(host), mIdentified(false)
 {
+       CODESIGN_DYNAMIC_CREATE(this, host);
 }
 
 
@@ -49,7 +49,33 @@ SecCode::SecCode(SecCode *host)
 // Clean up a SecCode object
 //
 SecCode::~SecCode() throw()
+try {
+} catch (...) {
+       return;
+}
+
+
+//
+// CF-level comparison of SecStaticCode objects compares CodeDirectory hashes if signed,
+// and falls back on comparing canonical paths if (both are) not.
+//
+bool SecCode::equal(SecCFObject &secOther)
+{
+       SecCode *other = static_cast<SecCode *>(&secOther);
+       CFDataRef mine = this->cdHash();
+       CFDataRef his = other->cdHash();
+       if (mine || his)
+               return mine && his && CFEqual(mine, his);
+       else
+               return this->staticCode()->equal(*other->staticCode());
+}
+
+CFHashCode SecCode::hash()
 {
+       if (CFDataRef h = this->cdHash())
+               return CFHash(h);
+       else
+               return this->staticCode()->hash();
 }
 
 
@@ -69,15 +95,50 @@ SecCode *SecCode::host() const
 //
 SecStaticCode *SecCode::staticCode()
 {
-       if (!mStaticCode) {
-               mStaticCode.take(this->getStaticCode());
-               secdebug("seccode", "%p got static=%p", this, mStaticCode.get());
+       if (!mIdentified) {
+               this->identify();
+               mIdentified = true;
        }
        assert(mStaticCode);
        return mStaticCode;
 }
 
 
+//
+// Yield the CodeDirectory hash as presented by our host.
+// This usually is the same as the hash of staticCode().codeDirectory(), but might not
+// if files are changing on disk while code is running.
+//
+CFDataRef SecCode::cdHash()
+{
+       if (!mIdentified) {
+               this->identify();
+               mIdentified = true;
+       }
+       return mCDHash;         // can be NULL (host has no dynamic identity for guest)
+}
+
+
+//
+// Retrieve current dynamic status.
+//
+SecCodeStatus SecCode::status()
+{
+       if (this->isRoot())
+               return kSecCodeStatusValid;                     // root of trust, presumed valid
+       else
+               return this->host()->getGuestStatus(this);
+}
+
+void SecCode::status(SecCodeStatusOperation operation, CFDictionaryRef arguments)
+{
+       if (this->isRoot())
+               MacOSError::throwMe(errSecCSHostProtocolStateError);
+       else
+               this->host()->changeGuestStatus(this, operation, arguments);
+}
+
+
 //
 // By default, we have no guests
 //
@@ -88,20 +149,19 @@ SecCode *SecCode::locateGuest(CFDictionaryRef)
 
 
 //
-// By default, we map ourselves to disk using our host's mapping facility.
+// By default, we self-identify by asking our host to identify us.
 // (This is currently only overridden in the root-of-trust (kernel) implementation.)
-// The caller owns the object returned.
 //
-SecStaticCode *SecCode::getStaticCode()
+void SecCode::identify()
 {
-       return host()->mapGuestToStatic(this);
+       mStaticCode.take(host()->identifyGuest(this, &mCDHash.aref()));
 }
 
 
 //
 // The default implementation cannot map guests to disk
 //
-SecStaticCode *SecCode::mapGuestToStatic(SecCode *guest)
+SecStaticCode *SecCode::identifyGuest(SecCode *, CFDataRef *)
 {
        MacOSError::throwMe(errSecCSNoSuchCode);
 }
@@ -118,31 +178,21 @@ SecStaticCode *SecCode::mapGuestToStatic(SecCode *guest)
 // This function validates internal requirements in the hosting chain. It does
 // not validate external requirements - the caller needs to do that with a separate call.
 //
-static const uint8_t interim_hosting_default_requirement[] = {
-       // anchor apple and (identifier com.apple.translate or identifier com.apple.LaunchCFMApp)
-       0xfa, 0xde, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06,
-       0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 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, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x63, 0x6f, 0x6d, 0x2e,
-       0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x4c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x43, 0x46, 0x4d, 0x41,
-       0x70, 0x70, 0x00, 0x00,
-};
-
 void SecCode::checkValidity(SecCSFlags flags)
 {
        if (this->isRoot()) {
                // the root-of-trust is valid by definition
-               secdebug("validator", "%p root of trust is presumed valid", this);
+               CODESIGN_EVAL_DYNAMIC_ROOT(this);
                return;
        }
-       secdebug("validator", "%p begin validating %s",
-               this, this->staticCode()->mainExecutablePath().c_str());
+       DTRACK(CODESIGN_EVAL_DYNAMIC, this, (char*)this->staticCode()->mainExecutablePath().c_str());
        
        //
        // Do not reorder the operations below without thorough cogitation. There are
-       // interesting dependencies and significant performance issues.
+       // interesting dependencies and significant performance issues. There is also
+       // client code that relies on errors being noticed in a particular order.
        //
-       // For the most part, failure of (secure) identity will cause exceptions to be
+       // For the most part, failure of (reliable) identity will cause exceptions to be
        // thrown, and success is indicated by survival. If you make it to the end,
        // you have won the validity race. (Good rat.)
        //
@@ -157,16 +207,18 @@ void SecCode::checkValidity(SecCSFlags flags)
        myDisk->validateDirectory();
 
        // check my own dynamic state
-       if (!(this->host()->getGuestStatus(this) & CS_VALID))
+       if (!(this->host()->getGuestStatus(this) & kSecCodeStatusValid))
                MacOSError::throwMe(errSecCSGuestInvalid);
+       
+       // check that static and dynamic views are consistent
+       if (this->cdHash() && !CFEqual(this->cdHash(), myDisk->cdHash()))
+               MacOSError::throwMe(errSecCSStaticCodeChanged);
 
        // check host/guest constraints
        if (!this->host()->isRoot()) {  // not hosted by root of trust
                myDisk->validateRequirements(kSecHostRequirementType, hostDisk, errSecCSHostReject);
                hostDisk->validateRequirements(kSecGuestRequirementType, myDisk);
        }
-       
-       secdebug("validator", "%p validation successful", this);
 }
 
 
@@ -178,6 +230,11 @@ uint32_t SecCode::getGuestStatus(SecCode *guest)
        MacOSError::throwMe(errSecCSNoSuchCode);
 }
 
+void SecCode::changeGuestStatus(SecCode *guest, SecCodeStatusOperation operation, CFDictionaryRef arguments)
+{
+       MacOSError::throwMe(errSecCSNoSuchCode);
+}
+
 
 //
 // Given a bag of attribute values, automagically come up with a SecCode
@@ -195,6 +252,10 @@ uint32_t SecCode::getGuestStatus(SecCode *guest)
 //
 SecCode *SecCode::autoLocateGuest(CFDictionaryRef attributes, SecCSFlags flags)
 {
+       // special case: with no attributes at all, return the root of trust
+       if (CFDictionaryGetCount(attributes) == 0)
+               return KernelCode::active()->retain();
+       
        // main logic: we need a pid, and we'll take a canonical guest id as an option
        int pid = 0;
        if (!cfscan(attributes, "{%O=%d}", kSecGuestAttributePid, &pid))
@@ -205,7 +266,7 @@ SecCode *SecCode::autoLocateGuest(CFDictionaryRef attributes, SecCSFlags flags)
                code.take(process);             // locateGuest gave us a retained object
                if (code->staticCode()->flag(kSecCodeSignatureHost)) {
                        // might be a code host. Let's find out
-                       CFRef<CFMutableDictionaryRef> rest = CFDictionaryCreateMutableCopy(NULL, 0, attributes);
+                       CFRef<CFMutableDictionaryRef> rest = makeCFMutableDictionary(attributes);
                        CFDictionaryRemoveValue(rest, kSecGuestAttributePid);
                        if (SecCode *guest = code->locateGuest(rest))
                                return guest;
index fca2dfdef193e64788da54ac9f0d7e54ee6b6e0d..715378c21d2ec8c9f4cc254785fcc42b9b731eac 100644 (file)
@@ -44,23 +44,32 @@ class SecStaticCode;
 //
 class SecCode : public SecCFObject {
        NOCOPY(SecCode)
+       friend class KernelCode;        // overrides identify() to set mStaticCode/mCDHash
 public:
        SECCFFUNCTIONS(SecCode, SecCodeRef, errSecCSInvalidObjectRef, gCFObjects().Code)
 
        SecCode(SecCode *host);
     virtual ~SecCode() throw();
        
+    bool equal(SecCFObject &other);
+    CFHashCode hash();
+       
        SecCode *host() const;
        bool isRoot() const { return host() == NULL; }
        SecStaticCode *staticCode();    // cached. Result lives as long as this SecCode
+       CFDataRef cdHash();
+       
+       SecCodeStatus status();                         // dynamic status
+       void status(SecCodeStatusOperation operation, CFDictionaryRef arguments);
 
        // primary virtual drivers. Caller owns the result
-       virtual SecStaticCode *getStaticCode();
+       virtual void identify();
        virtual SecCode *locateGuest(CFDictionaryRef attributes);
-       virtual SecStaticCode *mapGuestToStatic(SecCode *guest);
+       virtual SecStaticCode *identifyGuest(SecCode *guest, CFDataRef *cdhash);
        
        void checkValidity(SecCSFlags flags);
-       virtual uint32_t getGuestStatus(SecCode *guest);
+       virtual SecCodeStatus getGuestStatus(SecCode *guest);
+       virtual void changeGuestStatus(SecCode *guest, SecCodeStatusOperation operation, CFDictionaryRef arguments);
        
 public:
        // perform "autolocation" (root-based heuristic). Caller owns the result
@@ -68,7 +77,9 @@ public:
 
 private:
        SecPointer<SecCode> mHost;
-       SecPointer<SecStaticCode> mStaticCode;
+       bool mIdentified;                                                       // called identify(), mStaticCode & mCDHash are valid
+       SecPointer<SecStaticCode> mStaticCode;          // (static) code origin
+       CFRef<CFDataRef> mCDHash;                                       // (dynamic) CodeDirectory hash as per host
 };
 
 
index 1503ea1f1f0bdabe59de4f871214e22dfdb6b582..361d8fc342243ec21bfdf6a3834308316b2d7077 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -28,6 +28,7 @@
 #include "signer.h"
 #include "reqparser.h"
 #include "renum.h"
+#include "csdatabase.h"
 #include <security_utilities/unix++.h>
 #include <security_utilities/unixchild.h>
 #include <vector>
@@ -61,10 +62,9 @@ public:
 //
 // Construct a SecCodeSigner
 //
-SecCodeSigner::SecCodeSigner()
-       : mRequirements(NULL)
+SecCodeSigner::SecCodeSigner(SecCSFlags flags)
+       : mOpFlags(flags), mRequirements(NULL), mDigestAlgorithm(kSecCodeSignatureDefaultDigestAlgorithm)
 {
-       secdebug("signer", "%p created", this);
 }
 
 
@@ -72,9 +72,10 @@ SecCodeSigner::SecCodeSigner()
 // Clean up a SecCodeSigner
 //
 SecCodeSigner::~SecCodeSigner() throw()
-{
-       secdebug("signer", "%p destroyed", this);
+try {
        ::free((Requirements *)mRequirements);
+} catch (...) {
+       return;
 }
 
 
@@ -83,22 +84,39 @@ SecCodeSigner::~SecCodeSigner() throw()
 //
 void SecCodeSigner::parameters(CFDictionaryRef paramDict)
 {
-       secdebug("signer", "%p loading %d parameters", this, int(CFDictionaryGetCount(paramDict)));
        Parser(*this, paramDict);
        if (!valid())
                MacOSError::throwMe(errSecCSInvalidObjectRef);
 }
 
 
+//
+// Roughly check for validity.
+// This isn't thorough; it just sees if if looks like we've set up the object appropriately.
+//
+bool SecCodeSigner::valid() const
+{
+       if (mOpFlags & kSecCSRemoveSignature)
+               return true;
+       return mSigner;
+}
+
+
 //
 // Sign code
 //
 void SecCodeSigner::sign(SecStaticCode *code, SecCSFlags flags)
 {
-       if (!valid())
-               MacOSError::throwMe(errSecCSInvalidObjectRef);
-       secdebug("signer", "%p will sign %p (flags 0x%x)", this, code, flags);
-       Signer(*this, code).sign(flags);
+       Signer operation(*this, code);
+       if ((flags | mOpFlags) & kSecCSRemoveSignature) {
+               secdebug("signer", "%p will remove signature from %p", this, code);
+               operation.remove(flags);
+       } else {
+               if (!valid())
+                       MacOSError::throwMe(errSecCSInvalidObjectRef);
+               secdebug("signer", "%p will sign %p (flags 0x%x)", this, code, flags);
+               operation.sign(flags);
+       }
        code->resetValidity();
 }
 
@@ -107,7 +125,7 @@ void SecCodeSigner::sign(SecStaticCode *code, SecCSFlags flags)
 // ReturnDetachedSignature is called by writers or editors that try to return
 // detached signature data (rather than annotate the target).
 //
-void SecCodeSigner::returnDetachedSignature(BlobCore *blob)
+void SecCodeSigner::returnDetachedSignature(BlobCore *blob, Signer &signer)
 {
        assert(mDetached);
        if (CFGetTypeID(mDetached) == CFURLGetTypeID()) {
@@ -117,11 +135,32 @@ void SecCodeSigner::returnDetachedSignature(BlobCore *blob)
        } else if (CFGetTypeID(mDetached) == CFDataGetTypeID()) {
                CFDataAppendBytes(CFMutableDataRef(mDetached.get()),
                        (const UInt8 *)blob, blob->length());
+       } else if (CFGetTypeID(mDetached) == CFNullGetTypeID()) {
+               signatureDatabaseWriter().storeCode(blob, signer.path().c_str());
        } else
                assert(false);
 }
 
 
+//
+// Our DiskRep::signingContext methods communicate with the signing subsystem
+// in terms those callers can easily understand.
+//
+string SecCodeSigner::sdkPath(const std::string &path) const
+{
+       assert(path[0] == '/'); // need absolute path here
+       if (mSDKRoot)
+               return cfString(mSDKRoot) + path;
+       else
+               return path;
+}
+
+bool SecCodeSigner::isAdhoc() const
+{
+       return mSigner == SecIdentityRef(kCFNull);
+}
+
+
 //
 // The actual parsing operation is done in the Parser class.
 //
@@ -137,8 +176,6 @@ SecCodeSigner::Parser::Parser(SecCodeSigner &state, CFDictionaryRef parameters)
                        state.mSigner = SecIdentityRef(signer);
                else
                        MacOSError::throwMe(errSecCSInvalidObjectRef);
-       else
-               MacOSError::throwMe(errSecCSInvalidObjectRef);
 
        // the flags need some augmentation
        if (CFNumberRef flags = get<CFNumberRef>(kSecCodeSignerFlags)) {
@@ -146,6 +183,10 @@ SecCodeSigner::Parser::Parser(SecCodeSigner &state, CFDictionaryRef parameters)
                state.mCdFlags = cfNumber<uint32_t>(flags);
        } else
                state.mCdFlagsGiven = false;
+       
+       // digest algorithms are specified as a numeric code
+       if (CFNumberRef digestAlgorithm = get<CFNumberRef>(kSecCodeSignerDigestAlgorithm))
+               state.mDigestAlgorithm = cfNumber<long>(digestAlgorithm);
 
        if (CFNumberRef cmsSize = get<CFNumberRef>(CFSTR("cmssize")))
                state.mCMSSize = cfNumber<size_t>(cmsSize);
@@ -183,8 +224,8 @@ SecCodeSigner::Parser::Parser(SecCodeSigner &state, CFDictionaryRef parameters)
        
        // detached can be (destination) file URL or (mutable) Data to be appended-to
        if (state.mDetached = get<CFTypeRef>(kSecCodeSignerDetached)) {
-               if (CFGetTypeID(state.mDetached) != CFURLGetTypeID()
-                       && CFGetTypeID(state.mDetached) != CFDataGetTypeID())
+               CFTypeID type = CFGetTypeID(state.mDetached);
+               if (type != CFURLGetTypeID() && type != CFDataGetTypeID() && type != CFNullGetTypeID())
                        MacOSError::throwMe(errSecCSInvalidObjectRef);
        }
        
@@ -194,6 +235,8 @@ SecCodeSigner::Parser::Parser(SecCodeSigner &state, CFDictionaryRef parameters)
        
        state.mApplicationData = get<CFDataRef>(kSecCodeSignerApplicationData);
        state.mEntitlementData = get<CFDataRef>(kSecCodeSignerEntitlements);
+       
+       state.mSDKRoot = get<CFURLRef>(kSecCodeSignerSDKRoot);
 }
 
 
index f94feb3d860e85a2a45702ad8adac0870cb8e7a2..f3e8b8f60ec93e62a0fce12f8ae3f63c55ca19ee 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -41,37 +41,45 @@ namespace CodeSigning {
 // A SecCode object represents running code in the system. It must be subclassed
 // to implement a particular notion of code.
 //
-class SecCodeSigner : public SecCFObject {
+class SecCodeSigner : public SecCFObject, public DiskRep::SigningContext {
        NOCOPY(SecCodeSigner)
+public:
+       class Parser;
+       class Signer;
+
 public:
        SECCFFUNCTIONS(SecCodeSigner, SecCodeSignerRef, errSecCSInvalidObjectRef, gCFObjects().CodeSigner)
 
-       SecCodeSigner();
+       SecCodeSigner(SecCSFlags flags);
     virtual ~SecCodeSigner() throw();
        
        void parameters(CFDictionaryRef args);  // parse and set parameters
-       bool valid() const { return mSigner; }
+       bool valid() const;
        
        void sign(SecStaticCode *code, SecCSFlags flags);
+       void remove(SecStaticCode *code, SecCSFlags flags);
        
-       void returnDetachedSignature(BlobCore *blob);
-
-public:
-       class Parser;
-       class Signer;
+       void returnDetachedSignature(BlobCore *blob, Signer &signer);
+       
+protected:
+       std::string sdkPath(const std::string &path) const;
+       bool isAdhoc() const;
        
 private:
        // parsed parameter set
+       SecCSFlags mOpFlags;                    // operation flags
        CFRef<SecIdentityRef> mSigner;  // signing identity
        CFRef<CFTypeRef> mDetached;             // detached-signing information (NULL => attached)
        CFRef<CFDictionaryRef> mResourceRules; // explicit resource collection rules (override)
        CFRef<CFDateRef> mSigningTime;  // signing time desired (kCFNull for none)
        CFRef<CFDataRef> mApplicationData; // contents of application slot
        CFRef<CFDataRef> mEntitlementData; // entitlement configuration data
+       CFRef<CFURLRef> mSDKRoot;               // substitute filesystem root for sub-component lookup
        const Requirements *mRequirements; // internal code requirements
        size_t mCMSSize;                                // size estimate for CMS blob
        uint32_t mCdFlags;                              // CodeDirectory flags
        bool mCdFlagsGiven;                             // CodeDirectory flags were specified
+       CodeDirectory::HashAlgorithm mDigestAlgorithm; // interior digest (hash) algorithm
        std::string mIdentifier;                // unique identifier override
        std::string mIdentifierPrefix;  // prefix for un-dotted default identifiers
        bool mNoMachO;                                  // override to perform non-Mach-O signing
index e6b05a21fe463ddf52f5d47a08ff83801c5435e0..5169f0f943be0d60f56e090799d9c37801de3908 100644 (file)
@@ -63,8 +63,28 @@ SecRequirement::SecRequirement(const Requirement *req, bool transferOwnership)
 // Clean up a SecRequirement object
 //
 SecRequirement::~SecRequirement() throw()
-{
+try {
        ::free((void *)mReq);
+} catch (...) {
+       return;
+}
+
+
+//
+// CF-level comparison of SecRequirement objects compares the entire requirement
+// structure for equality. This means that two requirement programs are recognized
+// as equal if they're written identically (modulo comments and syntactic sugar).
+// Obviously, equality of outcome is not in the cards. :-)
+//
+bool SecRequirement::equal(SecCFObject &secOther)
+{
+       SecRequirement *other = static_cast<SecRequirement *>(&secOther);
+       return !memcmp(this->requirement(), other->requirement(), this->requirement()->length());
+}
+
+CFHashCode SecRequirement::hash()
+{
+       return CFHash(CFTempDataWrap(*this->requirement()));
 }
 
 
index dd3996d316b4fce839af520e8b5e14ce823edff7..e2c6ccc79d28697c0b06dc6c1964085789795875 100644 (file)
@@ -48,6 +48,9 @@ public:
        SecRequirement(const Requirement *req, bool transferOwnership = false);
     virtual ~SecRequirement() throw();
        
+    bool equal(SecCFObject &other);
+    CFHashCode hash();
+       
        const Requirement *requirement() const { return mReq; }
 
 private:
index eccd39693f53d73e1dbc9d8f8646d49ed6e25af1..36cefff908e657b05223c4e054cdcb4be576c3df 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -31,8 +31,7 @@
 #include "cs.h"
 #include "Code.h"
 #include "cskernel.h"
-#include <security_codesigning/cfmunge.h>
-#include <sys/codesign.h>
+#include <security_utilities/cfmunge.h>
 
 using namespace CodeSigning;
 
@@ -40,6 +39,7 @@ using namespace CodeSigning;
 //
 // CFError user info keys
 //
+const CFStringRef kSecCFErrorArchitecture =            CFSTR("SecCSArchitecture");
 const CFStringRef kSecCFErrorPattern =                 CFSTR("SecCSPattern");
 const CFStringRef kSecCFErrorResourceSeal =            CFSTR("SecCSResourceSeal");
 const CFStringRef kSecCFErrorResourceAdded =   CFSTR("SecCSResourceAdded");
@@ -49,6 +49,7 @@ const CFStringRef kSecCFErrorInfoPlist =              CFSTR("SecCSInfoPlist");
 const CFStringRef kSecCFErrorGuestAttributes = CFSTR("SecCSGuestAttributes");
 const CFStringRef kSecCFErrorRequirementSyntax = CFSTR("SecRequirementSyntax");
 
+
 //
 // CF-standard type code functions
 //
@@ -61,30 +62,45 @@ CFTypeID SecCodeGetTypeID(void)
 
 
 //
-// Get the root of trust Code
+// Get a reference to the calling code.
 //
-SecCodeRef SecGetRootCode(SecCSFlags flags)
+OSStatus SecCodeCopySelf(SecCSFlags flags, SecCodeRef *selfRef)
 {
        BEGIN_CSAPI
        
        checkFlags(flags);
-       return KernelCode::active()->handle();
+       CFRef<CFMutableDictionaryRef> attributes = makeCFMutableDictionary(1,
+               kSecGuestAttributePid, CFTempNumber(getpid()).get());
+       CodeSigning::Required(selfRef) = SecCode::autoLocateGuest(attributes, flags)->handle(false);
        
-       END_CSAPI1(NULL)
+       END_CSAPI
 }
 
 
 //
-// Get a reference to the calling code.
+// Get the dynamic status of a code.
 //
-OSStatus SecCodeCopySelf(SecCSFlags flags, SecCodeRef *selfRef)
+OSStatus SecCodeGetStatus(SecCodeRef codeRef, SecCSFlags flags, SecCodeStatus *status)
 {
        BEGIN_CSAPI
        
        checkFlags(flags);
-       CFRef<CFMutableDictionaryRef> attributes = makeCFMutableDictionary(1,
-               kSecGuestAttributePid, CFTempNumber(getpid()).get());
-       Required(selfRef) = SecCode::autoLocateGuest(attributes, flags)->handle(false);
+       CodeSigning::Required(status) = SecCode::required(codeRef)->status();
+       
+       END_CSAPI
+}
+
+
+//
+// Change the dynamic status of a code
+//
+OSStatus SecCodeSetStatus(SecCodeRef codeRef, SecCodeStatusOperation operation,
+       CFDictionaryRef arguments, SecCSFlags flags)
+{
+       BEGIN_CSAPI
+       
+       checkFlags(flags);
+       SecCode::required(codeRef)->status(operation, arguments);
        
        END_CSAPI
 }
@@ -99,7 +115,7 @@ OSStatus SecCodeCopyStaticCode(SecCodeRef codeRef, SecCSFlags flags, SecStaticCo
        
        checkFlags(flags);
        SecPointer<SecStaticCode> staticCode = SecCode::required(codeRef)->staticCode();
-       Required(staticCodeRef) = staticCode ? staticCode->handle() : NULL;
+       CodeSigning::Required(staticCodeRef) = staticCode ? staticCode->handle() : NULL;
 
        END_CSAPI
 }
@@ -114,7 +130,7 @@ OSStatus SecCodeCopyHost(SecCodeRef guestRef, SecCSFlags flags, SecCodeRef *host
        
        checkFlags(flags);
        SecPointer<SecCode> host = SecCode::required(guestRef)->host();
-       Required(hostRef) = host ? host->handle() : NULL;
+       CodeSigning::Required(hostRef) = host ? host->handle() : NULL;
 
        END_CSAPI
 }
@@ -123,9 +139,12 @@ OSStatus SecCodeCopyHost(SecCodeRef guestRef, SecCSFlags flags, SecCodeRef *host
 //
 // Find a guest by attribute(s)
 //
-const CFStringRef kSecGuestAttributePid =                      CFSTR("pid");
 const CFStringRef kSecGuestAttributeCanonical =                CFSTR("canonical");
+const CFStringRef kSecGuestAttributeHash =                     CFSTR("codedirectory-hash");
 const CFStringRef kSecGuestAttributeMachPort =         CFSTR("mach-port");
+const CFStringRef kSecGuestAttributePid =                      CFSTR("pid");
+const CFStringRef kSecGuestAttributeArchitecture =     CFSTR("architecture");
+const CFStringRef kSecGuestAttributeSubarchitecture = CFSTR("subarchitecture");
 
 OSStatus SecCodeCopyGuestWithAttributes(SecCodeRef hostRef,
        CFDictionaryRef attributes,     SecCSFlags flags, SecCodeRef *guestRef)
@@ -135,11 +154,11 @@ OSStatus SecCodeCopyGuestWithAttributes(SecCodeRef hostRef,
        checkFlags(flags);
        if (hostRef) {
                if (SecCode *guest = SecCode::required(hostRef)->locateGuest(attributes))
-                       Required(guestRef) = guest->handle(false);
+                       CodeSigning::Required(guestRef) = guest->handle(false);
                else
                        return errSecCSNoSuchCode;
        } else
-               Required(guestRef) = SecCode::autoLocateGuest(attributes, flags)->handle(false);
+               CodeSigning::Required(guestRef) = SecCode::autoLocateGuest(attributes, flags)->handle(false);
        
        END_CSAPI
 }
@@ -154,7 +173,7 @@ OSStatus SecCodeCreateWithPID(pid_t pid, SecCSFlags flags, SecCodeRef *processRe
        
        checkFlags(flags);
        if (SecCode *guest = KernelCode::active()->locateGuest(CFTemp<CFDictionaryRef>("{%O=%d}", kSecGuestAttributePid, pid)))
-               Required(processRef) = guest->handle(false);
+               CodeSigning::Required(processRef) = guest->handle(false);
        else
                return errSecCSNoSuchCode;
        
@@ -181,7 +200,7 @@ OSStatus SecCodeCheckValidityWithErrors(SecCodeRef codeRef, SecCSFlags flags,
        SecPointer<SecCode> code = SecCode::required(codeRef);
        code->checkValidity(flags);
        if (const SecRequirement *req = SecRequirement::optional(requirementRef))
-               code->staticCode()->validateRequirements(req->requirement(), errSecCSReqFailed);
+               code->staticCode()->validateRequirement(req->requirement(), errSecCSReqFailed);
 
        END_CSAPI_ERRORS
 }
@@ -200,16 +219,24 @@ const CFStringRef kSecCodeInfoChangedFiles =      CFSTR("changed-files");
 const CFStringRef kSecCodeInfoCMS =                            CFSTR("cms");
 const CFStringRef kSecCodeInfoDesignatedRequirement = CFSTR("designated-requirement");
 const CFStringRef kSecCodeInfoEntitlements =   CFSTR("entitlements");
-const CFStringRef kSecCodeInfoTime =                   CFSTR("signing-time");
 const CFStringRef kSecCodeInfoFormat =                 CFSTR("format");
+const CFStringRef kSecCodeInfoDigestAlgorithm =        CFSTR("digest-algorithm");
 const CFStringRef kSecCodeInfoIdentifier =             CFSTR("identifier");
 const CFStringRef kSecCodeInfoImplicitDesignatedRequirement = CFSTR("implicit-requirement");
 const CFStringRef kSecCodeInfoMainExecutable = CFSTR("main-executable");
 const CFStringRef kSecCodeInfoPList =                  CFSTR("info-plist");
 const CFStringRef kSecCodeInfoRequirements =   CFSTR("requirements");
 const CFStringRef kSecCodeInfoRequirementData =        CFSTR("requirement-data");
+const CFStringRef kSecCodeInfoSource =                 CFSTR("source");
 const CFStringRef kSecCodeInfoStatus =                 CFSTR("status");
+const CFStringRef kSecCodeInfoTime =                   CFSTR("signing-time");
 const CFStringRef kSecCodeInfoTrust =                  CFSTR("trust");
+const CFStringRef kSecCodeInfoUnique =                 CFSTR("unique");
+
+const CFStringRef kSecCodeInfoCodeDirectory =  CFSTR("CodeDirectory");
+const CFStringRef kSecCodeInfoCodeOffset =             CFSTR("CodeOffset");
+const CFStringRef kSecCodeInfoResourceDirectory = CFSTR("ResourceDirectory");
+
 
 OSStatus SecCodeCopySigningInformation(SecStaticCodeRef codeRef, SecCSFlags flags,
        CFDictionaryRef *infoRef)
@@ -227,17 +254,11 @@ OSStatus SecCodeCopySigningInformation(SecStaticCodeRef codeRef, SecCSFlags flag
        CFRef<CFDictionaryRef> info = code->signingInformation(flags);
        
        if (flags & kSecCSDynamicInformation)
-               if (SecPointer<SecCode> dcode = SecStaticCode::optionalDynamic(codeRef)) {
-                       uint32_t status;
-                       if (SecPointer<SecCode> host = dcode->host())
-                               status = host->getGuestStatus(dcode);
-                       else
-                               status = CS_VALID;              // root of trust, presumed valid
+               if (SecPointer<SecCode> dcode = SecStaticCode::optionalDynamic(codeRef))
                        info = cfmake<CFDictionaryRef>("{+%O,%O=%u}", info.get(),
-                               kSecCodeInfoStatus, status);
-               }
+                               kSecCodeInfoStatus, dcode->status());
        
-       Required(infoRef) = info.yield();
+       CodeSigning::Required(infoRef) = info.yield();
        
        END_CSAPI
 }
index 697c89de36caa98c1d7ac58915a93ae73d472d36..0e5ca7c409410169d34edabcb62fc4aa09c35db0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
 #ifndef _H_SECCODE
 #define _H_SECCODE
 
+#include <Security/CSCommon.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-#include <Security/CSCommon.h>
-
 
 /*!
        @function SecCodeGetTypeID
@@ -44,22 +44,6 @@ extern "C" {
 CFTypeID SecCodeGetTypeID(void);
 
 
-/*!
-       @function SecGetRootCode
-       Obtains a SecCode object for the running code that hosts the entire system.
-       This object usually represents the system kernel. It is always considered
-       valid and is implicitly trusted by everyone.
-       
-       This object has no host.
-       
-       @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
-       
-       @result An object reference to the root Code. This call should never fail.
-       If this call returns NULL, Code Signing is unusable.
-*/
-SecCodeRef SecGetRootCode(SecCSFlags flags);
-
-
 /*!
        @function SecCodeCopySelf
        Obtains a SecCode object for the code making the call.
@@ -70,13 +54,13 @@ SecCodeRef SecGetRootCode(SecCSFlags flags);
        is considered until revoked.
 
        @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
+       @param self Upon successful return, contains a SecCodeRef representing the caller.
        
        @result Upon success, noErr. Upon error, an OSStatus value documented in
        CSCommon.h or certain other Security framework headers.
  */
 OSStatus SecCodeCopySelf(SecCSFlags flags, SecCodeRef *self);
-       
-       
+
 
 /*!
        @function SecCodeCopyStaticCode
@@ -90,6 +74,12 @@ OSStatus SecCodeCopySelf(SecCSFlags flags, SecCodeRef *self);
        accept a SecCodeRef and apply this translation implicitly, operating on
        its result or returning its error code if any. Each of these functions
        calls out that behavior in its documentation.
+       
+       If the code was obtained from a universal (aka "fat") program file,
+       the resulting SecStaticCodeRef will refer only to the architecture actually
+       being used. This means that multiple running codes started from the same file
+       may conceivably result in different static code references if they ended up
+       using different execution architectures. (This is unusual but possible.)
 
        @param code A valid SecCode object reference representing code running
        on the system.
@@ -122,10 +112,15 @@ OSStatus SecCodeCopyHost(SecCodeRef guest, SecCSFlags flags, SecCodeRef *host);
 
 /*!
        @function SecCodeCopyGuestWithAttributes
-       Asks a SecCode object acting as a Code Signing host to identify one of
-       its guests by the type and value of specific attribute(s). Different hosts
-       support different types and combinations of attributes.
-       
+       This is the omnibus API function for obtaining dynamic code references.
+       In general, it asks a particular code acting as a code host to locate
+       and return a guest with given attributes. Different hosts support
+       different combinations of attributes and values for guest selection. 
+
+       Asking the NULL host invokes system default     procedures for obtaining
+       any running code in the system with the attributes given. The returned
+       code may be anywhere in the system.
        The methods a host uses to identify, separate, and control its guests
        are specific to each type of host. This call provides a generic abstraction layer
        that allows uniform interrogation of all hosts. A SecCode that does not
@@ -137,20 +132,22 @@ OSStatus SecCodeCopyHost(SecCodeRef guest, SecCSFlags flags, SecCodeRef *host);
        on the system that acts as a Code Signing host. As a special case, passing
        NULL indicates that the Code Signing root of trust should be used as a starting
        point. Currently, that is the system kernel.
-       @param attributes A CFDictionary containing one or more attribute selector
+       @param attributes A CFDictionary containing zero or more attribute selector
        values. Each selector has a CFString key and associated CFTypeRef value.
-       The key name identifies the attribute being selected; the associated value,
+       The key name identifies the attribute being specified; the associated value,
        whose type depends on the the key name, selects a particular value or other
        constraint on that attribute. Each host only supports particular combinations
        of keys and values,     and errors will be returned if any unsupported set is requested.
        As a special case, NULL is taken to mean an empty attribute set.
-       Also note that some hosts that support hosting chains (guests being hosts)
+       Note that some hosts that support hosting chains (guests being hosts)
        may return sub-guests in this call. In other words, do not assume that
-       a SecCodeRef returned by this call is an immediate guest of the queried host
+       a SecCodeRef returned by this call is a direct guest of the queried host
        (though it will be a proximate guest, i.e. a guest's guest some way down).
+       Asking the NULL host for NULL attributes returns a code reference for the system root
+       of trust (at present, the running Darwin kernel).
        @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
        @param guest On successful return, a SecCode object reference identifying
-       the particular guest of the host that owns the attribute value specified.
+       the particular guest of the host that owns the attribute value(s) specified.
        This argument will not be changed if the call fails (does not return noErr).
        @result Upon success, noErr. Upon error, an OSStatus value documented in
        CSCommon.h or certain other Security framework headers. In particular:
@@ -161,36 +158,23 @@ OSStatus SecCodeCopyHost(SecCodeRef guest, SecCSFlags flags, SecCodeRef *host);
        @error errSecCSNoSuchCode The host has no guest with the attribute value given
        by attributeValue, even though the value is of a supported type. This may also
        be returned if the host code does not currently act as a Code Signing host.
-       @error errSecCSNotAHost The putative host cannot, in fact, act as a code
+       @error errSecCSNotAHost The specified host cannot, in fact, act as a code
        host. (It is missing the kSecCodeSignatureHost option flag in its code
        signature.)
        @error errSecCSMultipleGuests The attributes specified do not uniquely identify
        a guest (the specification is ambiguous).
 */
-extern const CFStringRef kSecGuestAttributePid;
 extern const CFStringRef kSecGuestAttributeCanonical;
+extern const CFStringRef kSecGuestAttributeHash;
 extern const CFStringRef kSecGuestAttributeMachPort;
+extern const CFStringRef kSecGuestAttributePid;
+extern const CFStringRef kSecGuestAttributeArchitecture;
+extern const CFStringRef kSecGuestAttributeSubarchitecture;
 
 OSStatus SecCodeCopyGuestWithAttributes(SecCodeRef host,
        CFDictionaryRef attributes,     SecCSFlags flags, SecCodeRef *guest);
 
 
-/*!
-       @function SecCodeCreateWithPID
-       Asks the kernel to return a SecCode object for a process identified
-       by a UNIX process id (pid). This is a shorthand for asking SecGetRootCode()
-       for a guest whose "pid" attribute has the given pid value.
-       
-       @param pid A process id for an existing UNIX process on the system.
-       @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
-       @param process On successful return, a SecCode object reference identifying
-       the requesteed process.
-       @result Upon success, noErr. Upon error, an OSStatus value documented in
-       CSCommon.h or certain other Security framework headers.
-*/
-OSStatus SecCodeCreateWithPID(pid_t pid, SecCSFlags flags, SecCodeRef *process);
-
-
 /*!
        @function SecCodeCheckValidity
        Performs dynamic validation of the given SecCode object. The call obtains and
@@ -263,7 +247,7 @@ OSStatus SecCodeCopyPath(SecStaticCodeRef staticCode, SecCSFlags flags,
        @param requirement On successful return, contains a copy of a SecRequirement
        object representing the code's Designated Requirement. On error, unchanged.
        @result On success, noErr. On error, an OSStatus value
-       documented in CSCommon.h or certain other Security framework headers.
+               documented in CSCommon.h or certain other Security framework headers.
 */
 OSStatus SecCodeCopyDesignatedRequirement(SecStaticCodeRef code, SecCSFlags flags,
        SecRequirementRef *requirement);
@@ -286,6 +270,8 @@ OSStatus SecCodeCopyDesignatedRequirement(SecStaticCodeRef code, SecCSFlags flag
        
        @param code The Code or StaticCode object to be interrogated. For a Code
                argument, its StaticCode is processed as per SecCodeCopyStaticCode.
+               Note that dynamic information (kSecCSDynamicInformation) cannot be obtained
+               for a StaticCode argument.
        @param flags Optional flags. Use any or all of the kSecCS*Information flags
                to select what information to return. A generic set of entries is returned
                regardless; you may specify kSecCSDefaultFlags for just those.
@@ -294,8 +280,14 @@ OSStatus SecCodeCopyDesignatedRequirement(SecStaticCodeRef code, SecCSFlags flag
                the flags passed. Regardless of flags, the kSecCodeInfoIdentifier key is
                always present if the code is signed, and always absent if the code is
                unsigned.
+               Note that some of the objects returned are (retained) "live" API objects
+               used by the code signing infrastructure. Making changes to these objects
+               is unsupported and may cause subsequent code signing operations on the
+               affected code to behave in undefined ways.
        @result On success, noErr. On error, an OSStatus value
-       documented in CSCommon.h or certain other Security framework headers.
+               documented in CSCommon.h or certain other Security framework headers.
+               
+       Flags:
        
        @constant kSecCSSigningInformation Return cryptographic signing information,
                including the certificate chain and CMS data (if any). For ad-hoc signed
@@ -311,6 +303,67 @@ OSStatus SecCodeCopyDesignatedRequirement(SecStaticCodeRef code, SecCSFlags flag
                contents making up the signed code on disk. It is not generally advisable to
                make use of this information, but some utilities (such as software-update
                tools) may find it useful.
+       
+       Dictionary keys:
+
+       @constant kSecCodeInfoCertificates A CFArray of SecCertificates identifying the
+               certificate chain of the signing certificate as seen by the system. Absent
+               for ad-hoc signed code. May be partial or absent in error cases.
+       @constant kSecCodeInfoChangedFiles A CFArray of CFURLs identifying all files in
+               the code that may have been modified by the process of signing it. (In other
+               words, files not in this list will not have been touched by the signing operation.)
+       @constant kSecCodeInfoCMS A CFData containing the CMS cryptographic object that
+               secures the code signature. Empty for ad-hoc signed code.
+       @constant kSecCodeInfoDesignatedRequirement A SecRequirement describing the
+               actual Designated Requirement of the code.
+       @constant kSecCodeInfoEntitlements A CFData containing the embedded entitlement
+               blob of the code, if any.
+       @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
+               hash function used within the signature to seal its pieces together.
+       @constant kSecCodeInfoIdentifier A CFString with the actual signing identifier
+               sealed into the signature. Absent for unsigned code.
+       @constant kSecCodeInfoImplicitDesignatedRequirement A SecRequirement describing
+               the designated requirement that the system did generate, or would have generated,
+               for the code. If the Designated Requirement was implicitly generated, this is
+               the same object as kSecCodeInfoDesignatedRequirement; this can be used to test
+               for an explicit Designated Requirement.
+       @constant kSecCodeInfoMainExecutable A CFURL identifying the main executable file
+               of the code. For single files, that is the file itself. For bundles, it is the
+               main executable as identified by its Info.plist.
+       @constant kSecCodeInfoPList A retained CFDictionary referring to the secured Info.plist
+               as seen by code signing. Absent if no Info.plist is known to the code signing
+               subsystem. Note that this is not the same dictionary as the one CFBundle would
+               give you (CFBundle is free to add entries to the on-disk plist).
+       @constant kSecCodeInfoRequirements A CFString describing the internal requirements
+               of the code in canonical syntax.
+       @constant kSecCodeInfoRequirementsData A CFData containing the internal requirements
+               of the code as a binary blob.
+       @constant kSecCodeInfoSource A CFString describing the source of the code signature
+               used for the code object. The values are meant to be shown in informational
+               displays; do not rely on the precise value returned.
+       @constant kSecCodeInfoStatus A CFNumber containing the dynamic status word of the
+               (running) code. This is a snapshot at the time the API is executed and may be
+               out of date by the time you examine it. Do note however that most of the bits
+               are sticky and thus some values are permanently reliable. Be careful.
+       @constant kSecCodeInfoTime A CFDate describing the signing date (securely) embedded
+               in the code signature. Note that a signer is able to omit this date or pre-date
+               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 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
+               validation may have failed. This object may continue to be used for further
+               evaluations of this code; if you make any changes to it, behavior is undefined.
+       @constant kSecCodeInfoUnique A CFData binary identifier that uniquely identifies
+               the static code in question. It can be used to recognize this particular code
+               (and none other) now or in the future. Compare to kSecCodeInfoIdentifier, which
+               remains stable across (developer-approved) updates.
+               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.
  */
 enum {
        kSecCSInternalInformation = 1 << 0,
@@ -324,53 +377,26 @@ enum {
 extern const CFStringRef kSecCodeInfoCertificates;     /* Signing */
 extern const CFStringRef kSecCodeInfoChangedFiles;     /* Content */
 extern const CFStringRef kSecCodeInfoCMS;                      /* Signing */
-extern const CFStringRef kSecCodeInfoTime;                     /* Signing */
 extern const CFStringRef kSecCodeInfoDesignatedRequirement; /* Requirement */
 extern const CFStringRef kSecCodeInfoEntitlements;     /* Requirement */
 extern const CFStringRef kSecCodeInfoFormat;           /* generic */
+extern const CFStringRef kSecCodeInfoDigestAlgorithm; /* generic */
 extern const CFStringRef kSecCodeInfoIdentifier;       /* generic */
 extern const CFStringRef kSecCodeInfoImplicitDesignatedRequirement; /* Requirement */
 extern const CFStringRef kSecCodeInfoMainExecutable; /* generic */
 extern const CFStringRef kSecCodeInfoPList;                    /* generic */
 extern const CFStringRef kSecCodeInfoRequirements;     /* Requirement */
 extern const CFStringRef kSecCodeInfoRequirementData; /* Requirement */
+extern const CFStringRef kSecCodeInfoSource;           /* generic */
 extern const CFStringRef kSecCodeInfoStatus;           /* Dynamic */
+extern const CFStringRef kSecCodeInfoTime;                     /* Signing */
 extern const CFStringRef kSecCodeInfoTrust;                    /* Signing */
+extern const CFStringRef kSecCodeInfoUnique;           /* generic */
 
 OSStatus SecCodeCopySigningInformation(SecStaticCodeRef code, SecCSFlags flags,
        CFDictionaryRef *information);
 
 
-/*
-       @function SecCodeSetDetachedSignature
-       For a given Code or StaticCode object, explicitly specify the detached signature
-       data used to verify it.
-       This call unconditionally overrides any signature embedded in the Code and any
-       previously specified detached signature; only the signature data specified here
-       will be used from now on for this Code object. If NULL data is specified, this
-       call reverts to using any embedded signature.
-       Any call to this function voids all cached validations for the Code object.
-       Validations will be performed again as needed in the future. This call does not,
-       by itself, perform or trigger any validations.
-       Please note that it is possible to have multiple Code objects for the same static
-       or dynamic code entity in the system. This function only attaches signature data
-       to the particular SecStaticCodeRef involved. It is your responsibility to understand
-       the object graph and pick the right one(s).
-       
-       @param code A Code or StaticCode object whose signature information is to be changed.
-       @param signature A CFDataRef containing the signature data to be used for validating
-               the given Code. This must be exactly the data previously generated as a detached
-               signature by the SecCodeSignerAddSignature API or the codesign(1) command with
-               the -D/--detached option.
-               If signature is NULL, discards any previously set signature data and reverts
-               to using the embedded signature, if any. If not NULL, the data is retained and used
-               for future validation operations.
-       @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
- */
-OSStatus SecCodeSetDetachedSignature(SecStaticCodeRef code, CFDataRef signature,
-       SecCSFlags flags);
-
-
 /*
        @function SecCodeMapMemory
        For a given Code or StaticCode object, ask the kernel to accept the signing information
index fce240395d52122768ffcbfc70d77960b274c03c..f6989f2990629882aa79c591bb5e2c0272df3414 100644 (file)
@@ -56,9 +56,9 @@ OSStatus SecHostCreateGuest(SecGuestRef host,
 {
        BEGIN_CSAPI
        
-       checkFlags(flags, kSecCSDedicatedHost);
-       Required(newGuest) = SecurityServer::ClientSession().createGuest(host,
-               status, cfString(path).c_str(), DictData(attributes), flags);
+       checkFlags(flags, kSecCSDedicatedHost | kSecCSGenerateGuestHash);
+       CodeSigning::Required(newGuest) = SecurityServer::ClientSession().createGuest(host,
+               status, cfString(path).c_str(), CssmData(), DictData(attributes), flags);
        
        END_CSAPI
 }
@@ -89,7 +89,7 @@ OSStatus SecHostSelectedGuest(SecCSFlags flags, SecGuestRef *guestRef)
        BEGIN_CSAPI
        
        checkFlags(flags);
-       Required(guestRef) = SecurityServer::ClientSession().selectedGuest();
+       CodeSigning::Required(guestRef) = SecurityServer::ClientSession().selectedGuest();
        
        END_CSAPI
 }
index fc9c83d64017355906c8a48c9d5f8c47260daac7..dd70b8ab6f01df60acf2a1a2c2d09a6b27174a84 100644 (file)
@@ -41,7 +41,6 @@
 #define _H_SECCODEHOST
 
 #include <Security/CSCommon.h>
-#include <System/sys/codesign.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -91,9 +90,10 @@ extern "C" {
        of the guest to act as the new guest's host. If host has a dedicated guest,
        it will be deemed to be be the actual host, recursively.
        @param status The Code Signing status word for the new guest. These are combinations
-       of the CS_* flags in <sys/codesign.h>. Note that the proxy will enforce the rules for
-       the stickiness of these bits. In particular, if you don't pass the CS_VALID bit during
-       creation, your new guest will be born invalid and will never have a valid identity.
+       of the kSecCodeStatus* flags in <Security/CSCommon.h>. Note that the proxy will enforce
+       the rules for the stickiness of these bits. In particular, if you don't pass the
+       kSecCodeStatusValid bit during creation, your new guest will be born invalid and will
+       never have a valid identity.
        @param path The canonical path to the guest's code on disk. This is the path you would
        pass to SecStaticCodeCreateWithPath to make a static code object reference. You must
        use an absolute path.
@@ -101,6 +101,8 @@ extern "C" {
        to locate this particular guest among all of the caller's guests. The "canonical"
        attribute is automatically added for the value of guestRef. If you pass NULL,
        no other attributes are established for the guest.
+       While any key can be used in the attributes dictionary, the kSecGuestAttribute* constants
+       (in SecCode.h) are conventionally used here.
        @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior, or
        a combination of the flags defined below for special features.
        @result Upon success, noErr. Upon error, an OSStatus value documented in
@@ -118,9 +120,16 @@ extern "C" {
        It is invalid to declare dedicated hosting if other guests have already been
        introduced for this host, and it is invalid to introduce additional guests
        for this host after this call.
+       @constant kSecCSGenerateGuestHash Ask the proxy to generate the binary identifier
+       (hash of CodeDirectory) from the copy on disk at the path given. This is not optimal
+       since an attacker with write access may be able to substitute a different copy just
+       in time, but it is convenient. For optimal security, the host should calculate the
+       hash from the loaded in-memory signature of its guest and pass the result as an
+       attribute with key kSecGuestAttributeHash.
 */
 enum {
        kSecCSDedicatedHost = 1 << 0,
+       kSecCSGenerateGuestHash = 1 << 1,
 };
 
 OSStatus SecHostCreateGuest(SecGuestRef host,
@@ -186,8 +195,8 @@ OSStatus SecHostSelectedGuest(SecCSFlags flags, SecGuestRef *guestRef);
        on whose behalf this thread will act from now on. This setting will be remembered
        until it is changed (or the thread terminates).
        @param status The new Code Signing status word for the guest. The proxy enforces
-       the restrictions on changes to guest status; in particular, the CS_VALID bit can only
-       be cleared, and the CS_HARD and CS_KILL flags can only be set. Pass the previous
+       the restrictions on changes to guest status; in particular, the kSecCodeStatusValid bit can only
+       be cleared, and the kSecCodeStatusHard and kSecCodeStatusKill flags can only be set. Pass the previous
        guest status to indicate that no change is desired.
        @param attributes An optional dictionary containing attributes to be used to distinguish
        this guest from all guests of the caller. If given, it completely replaces the attributes
index a79c85ddbae2afca3977cfd7f0a031cc95803bb1..50dadf16e9ed67abf5e505af1c671f6d57fa03bb 100644 (file)
@@ -20,7 +20,7 @@
  * 
  * @APPLE_LICENSE_HEADER_END@
  */
-//#include <Security/SecCodeHostLib.h>
+#include "SecCodeHost.h"
 #include "SecCodeHostLib.h"
 #include <Security/Security.h>
 #include <Security/AuthSession.h>
@@ -64,8 +64,7 @@ OSStatus SecHostLibInit(SecCSFlags flags)
        if (KERN_SUCCESS != task_get_bootstrap_port(mach_task_self(), &bootstrapPort))
                return errSecCSInternalError;
        static char serverName[BOOTSTRAP_MAX_NAME_LEN] = SECURITYSERVER_BOOTSTRAP_NAME;
-       if (KERN_SUCCESS != bootstrap_look_up(bootstrapPort,
-               serverName, &gServerPort))
+       if (KERN_SUCCESS != bootstrap_look_up(bootstrapPort, serverName, &gServerPort))
                return errSecCSInternalError;
 
        ClientSetupInfo info = { 0x1234, SSPROTOVERSION };
@@ -80,12 +79,19 @@ OSStatus SecHostLibInit(SecCSFlags flags)
 OSStatus SecHostLibCreateGuest(SecGuestRef host,
        uint32_t status, const char *path, const char *attributeXML,
        SecCSFlags flags, SecGuestRef *newGuest)
+{
+       return SecHostLibCreateGuest2(host, status, path, "", 0, attributeXML, flags, newGuest);
+}
+
+OSStatus SecHostLibCreateGuest2(SecGuestRef host,
+       uint32_t status, const char *path, const void *cdhash, size_t cdhashLength, const char *attributeXML,
+       SecCSFlags flags, SecGuestRef *newGuest)
 {
        if (flags != kSecCSDedicatedHost)
                return errSecCSInvalidFlags;
        
        CALL(ucsp_client_createGuest(UCSP_ARGS, host, status, path,
-               ATTRDATA(attributeXML), flags, newGuest));
+               (void *)cdhash, cdhashLength, ATTRDATA(attributeXML), flags, newGuest));
 }
 
 
@@ -107,3 +113,12 @@ OSStatus SecHostSetHostingPort(mach_port_t hostingPort, SecCSFlags flags)
 {
        CALL(ucsp_client_registerHosting(UCSP_ARGS, hostingPort, flags));
 }
+
+
+//
+// Helper for checked incorporation of code.
+//
+OSStatus SecHostLibCheckLoad(const char *path, SecRequirementType type)
+{
+       CALL(ucsp_client_helpCheckLoad(UCSP_ARGS, path, type));
+}
index 65fa720064734f85defdff328076bd0a6d82e6c9..813b399377a14ed47c6d5a982e806f39642b5cee 100644 (file)
@@ -36,9 +36,7 @@
 #ifndef _H_SECCODEHOSTLIB
 #define _H_SECCODEHOSTLIB
 
-//#include <Security/SecCodeHost.h>
-#include "SecCodeHost.h"
-#include <System/sys/codesign.h>
+#include <Security/SecCodeHost.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -62,6 +60,10 @@ OSStatus SecHostLibInit(SecCSFlags flags);
  */
 OSStatus SecHostLibCreateGuest(SecGuestRef host,
        uint32_t status, const char *path, const char *attributeXML,
+       SecCSFlags flags, SecGuestRef *newGuest) DEPRECATED_ATTRIBUTE;
+       
+OSStatus SecHostLibCreateGuest2(SecGuestRef host,
+       uint32_t status, const char *path, const void *cdhash, size_t cdhashLength, const char *attributeXML,
        SecCSFlags flags, SecGuestRef *newGuest);
 
 
@@ -96,6 +98,11 @@ OSStatus SecHostSelectedGuest(SecCSFlags flags, SecGuestRef *guestRef);
 */
 
 
+/*!
+ */
+OSStatus SecHostLibCheckLoad(const char *path, SecRequirementType type);
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/SecCodePriv.h b/lib/SecCodePriv.h
new file mode 100644 (file)
index 0000000..54759b8
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2006-2007 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@
+ */
+
+/*!
+       @header SecCodePriv
+       SecCodePriv is the private counter-part to SecCode. Its contents are not
+       official API, and are subject to change without notice.
+*/
+#ifndef _H_SECCODEPRIV
+#define _H_SECCODEPRIV
+
+#include <Security/SecCode.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ *     Private constants for SecCodeCopySigningInformation.
+ *     These are returned with the 
+ */
+extern const CFStringRef kSecCodeInfoCodeDirectory;                    /* Internal */
+extern const CFStringRef kSecCodeInfoCodeOffset;                       /* Internal */
+extern const CFStringRef kSecCodeInfoResourceDirectory;                /* Internal */
+
+
+/*!
+       @function SecCodeGetStatus
+       Retrieves the dynamic status for a SecCodeRef.
+       
+       The dynamic status of a code can change at any time; the value returned is a snapshot
+       in time that is inherently stale by the time it is received by the caller. However,
+       since the status bits can only change in certain ways, some information is indefinitely
+       valid. For example, an indication of invalidity (kSecCodeStatusValid bit off) is permanent
+       since the valid bit cannot be set once clear, while an indication of validity (bit set)
+       may already be out of date.
+       Use this call with caution; it is usually wiser to call the validation API functions
+       and let then consider the status as part of their holistic computation. However,
+       SecCodeGetStatus is useful at times to capture persistent (sticky) status configurations.
+
+       @param code A valid SecCode object reference representing code running
+       on the system.
+       @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
+       @param status Upon successful return, contains the dynamic status of code as
+       determined by its host.
+       
+       @result Upon success, noErr. Upon error, an OSStatus value documented in
+       CSCommon.h or certain other Security framework headers.
+ */
+OSStatus SecCodeGetStatus(SecCodeRef code, SecCSFlags flags, SecCodeStatus *status);
+
+
+/*!
+       @function SecCodeSetStatus
+       Change the dynamic status of a SecCodeRef.
+       
+       @param code A valid SecCode object reference representing code running
+       on the system.
+       @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
+       @param status Upon successful return, contains the dynamic status of code as
+       determined by its host.
+       
+       @result Upon success, noErr. Upon error, an OSStatus value documented in
+       CSCommon.h or certain other Security framework headers.
+ */
+typedef uint32_t SecCodeStatusOperation;
+enum {
+       kSecCodeOperationNull = 0,
+       kSecCodeOperationInvalidate = 1,
+       kSecCodeOperationSetHard = 2,
+       kSecCodeOperationSetKill = 3,
+};
+
+OSStatus SecCodeSetStatus(SecCodeRef code, SecCodeStatusOperation operation,
+       CFDictionaryRef arguments, SecCSFlags flags);
+
+
+/*!
+       @function SecCodeCopyInternalRequirement
+       For a given Code or StaticCode object, retrieves a particular kind of internal
+       requirement that was sealed during signing.
+
+       This function will always fail for unsigned code. Requesting a type of internal
+       requirement that was not given during signing is not an error.
+       
+       Specifying a type of kSecDesignatedRequirementType is not the same as calling
+       SecCodeCopyDesignatedRequirement. This function will only return an explicit
+       Designated Requirement if one was specified during signing. SecCodeCopyDesignatedRequirement
+       will synthesize a suitable Designated Requirement if one was not given explicitly.
+       
+       @param code The Code or StaticCode object to be interrogated. For a Code
+               argument, its StaticCode is processed as per SecCodeCopyStaticCode.
+       @param type A SecRequirementType specifying which internal requirement is being
+               requested.
+       @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
+       @param requirement On successful return, contains a copy of the internal requirement
+               of the given type included in the given code. If the code has no such internal
+               requirement, this argument is set to NULL (with no error).
+       @result On success, noErr. On error, an OSStatus value
+               documented in CSCommon.h or certain other Security framework headers.
+*/
+OSStatus SecCodeCopyInternalRequirement(SecStaticCodeRef code, SecRequirementType type,
+       SecCSFlags flags, SecRequirementRef *requirement);
+
+
+/*!
+       @function SecCodeCreateWithPID
+       Asks the kernel to return a SecCode object for a process identified
+       by a UNIX process id (pid). This is a shorthand for asking SecGetRootCode()
+       for a guest whose "pid" attribute has the given pid value.
+       
+       This is a deprecated convenience function.
+       Call SecCodeCopyGuestWithAttributes instead.
+       
+       @param pid A process id for an existing UNIX process on the system.
+       @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
+       @param process On successful return, a SecCode object reference identifying
+       the requesteed process.
+       @result Upon success, noErr. Upon error, an OSStatus value documented in
+       CSCommon.h or certain other Security framework headers.
+*/
+OSStatus SecCodeCreateWithPID(pid_t pid, SecCSFlags flags, SecCodeRef *process)
+       AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_10_6;
+
+
+/*
+       @function SecCodeSetDetachedSignature
+       For a given Code or StaticCode object, explicitly specify the detached signature
+       data used to verify it.
+       This call unconditionally overrides any signature embedded in the Code and any
+       previously specified detached signature; only the signature data specified here
+       will be used from now on for this Code object. If NULL data is specified, the
+       code object is returned to its natural signing state (before a detached
+       signature was first attached to it).
+       Any call to this function voids all cached validations for the Code object.
+       Validations will be performed again as needed in the future. This call does not,
+       by itself, perform or trigger any validations.
+       Please note that it is possible to have multiple Code objects for the same static
+       or dynamic code entity in the system. This function only attaches signature data
+       to the particular SecStaticCodeRef involved. It is your responsibility to understand
+       the object graph and pick the right one(s).
+       
+       @param code A Code or StaticCode object whose signature information is to be changed.
+       @param signature A CFDataRef containing the signature data to be used for validating
+               the given Code. This must be exactly the data previously generated as a detached
+               signature by the SecCodeSignerAddSignature API or the codesign(1) command with
+               the -D/--detached option.
+               If signature is NULL, discards any previously set signature data and reverts
+               to using the embedded signature, if any. If not NULL, the data is retained and used
+               for future validation operations.
+               The data may be retained or copied. Behavior is undefined if this object
+               is modified after this call before it is replaced through another call to this
+               function).
+       @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
+ */
+OSStatus SecCodeSetDetachedSignature(SecStaticCodeRef code, CFDataRef signature,
+       SecCSFlags flags);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_H_SECCODE
index 6e752a408e80b7380310a20101b21900e7fb0858..adb8346c73d2ef5086bb49dac6944587ab3493d5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -40,6 +40,7 @@ using namespace CodeSigning;
 //
 const CFStringRef kSecCodeSignerApplicationData = CFSTR("application-specific");
 const CFStringRef kSecCodeSignerDetached =             CFSTR("detached");
+const CFStringRef kSecCodeSignerDigestAlgorithm = CFSTR("digest-algorithm");
 const CFStringRef kSecCodeSignerDryRun =               CFSTR("dryrun");
 const CFStringRef kSecCodeSignerEntitlements = CFSTR("entitlements");
 const CFStringRef kSecCodeSignerFlags =                        CFSTR("flags");
@@ -49,6 +50,7 @@ const CFStringRef kSecCodeSignerIdentity =            CFSTR("signer");
 const CFStringRef kSecCodeSignerPageSize =             CFSTR("pagesize");
 const CFStringRef kSecCodeSignerRequirements = CFSTR("requirements");
 const CFStringRef kSecCodeSignerResourceRules =        CFSTR("resource-rules");
+const CFStringRef kSecCodeSignerSDKRoot =              CFSTR("sdkroot");
 const CFStringRef kSecCodeSignerSigningTime =  CFSTR("signing-time");
 
 
@@ -70,9 +72,12 @@ OSStatus SecCodeSignerCreate(CFDictionaryRef parameters, SecCSFlags flags,
        SecCodeSignerRef *signerRef)
 {
        BEGIN_CSAPI
-       SecPointer<SecCodeSigner> signer = new SecCodeSigner;
+               
+       checkFlags(flags, kSecCSRemoveSignature);
+       SecPointer<SecCodeSigner> signer = new SecCodeSigner(flags);
        signer->parameters(parameters);
-       Required(signerRef) = signer->handle();
+       CodeSigning::Required(signerRef) = signer->handle();
+
     END_CSAPI
 }
 
index 32c0abb1c33b0ed3e9714ba1467b604ab91e1391..184dc663bec89e09b47ce20afbce14bcd240a13e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -23,7 +23,7 @@
 
 /*!
        @header SecCodeSigner
-       SecCodeSigner represents an object that signs code.
+       SecCodeSigner represents an object that can sign code.
 */
 #ifndef _H_SECCODESIGNER
 #define _H_SECCODESIGNER
@@ -43,23 +43,76 @@ typedef struct __SecCodeSigner *SecCodeSignerRef;   /* code signing object */
 
 /*!
        @function SecCodeGetTypeID
-       Returns the type identifier of all SecCode instances.
+       Returns the type identifier of all SecCodeSigner instances.
 */
 CFTypeID SecCodeSignerGetTypeID(void);
 
 
 /*!
+       The following CFString constants can be used as keys in the parameters argument
+       of SecCodeSignerCreate to specify various modes and options of the signing operation.
+       Passing any keys not specified here may lead to undefined behavior and is not supported.
+       The same applies to passing objects of types not explicitly allowed here.
+
+       @constant kSecCodeSignerDetached Determines where the signature is written.
+               If this key is absent, the code being signed is modified to contain the signature,
+               replacing any signature already embedded there.
+               If the value is kCFNull, the signature is written to the system-wide detached
+               signature database. (You must have root privileges to write there.)
+               If the value of this key is a CFURL, the signature is written to a file at that location,
+               replacing any data there.
+               If the value is a CFMutableData, the signature is appended to that data.
+       @constant kSecCodeSignerDryRun A boolean value. If present and true, the actual writing
+               of the signature is inhibited, and the code is not modified, but all operations
+               leading up to this are performed normally, including the cryptographic access to
+               the signing identity (if any).
+       @constant kSecCodeSignerFlags A CFNumber specifying which flags to set in the code signature.
+               Note that depending on circumstances, this value may be augmented or modified
+               as part of the signing operation.
+       @constant kSecCodeSignerIdentifier If present, a CFString that explicitly specifies
+               the unique identifier string sealed into the code signature. If absent, the identifier
+               is derived implicitly from the code being signed.
+       @constant kSecCodeSignerIdentifierPrefix If the unique identifier string of the code signature
+               is implicitly generated, and the resulting string does not contain any "." (dot)
+               characters, then the (string) value of this parameter is prepended to the identifier.
+               By convention, the prefix is usually of the form "com.yourcompany.", but any value
+               is acceptable. If the kSecCodeSignerIdentifier parameter is specified, this parameter
+               is ineffective (but still allowed).
        @constant kSecCodeSignerIdentity A SecIdentityRef describing the signing identity
-               to use for signing code. This is a mandatory parameter.
-       @constant kSecCodeSignerDetached If present, a detached code signature is generated.
-               If absent, code signature data is written into the target code (which must
-               be writable). The value is a CFURL identifying the file that is replaced with
-               the detached signature data.
-       @constant kSecCodeSignerRequirements Internal code requirements.
-       @constant kSecCodeSignerFlags Signature flags.
+               to use for signing code. This is a mandatory parameter for signing operations.
+               Its value must be either a SecIdentityRef specifying a cryptographic identity
+               valid for Code Signing, or the special value kCFNull to indicate ad-hoc signing.
+       @constant kSecCodeSignerOperation The type of operation to be performed. Valid values
+               are kSecCodeSignerOperationSign to sign code, and kSecCodeSignerOperationRemove
+               to remove any existing signature from code. The default operation is to sign code.
+       @constant kSecCodeSignerPageSize An integer value explicitly specifying the page size
+               used to sign the main executable. This must be a power of two. A value of zero indicates
+               infinite size (no paging).
+               Only certain page sizes are allowed in most circumstances, and specifying an inappropriate
+               size will lead to spurious verification failures. This is for expert use only.
+       @constant kSecCodeSignerRequirements Specifies the internal requirements to be sealed into
+               the code signature. Must be either a CFData containing the binary (compiled) form of
+               a requirements set (SuperBlob), or a CFString containing a valid text form to be
+               compiled into binary form. Default requirements are automatically generated if this
+               parameter is omitted, and defaults may be applied to particular requirement types
+               that are not specified; but any requirement type you specify is sealed exactly as
+               specified.
+       @constant kSecCodeSignerResourceRules A CFDictionary containing resource scanning rules
+               determining what resource files are sealed into the signature (and in what way).
+               A situation-dependent default is applied if this parameter is not specified.
+       @constant kSecCodeSignerSDKRoot A CFURLRef indicating an alterate directory root
+               where signing operations should find subcomponents (libraries, frameworks, modules, etc.).
+               The default is the host system root "/".
+       @constant kSecCodeSignerSigningTime Specifies what date and time is sealed into the
+               code signature's CMS data. Can be either a CFDate object specifying a date, or
+               the value kCFNull indicating that no date should be included in the signature.
+               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.
  */
 extern const CFStringRef kSecCodeSignerApplicationData;
 extern const CFStringRef kSecCodeSignerDetached;
+extern const CFStringRef kSecCodeSignerDigestAlgorithm;
 extern const CFStringRef kSecCodeSignerDryRun;
 extern const CFStringRef kSecCodeSignerEntitlements;
 extern const CFStringRef kSecCodeSignerFlags;
@@ -69,6 +122,7 @@ extern const CFStringRef kSecCodeSignerIdentity;
 extern const CFStringRef kSecCodeSignerPageSize;
 extern const CFStringRef kSecCodeSignerRequirements;
 extern const CFStringRef kSecCodeSignerResourceRules;
+extern const CFStringRef kSecCodeSignerSDKRoot;
 extern const CFStringRef kSecCodeSignerSigningTime;
 
 
@@ -81,11 +135,18 @@ extern const CFStringRef kSecCodeSignerSigningTime;
                are applied to all parameters; note however that some parameters do not have
                useful defaults, and will need to be set before signing is attempted.
        @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
+               The kSecCSRemoveSignature flag requests that any existing signature be stripped
+               from the target code instead of signing.
        @param staticCode On successful return, a SecStaticCode object reference representing
        the file system origin of the given SecCode. On error, unchanged.
        @result Upon success, noErr. Upon error, an OSStatus value documented in
        CSCommon.h or certain other Security framework headers.
 */
+enum {
+       kSecCSRemoveSignature = 1 << 0,         // strip existing signature
+};
+
+
 OSStatus SecCodeSignerCreate(CFDictionaryRef parameters, SecCSFlags flags,
        SecCodeSignerRef *signer);
 
index bab8ccce17027ad06ed3a3454b715209cc3329e8..a6ffb6265850786f9a61b1c2a0ae16692952ffde 100644 (file)
@@ -20,5 +20,4 @@
  * 
  * @APPLE_LICENSE_HEADER_END@
  */
-//#include <Security/SecCodeHostLib.h>
 #include "SecIntegrityLib.h"
index 0b6616d1c8426c01fab062aef12366f7680fbf05..cc3793a07ec8828f9314003dc775f1217bed5b12 100644 (file)
@@ -55,7 +55,7 @@ OSStatus SecRequirementCreateWithData(CFDataRef data, SecCSFlags flags,
        BEGIN_CSAPI
        
        checkFlags(flags);
-       Required(requirementRef) = (new SecRequirement(CFDataGetBytePtr(data), CFDataGetLength(data)))->handle();
+       CodeSigning::Required(requirementRef) = (new SecRequirement(CFDataGetBytePtr(data), CFDataGetLength(data)))->handle();
 
        END_CSAPI
 }
@@ -71,7 +71,7 @@ OSStatus SecRequirementCreateWithResource(CFURLRef resource, SecCSFlags flags,
        
        checkFlags(flags);
        CFRef<CFDataRef> data = cfLoadFile(resource);
-       Required(requirementRef) =
+       CodeSigning::Required(requirementRef) =
                (new SecRequirement(CFDataGetBytePtr(data), CFDataGetLength(data)))->handle();
 
        END_CSAPI
@@ -93,7 +93,7 @@ OSStatus SecRequirementCreateWithStringAndErrors(CFStringRef text, SecCSFlags fl
        BEGIN_CSAPI
        
        checkFlags(flags);
-       Required(requirementRef) = (new SecRequirement(parseRequirement(cfString(text))))->handle();
+       CodeSigning::Required(requirementRef) = (new SecRequirement(parseRequirement(cfString(text)), true))->handle();
 
        END_CSAPI_ERRORS
 }
@@ -119,9 +119,7 @@ OSStatus SecRequirementCreateGroup(CFStringRef groupName, SecCertificateRef anch
        } else {
                maker.anchor();                 // canonical Apple anchor
        }
-       Required(requirementRef) = (new SecRequirement(maker.make(), true))->handle();
-
-       secdebug("codesign", "created group requirement for %s", cfString(groupName).c_str());
+       CodeSigning::Required(requirementRef) = (new SecRequirement(maker.make(), true))->handle();
 
        END_CSAPI
 }
@@ -137,7 +135,7 @@ OSStatus SecRequirementCopyData(SecRequirementRef requirementRef, SecCSFlags fla
        
        const Requirement *req = SecRequirement::required(requirementRef)->requirement();
        checkFlags(flags);
-       Required(data);
+       CodeSigning::Required(data);
        *data = makeCFData(*req);
 
        END_CSAPI
@@ -154,9 +152,128 @@ OSStatus SecRequirementCopyString(SecRequirementRef requirementRef, SecCSFlags f
        
        const Requirement *req = SecRequirement::required(requirementRef)->requirement();
        checkFlags(flags);
-       Required(text);
+       CodeSigning::Required(text);
        *text = makeCFString(Dumper::dump(req));
 
        END_CSAPI
 }
 
+
+//
+// Assemble a requirement set (as a CFData) from a dictionary of requirement objects.
+// An empty set is allowed.
+//
+OSStatus SecRequirementsCreateFromRequirements(CFDictionaryRef requirements, SecCSFlags flags,
+       CFDataRef *requirementSet)
+{
+       BEGIN_CSAPI
+       
+       checkFlags(flags);
+       if (requirements == NULL)
+               return errSecCSObjectRequired;
+       CFIndex count = CFDictionaryGetCount(requirements);
+       CFNumberRef keys[count];
+       SecRequirementRef reqs[count];
+       CFDictionaryGetKeysAndValues(requirements, (const void **)keys, (const void **)reqs);
+       Requirements::Maker maker;
+       for (CFIndex n = 0; n < count; n++) {
+               const Requirement *req = SecRequirement::required(reqs[n])->requirement();
+               maker.add(cfNumber<Requirements::Type>(keys[n]), req->clone());
+       }
+       Requirements *reqset = maker.make();                                    // malloc'ed
+       CodeSigning::Required(requirementSet) = makeCFDataMalloc(*reqset);      // takes ownership of reqs
+
+       END_CSAPI
+}
+
+
+//
+// Break a requirement set (given as a CFData) into its constituent requirements
+// and return it as a CFDictionary.
+//
+OSStatus SecRequirementsCopyRequirements(CFDataRef requirementSet, SecCSFlags flags,
+       CFDictionaryRef *requirements)
+{
+       BEGIN_CSAPI
+       
+       checkFlags(flags);
+       if (requirementSet == NULL)
+               return errSecCSObjectRequired;
+       const Requirements *reqs = (const Requirements *)CFDataGetBytePtr(requirementSet);
+       CFRef<CFMutableDictionaryRef> dict = makeCFMutableDictionary();
+       unsigned count = reqs->count();
+       for (unsigned n = 0; n < count; n++) {
+               CFRef<SecRequirementRef> req = (new SecRequirement(reqs->blob<Requirement>(n)))->handle();
+               CFDictionaryAddValue(dict, CFTempNumber(reqs->type(n)), req);
+       }
+       CodeSigning::Required(requirements) = dict.yield();
+
+       END_CSAPI
+}
+
+       
+//
+// Generically parse a string as some kind of requirement-related source form.
+// If properly recognized, return the result as a CF object:
+//     SecRequirementRef for a single requirement
+//     CFDataRef for a requirement set
+//
+OSStatus SecRequirementsCreateWithString(CFStringRef text, SecCSFlags flags,
+       CFTypeRef *result, CFErrorRef *errors)
+{
+       BEGIN_CSAPI
+       
+       checkFlags(flags, kSecCSParseRequirement | kSecCSParseRequirementSet);
+       if (text == NULL || result == NULL)
+               return errSecCSObjectRequired;
+       std::string s = cfString(text);
+       switch (flags & (kSecCSParseRequirement | kSecCSParseRequirementSet)) {
+       case kSecCSParseRequirement:            // single only
+               *result = (new SecRequirement(parseRequirement(s), true))->handle();
+               break;
+       case kSecCSParseRequirementSet:         // single only
+               {
+                       const Requirements *reqs = parseRequirements(s);
+                       *result = makeCFDataMalloc(*reqs);
+                       break;
+               }
+       case 0:
+       case kSecCSParseRequirement | kSecCSParseRequirementSet:
+               {
+                       const BlobCore *any = parseGeneric(s);
+                       if (any->is<Requirement>())
+                               *result = (new SecRequirement(Requirement::specific(any), true))->handle();
+                       else
+                               *result = makeCFDataMalloc(*any);
+                       break;
+               }
+       }
+
+       END_CSAPI_ERRORS
+}
+
+       
+//
+// Convert a SecRequirementRef or a CFDataRef containing a requirement set to text.
+// Requirement sets will be formatted as multiple lines (one per requirement). They can be empty.
+// A single requirement will return a single line that is NOT newline-terminated.
+//
+OSStatus SecRequirementsCopyString(CFTypeRef input, SecCSFlags flags, CFStringRef *text)
+{
+       BEGIN_CSAPI
+       
+       checkFlags(flags);
+       if (input == NULL)
+               return errSecCSObjectRequired;
+       if (CFGetTypeID(input) == SecRequirementGetTypeID()) {
+               return SecRequirementCopyString(SecRequirementRef(input), flags, text);
+       } else if (CFGetTypeID(input) == CFDataGetTypeID()) {
+               const Requirements *reqs = (const Requirements *)CFDataGetBytePtr(CFDataRef(input));
+               if (!reqs->validateBlob(CFDataGetLength(CFDataRef(input))))
+                       return errSecCSReqInvalid;
+               CodeSigning::Required(text) = makeCFString(Dumper::dump(reqs, false));
+       } else
+               return errSecCSInvalidObjectRef;
+
+       END_CSAPI
+}
index 358b1b251fb5288d67e6bca87dd9c8eb9d92eb48..9a11c6f999f34b54d62163af2544139dd2602856 100644 (file)
 #ifndef _H_SECREQUIREMENT
 #define _H_SECREQUIREMENT
 
+#include <Security/CSCommon.h>
+#include <Security/SecCertificate.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-#include <Security/CSCommon.h>
-#include <Security/SecCertificate.h>
-
 
 /*!
        @function SecRequirementGetTypeID
@@ -70,22 +70,7 @@ CFTypeID SecRequirementGetTypeID(void);
 OSStatus SecRequirementCreateWithData(CFDataRef data, SecCSFlags flags,
        SecRequirementRef *requirement);
 
-/*!
-       @function SecRequirementCreateWithResource
-       Create a SecRequirement object from binary form obtained from a file.
-       This call is functionally equivalent to reading the entire contents of a file
-       into a CFDataRef and then calling SecRequirementCreateWithData with that.
        
-       @param resource A CFURL identifying a file containing a (binary) requirement blob.
-       @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
-       @param requirement On successful return, contains a reference to a SecRequirement
-       object that behaves identically to the one the data blob was obtained from.
-       @result Upon success, noErr. Upon error, an OSStatus value documented in
-       CSCommon.h or certain other Security framework headers.
-*/
-OSStatus SecRequirementCreateWithResource(CFURLRef resource, SecCSFlags flags,
-       SecRequirementRef *requirement);
-
 /*!
        @function SecRequirementCreateWithString
        Create a SecRequirement object by compiling a valid text representation
@@ -108,23 +93,6 @@ OSStatus SecRequirementCreateWithString(CFStringRef text, SecCSFlags flags,
 OSStatus SecRequirementCreateWithStringAndErrors(CFStringRef text, SecCSFlags flags,
        CFErrorRef *errors, SecRequirementRef *requirement);
 
-/*!
-       @function SecRequirementCreateGroup
-       Create a SecRequirement object that represents membership in a developer-defined
-       application     group. Group membership is defined by an entry in the code's
-       Info.plist, and sealed to a particular signing authority.
-       
-       @param groupName A CFString containing the name of the desired application group.
-       @param anchor A reference to a digital certificate representing the signing
-       authority that asserts group membership. If NULL, indicates Apple's authority.
-       @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
-       @param requirement On successful return, contains a reference to a SecRequirement
-       object that requires group membership to pass validation.
-       @result Upon success, noErr. Upon error, an OSStatus value documented in
-       CSCommon.h or certain other Security framework headers.
-*/
-OSStatus SecRequirementCreateGroup(CFStringRef groupName, SecCertificateRef anchor,
-       SecCSFlags flags, SecRequirementRef *requirement);
 
 /*!
        @function SecRequirementCopyData
diff --git a/lib/SecRequirementPriv.h b/lib/SecRequirementPriv.h
new file mode 100644 (file)
index 0000000..249eba4
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2006 Apple Computer, 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@
+ */
+
+/*!
+       @header SecRequirement
+       SecRequirementPriv is the private counter-part to SecRequirement. Its contents are not
+       official API, and are subject to change without notice.
+*/
+#ifndef _H_SECREQUIREMENTPRIV
+#define _H_SECREQUIREMENTPRIV
+
+#include <Security/SecRequirement.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*!
+       @function SecRequirementsCreateFromRequirements
+       Take a dictionary of requirement objects and package them up as a requirement set.
+       
+       @param requirements A dictionary of requirements to combine into a set.
+       Dictionary keys are CFNumbers representing the index keys. Values are SecRequirementRefs.
+       NULL requirements are not allowed in the dictionary.
+       @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
+       @param requirementSet Upon success, receives a CFData object 
+       @result Upon success, noErr. Upon error, an OSStatus value documented in
+       CSCommon.h or certain other Security framework headers.
+*/
+OSStatus SecRequirementsCreateFromRequirements(CFDictionaryRef requirements, SecCSFlags flags,
+       CFDataRef *requirementSet);
+
+
+/*!
+       @function SecRequirementsCopyRequirements
+       Create a SecRequirement object from binary form obtained from a file.
+       This call is functionally equivalent to reading the entire contents of a file
+       into a CFDataRef and then calling SecRequirementCreateWithData with that.
+       
+       @param requirementSet A CFData containing a requirement set.
+       @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
+       @param requirements Upon success, a dictionary containing each requirement contained
+       in requirementSet. The keys are CFNumbers indicating the requirement type.
+       @result Upon success, noErr. Upon error, an OSStatus value documented in
+       CSCommon.h or certain other Security framework headers.
+*/
+OSStatus SecRequirementsCopyRequirements(CFDataRef requirementSet, SecCSFlags flags,
+       CFDictionaryRef *requirements);
+
+       
+/*!
+       @function SecRequirementsCreateWithString
+       Create a SecRequirement object or requirement set based on the string provided.
+       
+       @param text A CFString containing the text form of a (single) Code Requirement.
+       @param flags Optional flags. Pass kSecCSDefaultFlags to accept any supported input form.
+       Pass a combination of individual flags to select what forms to accept; other forms will result
+       in an error.
+       @param result Upon success, a CoreFoundation object of some kind representing
+       the result of parsing text. Depending on the input string and flags, the result
+       can be a SecRequirementRef (for a single requirement) or a CFDataRef for a requirement set.
+       @param errors An optional pointer to a CFErrorRef variable. If the call fails
+       (and something other than noErr is returned), and this argument is non-NULL,
+       a CFErrorRef is stored there further describing the nature and circumstances
+       of the failure. The caller must CFRelease() this error object when done with it.
+       @result Upon success, noErr. Upon error, an OSStatus value documented in
+       CSCommon.h or certain other Security framework headers.
+*/
+enum {
+       kSecCSParseRequirement = 0x0001,                // accept single requirements
+       kSecCSParseRequirementSet = 0x0002,             // accept requirement sets
+};
+
+OSStatus SecRequirementsCreateWithString(CFStringRef text, SecCSFlags flags,
+       CFTypeRef *result, CFErrorRef *errors);
+
+
+/*!
+       @function SecRequirementsCopyString
+       Converts a requirement object of some kind into text form.
+       This is the effective inverse of SecRequirementsCreateWithString.
+
+       This function can process individual requirements (SecRequirementRefs)
+       and requirement sets (represented as CFDataRefs).
+       
+       Repeated application of this function may produce text that differs in
+       formatting, may contain different source comments, and may perform its
+       validation functions in different order. However, it is guaranteed that
+       recompiling the text using SecRequirementCreateWithString will produce a
+       SecRequirement object that behaves identically to the one you start with.
+       
+       @param requirements A SecRequirementRef, or a CFDataRef containing a valid requirement set.
+       @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
+       @param text On successful return, contains a reference to a CFString object
+       containing a text representation of the requirement.
+       @result Upon success, noErr. Upon error, an OSStatus value documented in
+       CSCommon.h or certain other Security framework headers.
+*/
+OSStatus SecRequirementsCopyString(CFTypeRef input, SecCSFlags flags, CFStringRef *text);
+       
+
+/*!
+       @function SecRequirementCreateWithResource
+       Create a SecRequirement object from binary form obtained from a file.
+       This call is functionally equivalent to reading the entire contents of a file
+       into a CFDataRef and then calling SecRequirementCreateWithData with that.
+       
+       @param resource A CFURL identifying a file containing a (binary) requirement blob.
+       @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
+       @param requirement On successful return, contains a reference to a SecRequirement
+       object that behaves identically to the one the data blob was obtained from.
+       @result Upon success, noErr. Upon error, an OSStatus value documented in
+       CSCommon.h or certain other Security framework headers.
+*/
+OSStatus SecRequirementCreateWithResource(CFURLRef resource, SecCSFlags flags,
+       SecRequirementRef *requirement);
+
+       
+/*!
+       @function SecRequirementCreateGroup
+       Create a SecRequirement object that represents membership in a developer-defined
+       application     group. Group membership is defined by an entry in the code's
+       Info.plist, and sealed to a particular signing authority.
+
+       This is not an API-track function. Don't call it if you don't already do.
+       
+       @param groupName A CFString containing the name of the desired application group.
+       @param anchor A reference to a digital certificate representing the signing
+       authority that asserts group membership. If NULL, indicates Apple's authority.
+       @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
+       @param requirement On successful return, contains a reference to a SecRequirement
+       object that requires group membership to pass validation.
+       @result Upon success, noErr. Upon error, an OSStatus value documented in
+       CSCommon.h or certain other Security framework headers.
+*/
+OSStatus SecRequirementCreateGroup(CFStringRef groupName, SecCertificateRef anchor,
+       SecCSFlags flags, SecRequirementRef *requirement);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_H_SECREQUIREMENTPRIV
index 51dd2a4000582a013feaa4c9bd6d96cb8137bbf9..e56d188c0d4a53ffdaae59c52a0cdab86dedf28a 100644 (file)
@@ -26,6 +26,7 @@
 //
 #include "cs.h"
 #include "StaticCode.h"
+#include <security_utilities/cfmunge.h>
 #include <fcntl.h>
 
 using namespace CodeSigning;
@@ -50,7 +51,38 @@ OSStatus SecStaticCodeCreateWithPath(CFURLRef path, SecCSFlags flags, SecStaticC
        BEGIN_CSAPI
        
        checkFlags(flags);
-       Required(staticCodeRef) = (new SecStaticCode(DiskRep::bestGuess(cfString(path).c_str())))->handle();
+       CodeSigning::Required(staticCodeRef) = (new SecStaticCode(DiskRep::bestGuess(cfString(path).c_str())))->handle();
+
+       END_CSAPI
+}
+
+const CFStringRef kSecCodeAttributeArchitecture =      CFSTR("architecture");
+const CFStringRef kSecCodeAttributeSubarchitecture =CFSTR("subarchitecture");
+const CFStringRef kSecCodeAttributeBundleVersion =     CFSTR("bundleversion");
+
+OSStatus SecStaticCodeCreateWithPathAndAttributes(CFURLRef path, SecCSFlags flags, CFDictionaryRef attributes,
+       SecStaticCodeRef *staticCodeRef)
+{
+       BEGIN_CSAPI
+       
+       checkFlags(flags);
+       DiskRep::Context ctx;
+       std::string version; // holds memory placed into ctx
+       if (attributes) {
+               std::string archName;
+               int archNumber, subarchNumber;
+               if (cfscan(attributes, "{%O=%s}", kSecCodeAttributeArchitecture, &archName)) {
+                       ctx.arch = Architecture(archName.c_str());
+               } else if (cfscan(attributes, "{%O=%d,%O=%d}",
+                               kSecCodeAttributeArchitecture, &archNumber, kSecCodeAttributeSubarchitecture, &subarchNumber))
+                       ctx.arch = Architecture(archNumber, subarchNumber);
+               else if (cfscan(attributes, "{%O=%d}", kSecCodeAttributeArchitecture, &archNumber))
+                       ctx.arch = Architecture(archNumber);
+               if (cfscan(attributes, "{%O=%s}", kSecCodeAttributeBundleVersion, &version))
+                       ctx.version = version.c_str();
+       }
+       
+       CodeSigning::Required(staticCodeRef) = (new SecStaticCode(DiskRep::bestGuess(cfString(path).c_str(), &ctx)))->handle();
 
        END_CSAPI
 }
@@ -59,6 +91,36 @@ OSStatus SecStaticCodeCreateWithPath(CFURLRef path, SecCSFlags flags, SecStaticC
 //
 // Check static validity of a StaticCode
 //
+static void validate(SecStaticCode *code, const SecRequirement *req, SecCSFlags flags)
+{
+       try {
+               code->validateDirectory();
+               if (!(flags & kSecCSDoNotValidateExecutable))
+                       code->validateExecutable();
+               if (!(flags & kSecCSDoNotValidateResources))
+                       code->validateResources();
+               if (req)
+                       code->validateRequirement(req->requirement(), errSecCSReqFailed);
+       } catch (CSError &err) {
+               if (Universal *fat = code->diskRep()->mainExecutableImage())    // Mach-O
+                       if (MachO *mach = fat->architecture()) {
+                               err.augment(kSecCFErrorArchitecture, CFTempString(mach->architecture().displayName()));
+                               delete mach;
+                       }
+               throw;
+       } catch (const MacOSError &err) {
+               // add architecture information if we can get it
+               if (Universal *fat = code->diskRep()->mainExecutableImage())
+                       if (MachO *mach = fat->architecture()) {
+                               CFTempString arch(mach->architecture().displayName());
+                               delete mach;
+                               CSError::throwMe(err.error, kSecCFErrorArchitecture, arch);
+                       }
+               // else just pass it on
+               throw;
+       }
+}
+
 OSStatus SecStaticCodeCheckValidity(SecStaticCodeRef staticCodeRef, SecCSFlags flags,
        SecRequirementRef requirementRef)
 {
@@ -77,13 +139,14 @@ OSStatus SecStaticCodeCheckValidityWithErrors(SecStaticCodeRef staticCodeRef, Se
                | kSecCSConsiderExpiration);
 
        SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(staticCodeRef);
-       code->validateDirectory();
-       if (!(flags & kSecCSDoNotValidateExecutable))
-               code->validateExecutable();
-       if (!(flags & kSecCSDoNotValidateResources))
-               code->validateResources();
-       if (const SecRequirement *req = SecRequirement::optional(requirementRef))
-               code->validateRequirements(req->requirement(), errSecCSReqFailed);
+       const SecRequirement *req = SecRequirement::optional(requirementRef);
+       DTRACK(CODESIGN_EVAL_STATIC, code, (char*)code->mainExecutablePath().c_str());
+       if (flags & kSecCSCheckAllArchitectures) {
+               SecStaticCode::AllArchitectures archs(code);
+               while (SecPointer<SecStaticCode> scode = archs())
+                       validate(scode, req, flags);
+       } else
+               validate(code, req, flags);
 
        END_CSAPI_ERRORS
 }
@@ -107,7 +170,7 @@ OSStatus SecCodeCopyPath(SecStaticCodeRef staticCodeRef, SecCSFlags flags, CFURL
        
        checkFlags(flags);
        SecPointer<SecStaticCode> staticCode = SecStaticCode::requiredStatic(staticCodeRef);
-       Required(path) = staticCode->canonicalPath();
+       CodeSigning::Required(path) = staticCode->canonicalPath();
 
        END_CSAPI
 }
@@ -124,7 +187,24 @@ OSStatus SecCodeCopyDesignatedRequirement(SecStaticCodeRef staticCodeRef, SecCSF
        checkFlags(flags);
        const Requirement *req =
                SecStaticCode::requiredStatic(staticCodeRef)->designatedRequirement();
-       Required(requirementRef) = (new SecRequirement(req))->handle();
+       CodeSigning::Required(requirementRef) = (new SecRequirement(req))->handle();
+
+       END_CSAPI
+}
+
+
+//
+// Fetch a particular internal requirement, if present
+//
+OSStatus SecCodeCopyInternalRequirement(SecStaticCodeRef staticCodeRef, SecRequirementType type,
+       SecCSFlags flags, SecRequirementRef *requirementRef)
+{
+       BEGIN_CSAPI
+       
+       checkFlags(flags);
+       const Requirement *req =
+               SecStaticCode::requiredStatic(staticCodeRef)->internalRequirement(type);
+       CodeSigning::Required(requirementRef) = req ? (new SecRequirement(req))->handle() : NULL;
 
        END_CSAPI
 }
@@ -141,7 +221,9 @@ OSStatus SecCodeSetDetachedSignature(SecStaticCodeRef codeRef, CFDataRef signatu
        checkFlags(flags);
        SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(codeRef);
 
-       code->detachedSignature(signature);
+       if (signature)
+               CFRetain(signature);    // own a reference...
+       code->detachedSignature(signature); // ... and pass it to the code
        code->resetValidity();
 
        END_CSAPI
index 8e3b04b28fefee25450237aa3803724b4f40251b..36a1b7e51db4f91a2d973aad08a50a60c8622ec8 100644 (file)
        @header SecStaticCode
        SecStaticCode represents the Code Signing identity of code in the file system.
        This includes applications, tools, frameworks, plugins, scripts, and so on.
+       Note that arbitrary files will be considered scripts of unknown provenance;
+       and thus it is possible to handle most files as if they were code, though that is
+       not necessarily a good idea.
        
        Normally, each SecCode has a specific SecStaticCode that holds its static signing
-       data. Informally, that is the SecStaticCode the SecCode "was made from". There is
-       however no viable link in the other direction - given a SecStaticCode, it is not
-       possible to find, enumerate, or control any SecCode that originated from it.
+       data. Informally, that is the SecStaticCode the SecCode "was made from" (by its host).
+       There is however no viable link in the other direction - given a SecStaticCode,
+       it is not possible to find, enumerate, or control any SecCode that originated from it.
+       There might not be any at a given point in time; or there might be many.
 */
 #ifndef _H_SECSTATICCODE
 #define _H_SECSTATICCODE
 
+#include <Security/CSCommon.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-#include <Security/CSCommon.h>
-
 
 /*!
        @function SecStaticCodeGetTypeID
@@ -55,20 +59,42 @@ CFTypeID SecStaticCodeGetTypeID(void);
        linked to running code in the system.
        
        It is possible to create a SecStaticCode object from an unsigned code object.
-       Most uses of such an object will return the errSecCSUnsigned error.
+       Most uses of such an object will return the errSecCSUnsigned error. However,
+       SecCodeCopyPath and SecCodeCopySigningInformation can be safely applied to such objects.
 
        @param path A path to a location in the file system. Only file:// URLs are
        currently supported. For bundles, pass a URL to the root directory of the
        bundle. For single files, pass a URL to the file. If you pass a URL to the
        main executable of a bundle, the bundle as a whole will be generally recognized.
+       Caution: Paths containing embedded // or /../ within a bundle's directory
+       may cause the bundle to be misconstrued. If you expect to submit such paths,
+       first clean them with realpath(3) or equivalent.
        @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
+       @param attributes A CFDictionary containing additional attributes of the code sought.
        @param staticCode On successful return, contains a reference to the StaticCode object
        representing the code at path. Unchanged on error.
        @result Upon success, noErr. Upon error, an OSStatus value documented in
        CSCommon.h or certain other Security framework headers.
+       
+       @constant kSecCodeAttributeArchitecture Specifies the Mach-O architecture of code desired.
+       This can be a CFString containing a canonical architecture name ("i386" etc.), or a CFNumber
+       specifying an architecture numerically (see mach/machine.h). This key is ignored if the code
+       is not in Mach-O binary form. If the code is Mach-O but not universal ("thin"), the architecture
+       specified must agree with the actual file contents.
+       @constant kSecCodeAttributeSubarchitecture If the architecture is specified numerically
+       (using the kSecCodeAttributeArchitecture key), specifies any sub-architecture by number.
+       This key is ignored if no main architecture is specified; if it is specified by name; or
+       if the code is not in Mach-O form.
 */
+extern const CFStringRef kSecCodeAttributeArchitecture;
+extern const CFStringRef kSecCodeAttributeSubarchitecture;
+extern const CFStringRef kSecCodeAttributeBundleVersion;
+
 OSStatus SecStaticCodeCreateWithPath(CFURLRef path, SecCSFlags flags, SecStaticCodeRef *staticCode);
 
+OSStatus SecStaticCodeCreateWithPathAndAttributes(CFURLRef path, SecCSFlags flags, CFDictionaryRef attributes,
+       SecStaticCodeRef *staticCode);
+
 
 /*!
        @function SecStaticCodeCheckValidity
@@ -80,6 +106,8 @@ OSStatus SecStaticCodeCreateWithPath(CFURLRef path, SecCSFlags flags, SecStaticC
        
        This call is only secure if the code is not subject to concurrent modification,
        and the outcome is only valid as long as the code is unmodified thereafter.
+       Consider this carefully if the underlying file system has dynamic characteristics,
+       such as a network file system, union mount, FUSE, etc.
 
        @param staticCode The code object to be validated.
        @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
@@ -97,10 +125,10 @@ OSStatus SecStaticCodeCreateWithPath(CFURLRef path, SecCSFlags flags, SecStaticC
        the staticCode object must satisfy to be considered valid. If NULL, no additional
        requirements are imposed.
        @param errors An optional pointer to a CFErrorRef variable. If the call fails
-       (and something other than noErr is returned), and this argument is non-NULL,
+       (something other than noErr is returned), and this argument is non-NULL,
        a CFErrorRef is stored there further describing the nature and circumstances
        of the failure. The caller must CFRelease() this error object when done with it.
-       @result If validation passes, noErr. If validation fails, an OSStatus value
+       @result If validation succeeds, noErr. If validation fails, an OSStatus value
        documented in CSCommon.h or certain other Security framework headers.
 */
 enum {
diff --git a/lib/SecStaticCodePriv.h b/lib/SecStaticCodePriv.h
new file mode 100644 (file)
index 0000000..1f0d74c
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2006 Apple Computer, 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@
+ */
+
+/*!
+       @header SecStaticCode
+       SecStaticCodePriv is the private counter-part to SecStaticCode. Its contents are not
+       official API, and are subject to change without notice.
+*/
+#ifndef _H_SECSTATICCODEPRIV
+#define _H_SECSTATICCODEPRIV
+
+#include <Security/SecStaticCode.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Currently empty
+ */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_H_SECSTATICCODEPRIV
diff --git a/lib/SecTask.c b/lib/SecTask.c
new file mode 100644 (file)
index 0000000..a1d62aa
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2009 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@
+ */
+
+#include <CoreFoundation/CFRuntime.h>
+#include <Carbon/Carbon.h>     /* Yuck! For MacErrors.h */
+
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOCFUnserialize.h>
+
+#include <pthread.h>
+
+#include <bsm/libbsm.h>
+
+/* XXX: convert <Security/xyz.h> -> "xyz.h" for these when in project */
+#include "SecCode.h"
+#include "SecRequirement.h"
+
+/* #include <debugging.h> */
+
+#include "SecTask.h"
+
+struct __SecTask {
+       CFRuntimeBase base;
+
+       audit_token_t token;
+
+       /* Track whether we've loaded entitlements independently since after the
+        * load, entitlements may legitimately be NULL */
+       Boolean entitlementsLoaded;
+       CFDictionaryRef entitlements;
+};
+
+enum {
+       kSecCodeMagicEntitlement = 0xfade7171,          /* entitlement blob */
+};
+
+
+CFTypeID _kSecTaskTypeID = _kCFRuntimeNotATypeID;
+
+static void SecTaskFinalize(CFTypeRef cfTask)
+{
+       SecTaskRef task = (SecTaskRef) cfTask;
+
+       if (task->entitlements != NULL) {
+               CFRelease(task->entitlements);
+               task->entitlements = NULL;
+       }
+}
+
+static CFStringRef SecTaskCopyDebugDescription(CFTypeRef cfTask)
+{
+       SecTaskRef task = (SecTaskRef) cfTask;
+
+       return CFStringCreateWithFormat(CFGetAllocator(task), NULL, CFSTR("<SecTask %p>"), task);
+}
+
+static void SecTaskRegisterClass(void)
+{
+       static const CFRuntimeClass SecTaskClass = {
+               .version = 0,
+               .className = "SecTask",
+               .init = NULL,
+               .copy = NULL,
+               .finalize = SecTaskFinalize,
+               .equal = NULL,
+               .hash = NULL,
+               .copyFormattingDesc = NULL,
+               .copyDebugDesc = SecTaskCopyDebugDescription,
+       };
+
+       _kSecTaskTypeID = _CFRuntimeRegisterClass(&SecTaskClass);
+}
+
+CFTypeID SecTaskGetTypeID(void)
+{
+       static pthread_once_t secTaskRegisterClassOnce = PTHREAD_ONCE_INIT;
+
+       /* Register the class with the CF runtime the first time through */
+       pthread_once(&secTaskRegisterClassOnce, SecTaskRegisterClass);
+
+       return _kSecTaskTypeID;
+}
+
+SecTaskRef SecTaskCreateWithAuditToken(CFAllocatorRef allocator, audit_token_t token)
+{
+       CFIndex extra = sizeof(struct __SecTask) - sizeof(CFRuntimeBase);
+       SecTaskRef task = (SecTaskRef) _CFRuntimeCreateInstance(allocator, SecTaskGetTypeID(), extra, NULL);
+       if (task != NULL) {
+
+               memcpy(&task->token, &token, sizeof(token));
+               task->entitlementsLoaded = false;
+               task->entitlements = NULL;
+       }
+
+       return task;
+}
+
+
+static CFDictionaryRef parseEntitlementsFromData(CFDataRef blobData)
+{
+       const struct theBlob {
+               uint32_t magic;  /* kSecCodeMagicEntitlement */
+               uint32_t length;
+               const uint8_t data[];
+       } *blob = NULL;
+
+       CFDictionaryRef entitlements = NULL;
+
+       size_t blobDataLen = CFDataGetLength (blobData);
+
+       /* Make sure we're at least the size of a blob */
+       if (blobDataLen <= sizeof(struct theBlob)) goto fin;
+
+       blob = (const struct theBlob *) CFDataGetBytePtr (blobData);
+
+       /* Check the magic */
+       if (kSecCodeMagicEntitlement != ntohl(blob->magic)) goto fin;
+
+       /* Make sure we have as much data as the blob says we should */
+       if (blobDataLen != ntohl(blob->length)) goto fin;
+
+       /* Convert the blobs payload to a dictionary */
+       CFDataRef entitlementData = CFDataCreateWithBytesNoCopy (kCFAllocatorDefault,
+                       blob->data,
+                       blobDataLen - sizeof(struct theBlob),
+                       kCFAllocatorNull);
+
+       if (NULL == entitlementData) goto fin;
+
+       entitlements = CFPropertyListCreateFromXMLData (kCFAllocatorDefault,
+                       entitlementData,
+                       kCFPropertyListImmutable,
+                       NULL);
+       if (NULL == entitlements) goto fin;
+
+       if (CFGetTypeID(entitlements) != CFDictionaryGetTypeID()) {
+               CFRelease (entitlements);
+               entitlements = NULL;
+       }
+fin:
+       if (NULL != entitlementData) { CFRelease (entitlementData); }
+
+       return entitlements;
+}
+
+
+static void SecTaskLoadEntitlements(SecTaskRef task, CFErrorRef *error)
+{
+       pid_t   pid;
+       CFNumberRef targetPID = NULL;
+       CFDictionaryRef guestAttributes = NULL;
+       CFDictionaryRef targetInfo = NULL;
+       CFDictionaryRef entitlements = NULL;
+       CFDataRef entitlementData = NULL;
+       SecCodeRef target = NULL;
+       CFErrorRef cfErr = NULL;
+       OSStatus ret = noErr;
+
+       /* XXX: Check for NULL == task->token? */
+
+       audit_token_to_au32 (task->token,
+                       /* auidp */ NULL,
+                       /* euidp */ NULL,
+                       /* egidp */ NULL,
+                       /* ruidp */ NULL,
+                       /* rgidp */ NULL,
+                       /* pidp  */ &pid,
+                       /* asidp */ NULL,
+                       /* tidp  */ NULL);
+
+       /*
+        * Ref: /usr/include/sys/_types.h
+        * typedef __int32_t       __darwin_pid_t;
+        */
+
+       targetPID = CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt32Type, &pid);
+       if (NULL == targetPID) {
+               ret = kPOSIXErrorENOMEM;
+               goto err;
+       }
+
+       guestAttributes = CFDictionaryCreate (kCFAllocatorDefault,
+                       (const void **)&kSecGuestAttributePid,
+                       (const void **)&targetPID,
+                       1,
+                       NULL,
+                       NULL);
+       if (NULL == guestAttributes) goto err;
+
+       ret = SecCodeCopyGuestWithAttributes (NULL,
+                       guestAttributes,
+                       kSecCSDefaultFlags,
+                       &target);
+       if (noErr != ret) goto err;
+
+       ret = SecCodeCopySigningInformation (target,
+                       kSecCSRequirementInformation,
+                       &targetInfo);
+       if (noErr != ret || NULL == targetInfo) goto err;
+
+       bool gotKey = CFDictionaryGetValueIfPresent (targetInfo,
+                       (const void *)kSecCodeInfoEntitlements,
+                       (const void **)&entitlementData);
+       if (false == gotKey || NULL == entitlementData) {
+               ret = kIOReturnInvalid;
+               goto err;
+       }
+
+       task->entitlements = parseEntitlementsFromData (entitlementData);
+       if (NULL == task->entitlements) goto err;
+
+       /* secdebug("entitlements", "entitlements %@", task->entitlements); */
+
+       task->entitlementsLoaded = true;
+err:
+       if (noErr != ret && NULL != error) {
+               if (NULL != cfErr) {
+                       *error = cfErr;
+               } else {
+                       *error = CFErrorCreate(CFGetAllocator(task), kCFErrorDomainMach, ret, NULL);
+               }
+       }
+
+       /* Free up any allocated things now! */
+       if (NULL != targetPID) CFRelease (targetPID);
+
+       if (NULL != guestAttributes) CFRelease (guestAttributes);
+
+       if (NULL != target) CFRelease (target);
+
+       if (NULL != targetInfo) CFRelease (targetInfo);
+}
+
+CFTypeRef SecTaskCopyValueForEntitlement(SecTaskRef task, CFStringRef entitlement, CFErrorRef *error)
+{
+       /* Load entitlements if necessary */
+       if (task->entitlementsLoaded == false) {
+               SecTaskLoadEntitlements(task, error);
+       }
+
+       CFTypeRef value = NULL;
+       if (task->entitlements != NULL) {
+               value = CFDictionaryGetValue(task->entitlements, entitlement);
+
+               /* Return something the caller must release */
+               if (value != NULL) {
+                       CFRetain(value);
+               }
+       }
+
+       return value;
+}
+
+CFDictionaryRef SecTaskCopyValuesForEntitlements(SecTaskRef task, CFArrayRef entitlements, CFErrorRef *error)
+{
+       /* Load entitlements if necessary */
+       if (task->entitlementsLoaded == false) {
+               SecTaskLoadEntitlements(task, error);
+       }
+
+       /* Iterate over the passed in entitlements, populating the dictionary
+        * If entitlements were loaded but none were present, return an empty
+        * dictionary */
+       CFMutableDictionaryRef values = NULL;
+       if (task->entitlementsLoaded == true) {
+
+               CFIndex i, count = CFArrayGetCount(entitlements);
+               values = CFDictionaryCreateMutable(CFGetAllocator(task), count, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+               if (task->entitlements != NULL) {
+                       for (i = 0; i < count; i++) {
+                               CFStringRef entitlement = CFArrayGetValueAtIndex(entitlements, i);
+                               CFTypeRef value = CFDictionaryGetValue(task->entitlements, entitlement);
+                               if (value != NULL) {
+                                       CFDictionarySetValue(values, entitlement, value);
+                               }
+                       }
+               }
+       }
+
+       return values;
+}
diff --git a/lib/SecTask.h b/lib/SecTask.h
new file mode 100644 (file)
index 0000000..309857d
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2008-2009 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@
+ */
+
+#ifndef _SECURITY_SECTASK_H_
+#define _SECURITY_SECTASK_H_
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <mach/message.h>
+#include <Security/SecCode.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+    @typedef SecTaskRef
+    @abstract CFType used for representing a task
+*/
+typedef struct __SecTask *SecTaskRef;
+
+/*!
+    @function SecTaskGetTypeID
+    @abstract Returns the type ID for CF instances of SecTask.
+    @result A CFTypeID for SecTask
+*/
+CFTypeID SecTaskGetTypeID(void);
+
+/*!
+    @function SecTaskCreateWithAuditToken
+    @abstract Create a SecTask object for the task that sent the mach message
+    represented by the audit token.
+    @param token The audit token of a mach message
+    @result The newly created SecTask object or NULL on error.  The caller must
+    CFRelease the returned object.
+*/
+SecTaskRef SecTaskCreateWithAuditToken(CFAllocatorRef allocator, audit_token_t token);
+
+/*!
+    @function SecTaskCopyValueForEntitlement
+    @abstract Returns the value of a single entitlement for the represented 
+    task.
+    @param task A previously created SecTask object
+    @param entitlement The name of the entitlement to be fetched
+    @param error On a NULL return, this may be contain a CFError describing
+    the problem.  This argument may be NULL if the caller is not interested in
+    detailed errors.
+    @result The value of the specified entitlement for the process or NULL if
+    the entitlement value could not be retrieved.  The type of the returned
+    value will depend on the entitlement specified.  The caller must release
+    the returned object.
+    @discussion A NULL return may indicate an error, or it may indicate that
+    the entitlement is simply not present.  In the latter case, no CFError is
+    returned.
+*/
+CFTypeRef SecTaskCopyValueForEntitlement(SecTaskRef task, CFStringRef entitlement, CFErrorRef *error);
+
+/*!
+    @function SecTaskCopyValuesForEntitlements
+    @abstract Returns the values of multiple entitlements for the represented 
+    task.
+    @param task A previously created SecTask object
+    @param entitlements An array of entitlement names to be fetched
+    @param error On a NULL return, this will contain a CFError describing
+    the problem.  This argument may be NULL if the caller is not interested in
+    detailed errors.  If a requested entitlement is not present for the 
+    returned dictionary, the entitlement is not set on the task.  The caller
+    must CFRelease the returned value
+*/
+CFDictionaryRef SecTaskCopyValuesForEntitlements(SecTaskRef task, CFArrayRef entitlements, CFErrorRef *error);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* !_SECURITY_SECTASK_H_ */
index 441cfd44716c0cdeb43a3c845a2d66d3f98bc8e6..6b33bf60e15272d62f162d195e42af7d8a24f397 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -31,6 +31,8 @@
 #include "sigblob.h"
 #include "resources.h"
 #include "renum.h"
+#include "detachedrep.h"
+#include "csdatabase.h"
 #include "csutilities.h"
 #include <CoreFoundation/CFURLAccess.h>
 #include <Security/SecPolicyPriv.h>
@@ -41,7 +43,7 @@
 #include <Security/SecCmsSignerInfo.h>
 #include <Security/SecCmsSignedData.h>
 #include <security_utilities/unix++.h>
-#include <security_codesigning/cfmunge.h>
+#include <security_utilities/cfmunge.h>
 #include <Security/CMSDecoder.h>
 
 
@@ -51,42 +53,6 @@ namespace CodeSigning {
 using namespace UnixPlusPlus;
 
 
-//
-// We use a DetachedRep to interpose (filter) the genuine DiskRep representing
-// the code on disk, *if* a detached signature was set on this object. In this
-// situation, mRep will point to a (2 element) chain of DiskReps.
-//
-// This is a neat way of dealing with the (unusual) detached-signature case
-// without disturbing things unduly. Consider DetachedDiskRep to be closely
-// married to SecStaticCode; it's unlikely to work right if you use it elsewhere.
-//
-class DetachedRep : public DiskRep {
-public:
-       DetachedRep(CFDataRef sig, DiskRep *orig);
-       
-       const RefPointer<DiskRep> original;             // underlying representation
-       
-       DiskRep *base()                                                 { return original; }
-       CFDataRef component(CodeDirectory::SpecialSlot slot);
-       std::string mainExecutablePath()                { return original->mainExecutablePath(); }
-       CFURLRef canonicalPath()                                { return original->canonicalPath(); }
-       std::string recommendedIdentifier()             { return original->recommendedIdentifier(); }
-       std::string resourcesRootPath()                 { return original->resourcesRootPath(); }
-       CFDictionaryRef defaultResourceRules()  { return original->defaultResourceRules(); }
-       Universal *mainExecutableImage()                { return original->mainExecutableImage(); }
-       size_t signingBase()                                    { return original->signingBase(); }
-       size_t signingLimit()                                   { return original->signingLimit(); }
-       std::string format()                                    { return original->format(); }
-       FileDesc &fd()                                                  { return original->fd(); }
-       void flush()                                                    { return original->flush(); }
-
-private:
-       CFCopyRef<CFDataRef> mSignature;
-       const EmbeddedSignatureBlob *mArch;             // current architecture; points into mSignature
-       const EmbeddedSignatureBlob *mGlobal;   // shared elements; points into mSignature
-};
-
-
 //
 // Construct a SecStaticCode object given a disk representation object
 //
@@ -95,6 +61,8 @@ SecStaticCode::SecStaticCode(DiskRep *rep)
          mValidated(false), mExecutableValidated(false),
          mDesignatedReq(NULL), mGotResourceBase(false), mEvalDetails(NULL)
 {
+       CODESIGN_STATIC_CREATE(this, rep);
+       checkForSystemSignature();
 }
 
 
@@ -102,8 +70,34 @@ SecStaticCode::SecStaticCode(DiskRep *rep)
 // Clean up a SecStaticCode object
 //
 SecStaticCode::~SecStaticCode() throw()
-{
+try {
        ::free(const_cast<Requirement *>(mDesignatedReq));
+} catch (...) {
+       return;
+}
+
+
+//
+// CF-level comparison of SecStaticCode objects compares CodeDirectory hashes if signed,
+// and falls back on comparing canonical paths if (both are) not.
+//
+bool SecStaticCode::equal(SecCFObject &secOther)
+{
+       SecStaticCode *other = static_cast<SecStaticCode *>(&secOther);
+       CFDataRef mine = this->cdHash();
+       CFDataRef his = other->cdHash();
+       if (mine || his)
+               return mine && his && CFEqual(mine, his);
+       else
+               return CFEqual(this->canonicalPath(), other->canonicalPath());
+}
+
+CFHashCode SecStaticCode::hash()
+{
+       if (CFDataRef h = this->cdHash())
+               return CFHash(h);
+       else
+               return CFHash(this->canonicalPath());
 }
 
 
@@ -112,10 +106,44 @@ SecStaticCode::~SecStaticCode() throw()
 //
 void SecStaticCode::detachedSignature(CFDataRef sigData)
 {
-       if (sigData)
-               mRep = new DetachedRep(sigData, mRep->base());
-       else
+       if (sigData) {
+               mRep = new DetachedRep(sigData, mRep->base(), "explicit detached");
+               CODESIGN_STATIC_ATTACH_EXPLICIT(this, mRep);
+       } else {
                mRep = mRep->base();
+               CODESIGN_STATIC_ATTACH_EXPLICIT(this, NULL);
+       }
+}
+
+
+//
+// Consult the system detached signature database to see if it contains
+// a detached signature for this StaticCode. If it does, fetch and attach it.
+// We do this only if the code has no signature already attached.
+//
+void SecStaticCode::checkForSystemSignature()
+{
+       if (!this->isSigned())
+               try {
+                       if (RefPointer<DiskRep> dsig = signatureDatabase().findCode(mRep)) {
+                               CODESIGN_STATIC_ATTACH_SYSTEM(this, dsig);
+                               mRep = dsig;
+                       }
+               } catch (...) {
+               }
+}
+
+
+//
+// Return a descriptive string identifying the source of the code signature
+//
+string SecStaticCode::signatureSource()
+{
+       if (!isSigned())
+               return "unsigned";
+       if (DetachedRep *rep = dynamic_cast<DetachedRep *>(mRep.get()))
+               return rep->source();
+       return "embedded";
 }
 
 
@@ -155,7 +183,7 @@ SecCode *SecStaticCode::optionalDynamic(SecStaticCodeRef ref)
 //
 void SecStaticCode::resetValidity()
 {
-       secdebug("staticCode", "%p resetting validity status", this);
+       CODESIGN_EVAL_STATIC_RESET(this);
        mValidated = false;
        mExecutableValidated = false;
        mDir = NULL;
@@ -166,10 +194,14 @@ void SecStaticCode::resetValidity()
        mEntitlements = NULL;
        mResourceDict = NULL;
        mDesignatedReq = NULL;
+       mGotResourceBase = false;
        mTrust = NULL;
        mCertChain = NULL;
        mEvalDetails = NULL;
        mRep->flush();
+       
+       // we may just have updated the system database, so check again
+       checkForSystemSignature();
 }
 
 
@@ -179,7 +211,7 @@ void SecStaticCode::resetValidity()
 // Otherwise, retrieve the component without validation (but cache it). Validation
 // will go through the cache and validate all cached components.
 //
-CFDataRef SecStaticCode::component(CodeDirectory::SpecialSlot slot)
+CFDataRef SecStaticCode::component(CodeDirectory::SpecialSlot slot, OSStatus fail /* = errSecCSSignatureFailed */)
 {
        assert(slot <= cdSlotMax);
        
@@ -189,12 +221,12 @@ CFDataRef SecStaticCode::component(CodeDirectory::SpecialSlot slot)
                        if (validated()) // if the directory has been validated...
                                if (!codeDirectory()->validateSlot(CFDataGetBytePtr(data), // ... and it's no good
                                                CFDataGetLength(data), -slot))
-                                       MacOSError::throwMe(errSecCSSignatureFailed); // ... then bail
+                                       MacOSError::throwMe(fail); // ... then bail
                        cache = data;   // it's okay, cache it
                } else {        // absent, mark so
                        if (validated())        // if directory has been validated...
                                if (codeDirectory()->slotIsPresent(-slot)) // ... and the slot is NOT missing
-                                       MacOSError::throwMe(errSecCSSignatureFailed);   // was supposed to be there
+                                       MacOSError::throwMe(fail);      // was supposed to be there
                        cache = CFDataRef(kCFNull);             // white lie
                }
        }
@@ -213,7 +245,7 @@ const CodeDirectory *SecStaticCode::codeDirectory(bool check /* = true */)
        if (!mDir) {
                if (mDir.take(mRep->codeDirectory())) {
                        const CodeDirectory *dir = reinterpret_cast<const CodeDirectory *>(CFDataGetBytePtr(mDir));
-                       dir->checkVersion();
+                       dir->checkIntegrity();
                }
        }
        if (mDir)
@@ -224,6 +256,26 @@ const CodeDirectory *SecStaticCode::codeDirectory(bool check /* = true */)
 }
 
 
+//
+// Get the hash of the CodeDirectory.
+// Returns NULL if there is none.
+//
+CFDataRef SecStaticCode::cdHash()
+{
+       if (!mCDHash) {
+               if (const CodeDirectory *cd = codeDirectory(false)) {
+                       SHA1 hash;
+                       hash(cd, cd->length());
+                       SHA1::Digest digest;
+                       hash.finish(digest);
+                       mCDHash.take(makeCFData(digest, sizeof(digest)));
+                       CODESIGN_STATIC_CDHASH(this, digest, sizeof(digest));
+               }
+       }
+       return mCDHash;
+}
+
+
 //
 // Return the CMS signature blob; NULL if none found.
 //
@@ -248,11 +300,13 @@ void SecStaticCode::validateDirectory()
        if (!validated())
                try {
                        // perform validation (or die trying)
-                       secdebug("staticCode", "%p validating directory", this);
+                       CODESIGN_EVAL_STATIC_DIRECTORY(this);
                        mValidationExpired = verifySignature();
-                       component(cdInfoSlot);          // force load of Info Dictionary (if any)
-                       for (CodeDirectory::SpecialSlot slot = codeDirectory()->nSpecialSlots;
-                                       slot >= 1; --slot)
+                       component(cdInfoSlot, errSecCSInfoPlistFailed); // force load of Info Dictionary (if any)
+                       CodeDirectory::SpecialSlot slot = codeDirectory()->nSpecialSlots;
+                       if (slot > cdSlotMax)   // might have more special slots than we know about...
+                               slot = cdSlotMax;       // ... but only process the ones we understand
+                       for ( ; slot >= 1; --slot)
                                if (mCache[slot])       // if we already loaded that resource...
                                        validateComponent(slot); // ... then check it now
                        mValidated = true;                      // we've done the deed...
@@ -298,17 +352,19 @@ CFAbsoluteTime SecStaticCode::signingTime()
 // This performs the cryptographic tango. It returns if the signature is valid,
 // or throws if it is not. As a side effect, a successful return sets up the
 // cached certificate chain for future use.
+// Returns true if the signature is expired (the X.509 sense), false if it's not.
 //
 bool SecStaticCode::verifySignature()
 {
        // ad-hoc signed code is considered validly signed by definition
        if (flag(kSecCodeSignatureAdhoc)) {
-               secdebug("staticCode", "%p considered verified since it is ad-hoc", this);
+               CODESIGN_EVAL_STATIC_SIGNATURE_ADHOC(this);
                return false;
        }
+       
+       DTRACK(CODESIGN_EVAL_STATIC_SIGNATURE, this, (char*)this->mainExecutablePath().c_str());
 
        // decode CMS and extract SecTrust for verification
-       secdebug("staticCode", "%p verifying signature", this);
        CFRef<CMSDecoderRef> cms;
        MacOSError::check(CMSDecoderCreate(&cms.aref())); // create decoder
        CFDataRef sig = this->signature();
@@ -350,7 +406,7 @@ bool SecStaticCode::verifySignature()
                CSSM_TP_ACTION_IMPLICIT_ANCHORS // action flags
        };
        
-       for (;;) {
+       for (;;) {      // at most twice
                MacOSError::check(SecTrustSetParameters(mTrust,
                        CSSM_TP_ACTION_DEFAULT, CFTempData(&actionData, sizeof(actionData))));
        
@@ -358,8 +414,7 @@ bool SecStaticCode::verifySignature()
                SecTrustResultType trustResult;
                MacOSError::check(SecTrustEvaluate(mTrust, &trustResult));
                MacOSError::check(SecTrustGetResult(mTrust, &trustResult, &mCertChain.aref(), &mEvalDetails));
-               secdebug("staticCode", "%p verification result=%d chain=%ld",
-                       this, trustResult, mCertChain ? CFArrayGetCount(mCertChain) : -1);
+               CODESIGN_EVAL_STATIC_SIGNATURE_RESULT(this, trustResult, mCertChain ? CFArrayGetCount(mCertChain) : 0);
                switch (trustResult) {
                case kSecTrustResultProceed:
                case kSecTrustResultConfirm:
@@ -376,9 +431,10 @@ bool SecStaticCode::verifySignature()
                        {
                                OSStatus result;
                                MacOSError::check(SecTrustGetCssmResultCode(mTrust, &result));
-                               if (result == CSSMERR_TP_CERT_EXPIRED && !(actionData.ActionFlags & CSSM_TP_ACTION_ALLOW_EXPIRED)) {
-                                       secdebug("staticCode", "expired certificate(s); retrying validation");
-                                       actionData.ActionFlags |= CSSM_TP_ACTION_ALLOW_EXPIRED;
+                               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
                                }
                                MacOSError::throwMe(result);
@@ -407,16 +463,17 @@ SecPolicyRef SecStaticCode::verificationPolicy()
 // The resource must already have been placed in the cache.
 // This does NOT perform basic validation.
 //
-void SecStaticCode::validateComponent(CodeDirectory::SpecialSlot slot)
+void SecStaticCode::validateComponent(CodeDirectory::SpecialSlot slot, OSStatus fail /* = errSecCSSignatureFailed */)
 {
+       assert(slot <= cdSlotMax);
        CFDataRef data = mCache[slot];
        assert(data);           // must be cached
        if (data == CFDataRef(kCFNull)) {
                if (codeDirectory()->slotIsPresent(-slot)) // was supposed to be there...
-                               MacOSError::throwMe(errSecCSSignatureFailed);   // ... and is missing
+                               MacOSError::throwMe(fail);      // ... and is missing
        } else {
                if (!codeDirectory()->validateSlot(CFDataGetBytePtr(data), CFDataGetLength(data), -slot))
-                       MacOSError::throwMe(errSecCSSignatureFailed);
+                       MacOSError::throwMe(fail);
        }
 }
 
@@ -430,8 +487,8 @@ void SecStaticCode::validateComponent(CodeDirectory::SpecialSlot slot)
 //
 void SecStaticCode::validateExecutable()
 {
-       secdebug("staticCode", "%p performing static main exec validate of %s",
-               this, mainExecutablePath().c_str());
+       DTRACK(CODESIGN_EVAL_STATIC_EXECUTABLE, this,
+               (char*)this->mainExecutablePath().c_str(), codeDirectory()->nCodeSlots);
        const CodeDirectory *cd = this->codeDirectory();
        if (!cd)
                MacOSError::throwMe(errSecCSUnsigned);
@@ -444,15 +501,13 @@ void SecStaticCode::validateExecutable()
        for (size_t slot = 0; slot < cd->nCodeSlots; ++slot) {
                size_t size = min(remaining, pageSize);
                if (!cd->validateSlot(fd, size, slot)) {
-                       secdebug("staticCode", "%p failed static validation of code page %zd", this, slot);
+                       CODESIGN_EVAL_STATIC_EXECUTABLE_FAIL(this, slot);
                        mExecutableValidated = true;    // we tried
                        mExecutableValid = false;               // it failed
                        MacOSError::throwMe(errSecCSSignatureFailed);
                }
                remaining -= size;
        }
-       secdebug("staticCode", "%p validated full executable (%d pages)",
-               this, int(cd->nCodeSlots));
        mExecutableValidated = true;    // we tried
        mExecutableValid = true;                // it worked
 }
@@ -483,27 +538,22 @@ void SecStaticCode::validateResources()
        // found resources, and they are sealed
        CFDictionaryRef rules = cfget<CFDictionaryRef>(sealedResources, "rules");
        CFDictionaryRef files = cfget<CFDictionaryRef>(sealedResources, "files");
-       secdebug("staticCode", "%p verifying %d sealed resources",
-               this, int(CFDictionaryGetCount(files)));
+       DTRACK(CODESIGN_EVAL_STATIC_RESOURCES, this,
+               (char*)this->mainExecutablePath().c_str(), int(CFDictionaryGetCount(files)));
 
        // make a shallow copy of the ResourceDirectory so we can "check off" what we find
-       CFRef<CFMutableDictionaryRef> resourceMap = CFDictionaryCreateMutableCopy(NULL,
-               CFDictionaryGetCount(files), files);
-       if (!resourceMap)
-               CFError::throwMe();
+       CFRef<CFMutableDictionaryRef> resourceMap = makeCFMutableDictionary(files);
 
        // scan through the resources on disk, checking each against the resourceDirectory
        CollectingContext ctx(*this);           // collect all failures in here
-       ResourceBuilder resources(cfString(this->resourceBase()), rules);
+       ResourceBuilder resources(cfString(this->resourceBase()), rules, codeDirectory()->hashType);
        mRep->adjustResources(resources);
        string path;
        ResourceBuilder::Rule *rule;
 
        while (resources.next(path, rule)) {
-               if (CFDataRef value = resource(path, ctx))
-                       CFRelease(value);
+               validateResource(path, ctx);
                CFDictionaryRemoveValue(resourceMap, CFTempString(path));
-               secdebug("staticCode", "%p validated %s", this, path.c_str());
        }
        
        if (CFDictionaryGetCount(resourceMap) > 0) {
@@ -514,8 +564,6 @@ void SecStaticCode::validateResources()
        // now check for any errors found in the reporting context
        if (ctx)
                ctx.throwMe();
-
-       secdebug("staticCode", "%p sealed resources okay", this);
 }
 
 
@@ -538,7 +586,7 @@ void SecStaticCode::checkOptionalResource(CFTypeRef key, CFTypeRef value, void *
 CFDictionaryRef SecStaticCode::infoDictionary()
 {
        if (!mInfoDict) {
-               mInfoDict.take(getDictionary(cdInfoSlot));
+               mInfoDict.take(getDictionary(cdInfoSlot, errSecCSInfoPlistFailed));
                secdebug("staticCode", "%p loaded InfoDict %p", this, mInfoDict.get());
        }
        return mInfoDict;
@@ -565,7 +613,7 @@ CFDictionaryRef SecStaticCode::resourceDictionary()
 {
        if (mResourceDict)      // cached
                return mResourceDict;
-       if (CFRef<CFDictionaryRef> dict = getDictionary(cdResourceDirSlot))
+       if (CFRef<CFDictionaryRef> dict = getDictionary(cdResourceDirSlot, errSecCSSignatureFailed))
                if (cfscan(dict, "{rules=%Dn,files=%Dn}")) {
                        secdebug("staticCode", "%p loaded ResourceDict %p",
                                this, mResourceDict.get());
@@ -597,11 +645,11 @@ CFURLRef SecStaticCode::resourceBase()
 // This will force load and validation, which means that it will perform basic
 // validation if it hasn't been done yet.
 //
-CFDictionaryRef SecStaticCode::getDictionary(CodeDirectory::SpecialSlot slot)
+CFDictionaryRef SecStaticCode::getDictionary(CodeDirectory::SpecialSlot slot, OSStatus fail /* = errSecCSSignatureFailed */)
 {
        validateDirectory();
-       if (CFDataRef infoData = component(slot)) {
-               validateComponent(slot);
+       if (CFDataRef infoData = component(slot, fail)) {
+               validateComponent(slot, fail);
                if (CFDictionaryRef dict = makeCFDictionaryFrom(infoData))
                        return dict;
                else
@@ -636,9 +684,9 @@ CFDataRef SecStaticCode::resource(string path, ValidationContext &ctx)
                                MacOSError::throwMe(errSecCSResourcesNotFound);
                        CFRef<CFURLRef> fullpath = makeCFURL(path, false, resourceBase());
                        if (CFRef<CFDataRef> data = cfLoadFile(fullpath)) {
-                               SHA1 hasher;
-                               hasher(CFDataGetBytePtr(data), CFDataGetLength(data));
-                               if (hasher.verify(seal.hash()))
+                               MakeHash<CodeDirectory> hasher(this->codeDirectory());
+                               hasher->update(CFDataGetBytePtr(data), CFDataGetLength(data));
+                               if (hasher->verify(seal.hash()))
                                        return data.yield();    // good
                                else
                                        ctx.reportProblem(errSecCSBadResource, kSecCFErrorResourceAltered, fullpath); // altered
@@ -662,6 +710,35 @@ CFDataRef SecStaticCode::resource(string path)
 }
 
 
+void SecStaticCode::validateResource(string path, ValidationContext &ctx)
+{
+       if (CFDictionaryRef rdict = resourceDictionary()) {
+               if (CFTypeRef file = cfget(rdict, "files.%s", path.c_str())) {
+                       ResourceSeal seal = file;
+                       if (!resourceBase())    // no resources in DiskRep
+                               MacOSError::throwMe(errSecCSResourcesNotFound);
+                       CFRef<CFURLRef> fullpath = makeCFURL(path, false, resourceBase());
+                       AutoFileDesc fd(cfString(fullpath), O_RDONLY, FileDesc::modeMissingOk); // open optional filee
+                       if (fd) {
+                               MakeHash<CodeDirectory> hasher(this->codeDirectory());
+                               hashFileData(fd, hasher.get());
+                               if (hasher->verify(seal.hash()))
+                                       return;                 // verify good
+                               else
+                                       ctx.reportProblem(errSecCSBadResource, kSecCFErrorResourceAltered, fullpath); // altered
+                       } else {
+                               if (!seal.optional())
+                                       ctx.reportProblem(errSecCSBadResource, kSecCFErrorResourceMissing, fullpath); // was sealed but is now missing
+                               else
+                                       return;                 // validly missing
+                       }
+               } else
+                       ctx.reportProblem(errSecCSBadResource, kSecCFErrorResourceAdded, CFTempURL(path, false, resourceBase()));
+       } else
+               MacOSError::throwMe(errSecCSResourcesNotSealed);
+}
+
+
 //
 // Test a CodeDirectory flag.
 // Returns false if there is no CodeDirectory.
@@ -801,7 +878,6 @@ bool SecStaticCode::isAppleSDKSignature()
        return false;
 }
 
-
 void SecStaticCode::defaultDesignatedNonAppleAnchor(Requirement::Maker &maker)
 {
        // get the Organization DN element for the leaf
@@ -815,14 +891,14 @@ void SecStaticCode::defaultDesignatedNonAppleAnchor(Requirement::Maker &maker)
                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 (CFStringCompare(leafOrganization, caOrganization, 0) != kCFCompareEqualTo)
+                       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);
@@ -836,28 +912,30 @@ void SecStaticCode::defaultDesignatedNonAppleAnchor(Requirement::Maker &maker)
 void SecStaticCode::validateRequirements(SecRequirementType type, SecStaticCode *target,
        OSStatus nullError /* = noErr */)
 {
-       secdebug("staticCode", "%p validating %s requirements for %p",
-               this, Requirement::typeNames[type], target);
+       DTRACK(CODESIGN_EVAL_STATIC_INTREQ, this, type, target, nullError);
        if (const Requirement *req = internalRequirement(type))
-               target->validateRequirements(req, nullError ? nullError : errSecCSReqFailed);
-       else if (nullError) {
-               secdebug("staticCode", "%p NULL validate for %s prohibited",
-                       this, Requirement::typeNames[type]);
+               target->validateRequirement(req, nullError ? nullError : errSecCSReqFailed);
+       else if (nullError)
                MacOSError::throwMe(nullError);
-       } else
-               secdebug("staticCode", "%p NULL validate (no requirements for %s)",
-                       this, Requirement::typeNames[type]);
+       else
+               /* accept it */;
 }
 
 
 //
 // Validate this StaticCode against an external Requirement
 //
-void SecStaticCode::validateRequirements(const Requirement *req, OSStatus failure)
+bool SecStaticCode::satisfiesRequirement(const Requirement *req, OSStatus failure)
 {
        assert(req);
        validateDirectory();
-       req->validate(Requirement::Context(mCertChain, infoDictionary(), entitlements(), codeDirectory()), failure);
+       return req->validates(Requirement::Context(mCertChain, infoDictionary(), entitlements(), codeDirectory()), failure);
+}
+
+void SecStaticCode::validateRequirement(const Requirement *req, OSStatus failure)
+{
+       if (!this->satisfiesRequirement(req, failure))
+               MacOSError::throwMe(failure);
 }
 
 
@@ -867,7 +945,7 @@ void SecStaticCode::validateRequirements(const Requirement *req, OSStatus failur
 //    [ leaf, intermed-1, ..., intermed-n, anchor ]
 //        0       1       ...     -2         -1
 // Returns NULL if unavailable for any reason.
-//     
+//
 SecCertificateRef SecStaticCode::cert(int ix)
 {
        validateDirectory();            // need cert chain
@@ -889,7 +967,7 @@ CFArrayRef SecStaticCode::certificates()
 
 
 //
-// Gather API-official information about this StaticCode.
+// Gather (mostly) API-official information about this StaticCode.
 //
 // This method lives in the twilight between the API and internal layers,
 // since it generates API objects (Sec*Refs) for return.
@@ -911,26 +989,28 @@ CFDictionaryRef SecStaticCode::signingInformation(SecCSFlags flags)
        if (!this->isSigned())
                return dict.yield();
        
-
        //
-       // Now add the generic attributes that we always include
+       // Add the generic attributes that we always include
        //
        CFDictionaryAddValue(dict, kSecCodeInfoIdentifier, CFTempString(this->identifier()));
        CFDictionaryAddValue(dict, kSecCodeInfoFormat, CFTempString(this->format()));
-       if (CFDictionaryRef info = infoDictionary())
+       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));
 
        //
        // kSecCSSigningInformation adds information about signing certificates and chains
        //
        if (flags & kSecCSSigningInformation) {
-               if (CFArrayRef certs = certificates())
+               if (CFArrayRef certs = this->certificates())
                CFDictionaryAddValue(dict, kSecCodeInfoCertificates, certs);
-               if (CFDataRef sig = signature())
+               if (CFDataRef sig = this->signature())
                        CFDictionaryAddValue(dict, kSecCodeInfoCMS, sig);
                if (mTrust)
                        CFDictionaryAddValue(dict, kSecCodeInfoTrust, mTrust);
-               if (CFAbsoluteTime time = signingTime())
+               if (CFAbsoluteTime time = this->signingTime())
                        if (CFRef<CFDateRef> date = CFDateCreate(NULL, time))
                                CFDictionaryAddValue(dict, kSecCodeInfoTime, date);
        }
@@ -939,25 +1019,24 @@ CFDictionaryRef SecStaticCode::signingInformation(SecCSFlags flags)
        // kSecCSRequirementInformation adds information on requirements
        //
        if (flags & kSecCSRequirementInformation) {
-               if (const Requirements *reqs = internalRequirements()) {
+               if (const Requirements *reqs = this->internalRequirements()) {
                        CFDictionaryAddValue(dict, kSecCodeInfoRequirements,
                                CFTempString(Dumper::dump(reqs)));
                        CFDictionaryAddValue(dict, kSecCodeInfoRequirementData, CFTempData(*reqs));
                }
-               const Requirement *dreq = designatedRequirement();
-               const Requirement *ddreq = defaultDesignatedRequirement();
-               CFRef<SecRequirementRef> ddreqRef = (new SecRequirement(ddreq))->handle();
-               if (dreq == ddreq) {
-                       CFDictionaryAddValue(dict, kSecCodeInfoDesignatedRequirement, ddreqRef);
-                       CFDictionaryAddValue(dict, kSecCodeInfoImplicitDesignatedRequirement, ddreqRef);
-               } else {
-                       CFDictionaryAddValue(dict, kSecCodeInfoDesignatedRequirement,
-                               CFRef<SecRequirementRef>((new SecRequirement(dreq))->handle()));
+               
+               const Requirement *dreq = this->designatedRequirement();
+               CFRef<SecRequirementRef> dreqRef = (new SecRequirement(dreq))->handle();
+               CFDictionaryAddValue(dict, kSecCodeInfoDesignatedRequirement, dreqRef);
+               if (this->internalRequirement(kSecDesignatedRequirementType)) { // explicit
+                       CFRef<SecRequirementRef> ddreqRef = (new SecRequirement(this->defaultDesignatedRequirement(), true))->handle();
                        CFDictionaryAddValue(dict, kSecCodeInfoImplicitDesignatedRequirement, ddreqRef);
+               } else {        // implicit
+                       CFDictionaryAddValue(dict, kSecCodeInfoImplicitDesignatedRequirement, dreqRef);
                }
                
-               if (CFDataRef ent = component(cdEntitlementSlot))
-                       CFDictionaryAddValue(dict, kSecCodeInfoEntitlements, ent);
+          if (CFDataRef ent = this->component(cdEntitlementSlot))
+                  CFDictionaryAddValue(dict, kSecCodeInfoEntitlements, ent);
        }
        
        //
@@ -968,10 +1047,10 @@ CFDictionaryRef SecStaticCode::signingInformation(SecCSFlags flags)
        //
        if (flags & kSecCSInternalInformation) {
                if (mDir)
-                       CFDictionaryAddValue(dict, CFSTR("CodeDirectory"), mDir);
-               CFDictionaryAddValue(dict, CFSTR("CodeOffset"), CFTempNumber(mRep->signingBase()));
+                       CFDictionaryAddValue(dict, kSecCodeInfoCodeDirectory, mDir);
+               CFDictionaryAddValue(dict, kSecCodeInfoCodeOffset, CFTempNumber(mRep->signingBase()));
                if (CFDictionaryRef resources = resourceDictionary())
-                       CFDictionaryAddValue(dict, CFSTR("ResourceDirectory"), resources);
+                       CFDictionaryAddValue(dict, kSecCodeInfoResourceDirectory, resources);
        }
        
        
@@ -1006,7 +1085,7 @@ void SecStaticCode::CollectingContext::reportProblem(OSStatus rc, CFStringRef ty
                mStatus = rc;                   // record first failure for eventual error return
        if (type) {
                if (!mCollection)
-                       mCollection.take(makeCFMutableDictionary(0));
+                       mCollection.take(makeCFMutableDictionary());
                CFMutableArrayRef element = CFMutableArrayRef(CFDictionaryGetValue(mCollection, type));
                if (!element) {
                        element = makeCFMutableArray(0);
@@ -1027,41 +1106,54 @@ void SecStaticCode::CollectingContext::throwMe()
 
 
 //
-// DetachedRep construction
+// SecStaticCode::AllArchitectures produces SecStaticCode objects separately
+// for each architecture represented by a base object.
+//
+// Performance note: This is a simple, straight-forward implementation that
+// does not heroically try to share resources between the code objects produced.
+// In practice, this means we'll re-open files and re-read resource files.
+// In exchange, we enter all the code paths in the normal way, and do not have
+// special sharing paths to worry about.
+// If a performance tool brings you here because you have *proof* of a performance
+// problem, consider digging up MachO and Universal (for sharing file descriptors),
+// and SecStaticCode (for sharing resource iterators). That ought to cover most of
+// the big chunks. If you're just offended by the simplicity of this implementation,
+// go play somewhere else.
 //
-DetachedRep::DetachedRep(CFDataRef sig, DiskRep *orig)
-       : original(orig), mSignature(sig)
+SecStaticCode::AllArchitectures::AllArchitectures(SecStaticCode *code)
+       : mBase(code)
 {
-       const BlobCore *sigBlob = reinterpret_cast<const BlobCore *>(CFDataGetBytePtr(sig));
-       if (sigBlob->is<EmbeddedSignatureBlob>()) {             // architecture-less
-               mArch = EmbeddedSignatureBlob::specific(sigBlob);
-               mGlobal = NULL;
-               return;
-       } else if (sigBlob->is<DetachedSignatureBlob>()) {      // architecture collection
-               const DetachedSignatureBlob *dsblob = DetachedSignatureBlob::specific(sigBlob);
-               if (Universal *fat = orig->mainExecutableImage()) {
-                       if (const BlobCore *blob = dsblob->find(fat->bestNativeArch().cpuType())) {
-                               mArch = EmbeddedSignatureBlob::specific(blob);
-                               mGlobal = EmbeddedSignatureBlob::specific(dsblob->find(0));
-                               return;
-                       } else
-                               secdebug("staticcode", "detached signature missing architecture %s",
-                                       fat->bestNativeArch().name());
-               } else
-                       secdebug("staticcode", "detached signature requires Mach-O binary");
-       } else
-               secdebug("staticcode", "detached signature bad magic 0x%x", sigBlob->magic());
-       MacOSError::throwMe(errSecCSSignatureInvalid);
+       if (Universal *fat = code->diskRep()->mainExecutableImage()) {
+               fat->architectures(mArchitectures);
+               mCurrent = mArchitectures.begin();
+               mState = fatBinary;
+       } else {
+               mState = firstNonFat;
+       }
 }
 
-CFDataRef DetachedRep::component(CodeDirectory::SpecialSlot slot)
+SecStaticCode *SecStaticCode::AllArchitectures::operator () ()
 {
-       if (CFDataRef result = mArch->component(slot))
-               return result;
-       if (mGlobal)
-               if (CFDataRef result = mGlobal->component(slot))
-                       return result;
-       return original->component(slot);
+       switch (mState) {
+       case firstNonFat:
+               mState = atEnd;
+               return mBase;
+       case fatBinary:
+               {
+                       if (mCurrent == mArchitectures.end())
+                               return NULL;
+                       Architecture arch = *mCurrent++;
+                       if (arch == mBase->diskRep()->mainExecutableImage()->bestNativeArch()) {
+                               return mBase;
+                       } else {
+                               DiskRep::Context ctx;
+                               ctx.arch = arch;
+                               return new SecStaticCode(DiskRep::bestGuess(mBase->mainExecutablePath(), &ctx));
+                       }
+               }
+       default:
+               return NULL;
+       }
 }
 
 
index 7aed254ac86396caa678fcc85ee3a485de64076a..8350ddbe7dac13b4efb448c189f441eb142db09e 100644 (file)
@@ -49,18 +49,32 @@ class SecCode;
 //
 // Note that concrete knowledge of where stuff is stored resides in the DiskRep
 // object we hold. DiskReps allocate, retrieve, and return data to us. We are
-// responsible for interpreting, caching, and validating them.
+// responsible for interpreting, caching, and validating them. (In other words,
+// DiskReps know where stuff is and how it is stored, but we know what it means.)
+//
+// Data accessors (returning CFDataRef, CFDictionaryRef, various pointers, etc.)
+// cache those values internally and return unretained(!) references ("Get" style)
+// that are valid as long as the SecStaticCode object's lifetime, or until
+// resetValidity() is called, whichever is sooner. If you need to keep them,
+// retain or copy them as needed.
 //
 class SecStaticCode : public SecCFObject {
        NOCOPY(SecStaticCode)
        
 protected:
+       //
+       // A context for resource validation operations, to tailor error response.
+       // The base class throws an exception immediately and ignores detail data.
+       // 
        class ValidationContext {
        public:
                virtual ~ValidationContext();
                virtual void reportProblem(OSStatus rc, CFStringRef type, CFTypeRef value);
        };
        
+       //
+       // A CollectingContext collects all error details and throws an annotated final error.
+       //
        class CollectingContext : public ValidationContext {
        public:
                CollectingContext(SecStaticCode &c) : code(c), mStatus(noErr) { }
@@ -87,9 +101,14 @@ public:
        SecStaticCode(DiskRep *rep);
     virtual ~SecStaticCode() throw();
        
-       void detachedSignature(CFDataRef sig);
+    bool equal(SecCFObject &other);
+    CFHashCode hash();
+       
+       void detachedSignature(CFDataRef sig);          // attach an explicitly given detached signature
+       void checkForSystemSignature();                         // check for and attach system-supplied detached signature
 
        const CodeDirectory *codeDirectory(bool check = true);
+       CFDataRef cdHash();
        CFDataRef signature();
        CFAbsoluteTime signingTime();
        bool isSigned() { return codeDirectory(false) != NULL; }
@@ -98,7 +117,8 @@ public:
        CFURLRef canonicalPath() const { return mRep->canonicalPath(); }
        std::string identifier() { return codeDirectory()->identifier(); }
        std::string format() const { return mRep->format(); }
-       CFDataRef component(CodeDirectory::SpecialSlot slot);
+       std::string signatureSource();
+       CFDataRef component(CodeDirectory::SpecialSlot slot, OSStatus fail = errSecCSSignatureFailed);
        CFDictionaryRef infoDictionary();
        CFDictionaryRef entitlements();
 
@@ -106,36 +126,42 @@ public:
        CFURLRef resourceBase();
        CFDataRef resource(std::string path);
        CFDataRef resource(std::string path, ValidationContext &ctx);
+       void validateResource(std::string path, ValidationContext &ctx);
        
        bool flag(uint32_t tested);
        
-       void resetValidity();
+       void resetValidity();                                           // clear validation caches (if something may have changed)
        
        bool validated() const  { return mValidated; }
        bool valid() const
                { assert(validated()); return mValidated && (mValidationResult == noErr); }
        
        void validateDirectory();
-       void validateComponent(CodeDirectory::SpecialSlot slot);
+       void validateComponent(CodeDirectory::SpecialSlot slot, OSStatus fail = errSecCSSignatureFailed);
        void validateResources();
        void validateExecutable();
        
        const Requirements *internalRequirements();
        const Requirement *internalRequirement(SecRequirementType type);
        const Requirement *designatedRequirement();
-       const Requirement *defaultDesignatedRequirement();
+       const Requirement *defaultDesignatedRequirement();              // newly allocated (caller owns)
        
        void validateRequirements(SecRequirementType type, SecStaticCode *target,
-               OSStatus nullError = noErr);
-       void validateRequirements(const Requirement *req, OSStatus failure);
+               OSStatus nullError = noErr);                                                                            // target against my [type], throws
+       void validateRequirement(const Requirement *req, OSStatus failure);             // me against [req], throws
+       bool satisfiesRequirement(const Requirement *req, OSStatus failure);    // me against [req], returns on clean miss
        
+       // certificates are available after signature validation (they are stored in the CMS signature)
        SecCertificateRef cert(int ix);         // get a cert from the cert chain
        CFArrayRef certificates();                      // get the entire certificate chain
        
-       CFDictionaryRef signingInformation(SecCSFlags flags); // information-gathering API
+       CFDictionaryRef signingInformation(SecCSFlags flags); // omnibus information-gathering API (creates new dictionary)
+       
+public:
+       class AllArchitectures;
        
 protected:
-       CFDictionaryRef getDictionary(CodeDirectory::SpecialSlot slot);
+       CFDictionaryRef getDictionary(CodeDirectory::SpecialSlot slot, OSStatus fail); // component value as a dictionary
        bool verifySignature();
        SecPolicyRef verificationPolicy();
 
@@ -168,6 +194,7 @@ private:
        CFRef<CFDictionaryRef> mEntitlements; // derived from mCache slot
        CFRef<CFDictionaryRef> mResourceDict; // derived from mCache slot
        const Requirement *mDesignatedReq;      // cached designated req if we made one up
+       CFRef<CFDataRef> mCDHash;                       // hash of CodeDirectory
        
        bool mGotResourceBase;                          // asked mRep for resourceBasePath
        CFRef<CFURLRef> mResourceBase;          // URL form of resource base directory
@@ -182,6 +209,24 @@ private:
 };
 
 
+//
+// Given a SecStaticCode, create an iterator that produces SecStaticCodes
+// for all architectures encompassed by this static code reference.
+//
+class SecStaticCode::AllArchitectures : public SecPointer<SecStaticCode> {
+public:
+       AllArchitectures(SecStaticCode *code);
+       
+       SecStaticCode *operator () ();
+       
+private:
+       SecPointer<SecStaticCode> mBase;
+       enum { fatBinary, firstNonFat, atEnd } mState;
+       Universal::Architectures mArchitectures;
+       Universal::Architectures::const_iterator mCurrent;
+};
+
+
 } // end namespace CodeSigning
 } // end namespace Security
 
index ffaa4789a94fca1b556a8eee1ae6ef8726a914a7..b7d3315d03c7c134912cdfd0e69cc1d0b2dcdb8d 100644 (file)
@@ -23,7 +23,7 @@
 #include "bundlediskrep.h"
 #include <CoreFoundation/CFURLAccess.h>
 #include <CoreFoundation/CFBundlePriv.h>
-#include <security_codesigning/cfmunge.h>
+#include <security_utilities/cfmunge.h>
 #include <copyfile.h>
 
 
@@ -36,18 +36,38 @@ using namespace UnixPlusPlus;
 //
 // We make a CFBundleRef immediately, but everything else is lazy
 //
-BundleDiskRep::BundleDiskRep(const char *path)
+BundleDiskRep::BundleDiskRep(const char *path, const Context *ctx)
        : mBundle(_CFBundleCreateIfMightBeBundle(NULL, CFTempURL(path)))
 {
        if (!mBundle)
                MacOSError::throwMe(errSecCSBadObjectFormat);
-       mExecRep = DiskRep::bestFileGuess(this->mainExecutablePath());
+       setup(ctx);
+       CODESIGN_DISKREP_CREATE_BUNDLE_PATH(this, (char*)path, (void*)ctx, mExecRep);
 }
 
-BundleDiskRep::BundleDiskRep(CFBundleRef ref)
+BundleDiskRep::BundleDiskRep(CFBundleRef ref, const Context *ctx)
 {
        mBundle = ref;          // retains
-       mExecRep = DiskRep::bestFileGuess(this->mainExecutablePath());
+       setup(ctx);
+       CODESIGN_DISKREP_CREATE_BUNDLE_REF(this, ref, (void*)ctx, mExecRep);
+}
+
+void BundleDiskRep::setup(const Context *ctx)
+{
+       string version = resourcesRootPath()
+               + "/Versions/"
+               + ((ctx && ctx->version) ? ctx->version : "Current")
+               + "/.";
+       if (::access(version.c_str(), F_OK) == 0) {             // versioned bundle
+               if (CFBundleRef versionBundle = CFBundleCreate(NULL, CFTempURL(version)))
+                       mBundle.take(versionBundle);    // replace top bundle ref
+               else
+                       MacOSError::throwMe(errSecCSStaticCodeNotFound);
+       } else {
+               if (ctx && ctx->version)        // explicitly specified
+                       MacOSError::throwMe(errSecCSStaticCodeNotFound);
+       }
+       mExecRep = DiskRep::bestFileGuess(this->mainExecutablePath(), ctx);
 }
 
 
@@ -123,30 +143,20 @@ CFDataRef BundleDiskRep::component(CodeDirectory::SpecialSlot slot)
 
 
 //
-// Various aspects of our DiskRep personality.
+// The binary identifier is taken directly from the main executable.
 //
-CFURLRef BundleDiskRep::canonicalPath()
+CFDataRef BundleDiskRep::identification()
 {
-       return CFBundleCopyBundleURL(mBundle);
+       return mExecRep->identification();
 }
 
-string BundleDiskRep::recommendedIdentifier()
+
+//
+// Various aspects of our DiskRep personality.
+//
+CFURLRef BundleDiskRep::canonicalPath()
 {
-       if (CFStringRef identifier = CFBundleGetIdentifier(mBundle))
-               return cfString(identifier);
-       if (CFDictionaryRef infoDict = CFBundleGetInfoDictionary(mBundle))
-               if (CFStringRef identifier = CFStringRef(CFDictionaryGetValue(infoDict, kCFBundleNameKey)))
-                       return cfString(identifier);
-       
-       // fall back to using the $(basename) of the canonical path. Drop any .app suffix
-       string path = cfString(this->canonicalPath(), true);
-       if (path.substr(path.size() - 4) == ".app")
-               path = path.substr(0, path.size() - 4);
-       string::size_type p = path.rfind('/');
-       if (p == string::npos)
-               return path;
-       else
-               return path.substr(p+1);
+       return CFBundleCopyBundleURL(mBundle);
 }
 
 string BundleDiskRep::mainExecutablePath()
@@ -154,7 +164,7 @@ string BundleDiskRep::mainExecutablePath()
        if (CFURLRef exec = CFBundleCopyExecutableURL(mBundle))
                return cfString(exec, true);
        else
-               MacOSError::throwMe(errSecCSBadObjectFormat);
+               MacOSError::throwMe(errSecCSNoMainExecutable);
 }
 
 string BundleDiskRep::resourcesRootPath()
@@ -162,16 +172,6 @@ string BundleDiskRep::resourcesRootPath()
        return cfString(CFBundleCopySupportFilesDirectoryURL(mBundle), true);
 }
 
-CFDictionaryRef BundleDiskRep::defaultResourceRules()
-{
-       return cfmake<CFDictionaryRef>("{rules={"
-               "'^version.plist$' = #T"
-               "'^Resources/' = #T"
-               "'^Resources/.*\\.lproj/' = {optional=#T, weight=1000}"
-               "'^Resources/.*\\.lproj/locversion.plist$' = {omit=#T, weight=1100}"
-               "}}");
-}
-
 void BundleDiskRep::adjustResources(ResourceBuilder &builder)
 {
        // exclude entire contents of meta directory
@@ -181,26 +181,17 @@ void BundleDiskRep::adjustResources(ResourceBuilder &builder)
        string resources = resourcesRootPath();
        string executable = mainExecutablePath();
        if (!executable.compare(0, resources.length(), resources, 0, resources.length()))       // is prefix
-               builder.addExclusion(string("^") + executable.substr(resources.length() + 1) + "$");
+               builder.addExclusion(string("^")
+                       + ResourceBuilder::escapeRE(executable.substr(resources.length() + 1)) + "$");
 }
 
 
-const Requirements *BundleDiskRep::defaultRequirements(const Architecture *arch)
-{
-       return mExecRep->defaultRequirements(arch);
-}
-
 
 Universal *BundleDiskRep::mainExecutableImage()
 {
        return mExecRep->mainExecutableImage();
 }
 
-size_t BundleDiskRep::pageSize()
-{
-       return mExecRep->pageSize();
-}
-
 size_t BundleDiskRep::signingBase()
 {
        return mExecRep->signingBase();
@@ -248,6 +239,42 @@ void BundleDiskRep::flush()
 }
 
 
+//
+// Defaults for signing operations
+//
+string BundleDiskRep::recommendedIdentifier(const SigningContext &)
+{
+       if (CFStringRef identifier = CFBundleGetIdentifier(mBundle))
+               return cfString(identifier);
+       if (CFDictionaryRef infoDict = CFBundleGetInfoDictionary(mBundle))
+               if (CFStringRef identifier = CFStringRef(CFDictionaryGetValue(infoDict, kCFBundleNameKey)))
+                       return cfString(identifier);
+       
+       // fall back to using the canonical path
+       return canonicalIdentifier(cfString(this->canonicalPath()));
+}
+
+CFDictionaryRef BundleDiskRep::defaultResourceRules(const SigningContext &)
+{
+       return cfmake<CFDictionaryRef>("{rules={"
+               "'^version.plist$' = #T"
+               "'^Resources/' = #T"
+               "'^Resources/.*\\.lproj/' = {optional=#T, weight=1000}"
+               "'^Resources/.*\\.lproj/locversion.plist$' = {omit=#T, weight=1100}"
+               "}}");
+}
+
+const Requirements *BundleDiskRep::defaultRequirements(const Architecture *arch, const SigningContext &ctx)
+{
+       return mExecRep->defaultRequirements(arch, ctx);
+}
+
+size_t BundleDiskRep::pageSize(const SigningContext &ctx)
+{
+       return mExecRep->pageSize(ctx);
+}
+
+
 //
 // Writers
 //
@@ -282,18 +309,39 @@ void BundleDiskRep::Writer::component(CodeDirectory::SpecialSlot slot, CFDataRef
                        string path = rep->metaPath(name);
                        AutoFileDesc fd(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
                        fd.writeAll(CFDataGetBytePtr(data), CFDataGetLength(data));
-                       if (rep->mMetaExists) {
-                               // leave a symlink in the support directory for pre-10.5.3 compatibility (but ignore errors)
-                               string legacy = cfString(CFBundleCopySupportFilesDirectoryURL(rep->mBundle), true) + "/" + name;
-//                             ::unlink(legacy.c_str());               // force-replace
-                               ::symlink((string(BUNDLEDISKREP_DIRECTORY "/") + name).c_str(), legacy.c_str());
-                       }
                } else
                        MacOSError::throwMe(errSecCSBadObjectFormat);
        }
 }
 
 
+//
+// Remove all signature data
+//
+void BundleDiskRep::Writer::remove()
+{
+       // remove signature from the executable
+       execWriter->remove();
+       
+       // remove signature files from bundle
+       for (CodeDirectory::SpecialSlot slot = 0; slot < cdSlotCount; slot++)
+               remove(slot);
+       remove(cdSignatureSlot);
+}
+
+void BundleDiskRep::Writer::remove(CodeDirectory::SpecialSlot slot)
+{
+       if (const char *name = CodeDirectory::canonicalSlotName(slot))
+               if (::unlink(rep->metaPath(name).c_str()))
+                       switch (errno) {
+                       case ENOENT:            // not found - that's okay
+                               break;
+                       default:
+                               UnixError::throwMe();
+                       }
+}
+
+
 void BundleDiskRep::Writer::flush()
 {
        execWriter->flush();
index a6ffe2b258f164297228621d5ca51fdc2b695beb..72c126f09bd9dd8f4699cf50297e45dfc3956dbe 100644 (file)
@@ -47,25 +47,27 @@ namespace CodeSigning {
 //
 class BundleDiskRep : public DiskRep {
 public:
-       BundleDiskRep(const char *path);
-       BundleDiskRep(CFBundleRef ref);
+       BundleDiskRep(const char *path, const Context *ctx = NULL);
+       BundleDiskRep(CFBundleRef ref, const Context *ctx = NULL);
        
        CFDataRef component(CodeDirectory::SpecialSlot slot);
+       CFDataRef identification();
        std::string mainExecutablePath();
        CFURLRef canonicalPath();
-       std::string recommendedIdentifier();
        std::string resourcesRootPath();
-       CFDictionaryRef defaultResourceRules();
        void adjustResources(ResourceBuilder &builder);
-       const Requirements *defaultRequirements(const Architecture *arch);
        Universal *mainExecutableImage();
-       size_t pageSize();
        size_t signingBase();
        size_t signingLimit();
        std::string format();
        CFArrayRef modifiedFiles();
        UnixPlusPlus::FileDesc &fd();
        void flush();
+       
+       std::string recommendedIdentifier(const SigningContext &ctx);
+       CFDictionaryRef defaultResourceRules(const SigningContext &ctx);
+       const Requirements *defaultRequirements(const Architecture *arch, const SigningContext &ctx);
+       size_t pageSize(const SigningContext &ctx);
 
        CFBundleRef bundle() const { return mBundle; }
        
@@ -80,6 +82,7 @@ protected:
        void createMeta();                                              // (try to) create the meta-file directory
        
 private:
+       void setup(const Context *ctx);                 // shared init
        void checkModifiedFile(CFMutableArrayRef files, CodeDirectory::SpecialSlot slot);
 
 private:
@@ -100,10 +103,12 @@ public:
        Writer(BundleDiskRep *r);
        
        void component(CodeDirectory::SpecialSlot slot, CFDataRef data);
+       void remove();
        void flush();
        
 protected:
        DiskRep *execRep() { return rep->mExecRep; }
+       void remove(CodeDirectory::SpecialSlot slot);
 
 protected:
        RefPointer<BundleDiskRep> rep;
index eac0a4254ad0c6127ed000b1896d05c134ff44d5..ac17edbc4229db9fe62943c63404bd5c1887f028 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -39,10 +39,23 @@ namespace CodeSigning {
 //
 // Create an (empty) builder
 //
-CodeDirectory::Builder::Builder()
-       : mFlags(0), mSpecialSlots(0), mCodeSlots(0), mDir(NULL)
+CodeDirectory::Builder::Builder(HashAlgorithm digestAlgorithm)
+       : mFlags(0),
+         mHashType(digestAlgorithm),
+         mSpecialSlots(0),
+         mCodeSlots(0),
+         mScatter(NULL),
+         mScatterSize(0),
+         mDir(NULL)
 {
-       memset(mSpecial, 0, sizeof(mSpecial));
+       mDigestLength = MakeHash<Builder>(this)->digestLength();
+       mSpecial = (unsigned char *)calloc(cdSlotMax, mDigestLength);
+}
+
+CodeDirectory::Builder::~Builder()
+{
+       ::free(mSpecial);
+       ::free(mScatter);
 }
 
 
@@ -72,17 +85,33 @@ void CodeDirectory::Builder::reopen(string path, size_t offset, size_t length)
 //
 // Set the source for one special slot
 //
-void CodeDirectory::Builder::special(size_t slot, CFDataRef data)
+void CodeDirectory::Builder::specialSlot(SpecialSlot slot, CFDataRef data)
 {
        assert(slot <= cdSlotMax);
-       Hash hash;
-       hash(CFDataGetBytePtr(data), CFDataGetLength(data));
-       hash.finish(mSpecial[slot]);
+       MakeHash<Builder> hash(this);
+       hash->update(CFDataGetBytePtr(data), CFDataGetLength(data));
+       hash->finish(specialSlot(slot));
        if (slot >= mSpecialSlots)
                mSpecialSlots = slot;
 }
 
 
+//
+// Allocate a Scatter vector
+//
+CodeDirectory::Scatter *CodeDirectory::Builder::scatter(unsigned count)
+{
+       mScatterSize = (count + 1) * sizeof(Scatter);
+       if (!(mScatter = (Scatter *)::realloc(mScatter, mScatterSize)))
+               UnixError::throwMe(ENOMEM);
+       ::memset(mScatter, 0, mScatterSize);
+       return mScatter;
+}
+
+
+//
+// Calculate the size we'll need for the CodeDirectory as described so far
+//
 size_t CodeDirectory::Builder::size()
 {
        assert(mExec);                  // must have called executable()
@@ -97,8 +126,9 @@ size_t CodeDirectory::Builder::size()
        }
                
        size_t offset = sizeof(CodeDirectory);
+       offset += mScatterSize;                         // scatter vector
        offset += mIdentifier.size() + 1;       // size of identifier (with null byte)
-       offset += (mCodeSlots + mSpecialSlots) * Hash::digestLength; // hash vector
+       offset += (mCodeSlots + mSpecialSlots) * mDigestLength; // hash vector
        return offset;
 }
 
@@ -106,9 +136,15 @@ size_t CodeDirectory::Builder::size()
 //
 // Take everything added to date and wrap it up in a shiny new CodeDirectory.
 //
-// Note that this doesn't include or generate the signature. You're free to
-// modify the result. But this function determines the memory layout, so the
-// sizes and counts should be correct on entry.
+// Note that this only constructs a CodeDirectory; it does not touch any subsidiary
+// structures (resource tables, etc.), nor does it create any signature to secure
+// the CodeDirectory.
+// The returned CodeDirectory object is yours, and you may modify it as desired.
+// But the memory layout is set here, so the various sizes and counts should be good
+// when you call build().
+// It's up to us to order the dynamic fields as we wish; but note that we currently
+// don't pad them, and so they should be allocated in non-increasing order of required
+// alignment. Make sure to keep the code here in sync with the size-calculating code above.
 //
 CodeDirectory *CodeDirectory::Builder::build()
 {
@@ -127,8 +163,8 @@ CodeDirectory *CodeDirectory::Builder::build()
        mDir->nSpecialSlots = mSpecialSlots;
        mDir->nCodeSlots = mCodeSlots;
        mDir->codeLimit = mExecLength;
-       mDir->hashSize = Hash::digestLength;
-       mDir->hashType = cdHashTypeDefault;
+       mDir->hashType = mHashType;
+       mDir->hashSize = mDigestLength;
        if (mPageSize) {
                int pglog;
                assert(frexp(mPageSize, &pglog) == 0.5); // must be power of 2
@@ -140,27 +176,35 @@ CodeDirectory *CodeDirectory::Builder::build()
 
        // locate and fill flex fields
        size_t offset = sizeof(CodeDirectory);
+
+       if (mScatter) {
+               mDir->scatterOffset = offset;
+               memcpy(mDir->scatterVector(), mScatter, mScatterSize);
+               offset += mScatterSize;
+       }
+
        mDir->identOffset = offset;
        memcpy(mDir->identifier(), mIdentifier.c_str(), identLength);
        offset += identLength;
 
        // (add new flexibly-allocated fields here)
 
-       mDir->hashOffset = offset + mSpecialSlots * Hash::digestLength;
-       offset += (mSpecialSlots + mCodeSlots) * Hash::digestLength;
+       mDir->hashOffset = offset + mSpecialSlots * mDigestLength;
+       offset += (mSpecialSlots + mCodeSlots) * mDigestLength;
        assert(offset == total);        // matches allocated size
        
        // fill special slots
-       memset((*mDir)[-mSpecialSlots], 0, mDir->hashSize * mSpecialSlots);
+       memset((*mDir)[-mSpecialSlots], 0, mDigestLength * mSpecialSlots);
        for (size_t slot = 1; slot <= mSpecialSlots; ++slot)
-               memcpy((*mDir)[-slot], &mSpecial[slot], Hash::digestLength);
+               memcpy((*mDir)[-slot], specialSlot(slot), mDigestLength);
        
        // fill code slots
        mExec.seek(mExecOffset);
        size_t remaining = mExecLength;
        for (unsigned int slot = 0; slot < mCodeSlots; ++slot) {
                size_t thisPage = min(mPageSize, remaining);
-               hash(mExec, (*mDir)[slot], thisPage);
+               MakeHash<Builder> hasher(this);
+               generateHash(hasher, mExec, (*mDir)[slot], thisPage);
                remaining -= thisPage;
        }
        
index 01c0a6717d9e71df647ac5d146cf40af77f19b2b..3a050bbf158547ae0c87b1470b3fac53fcbe73c0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -36,37 +36,54 @@ namespace CodeSigning {
 
 //
 // Builder can construct CodeDirectories from pieces:
-//     Builder builder;
+//     Builder builder(...);
 //     builder.variousSetters(withSuitableData);
 //  CodeDirectory *result = builder.build();
 // Builder is not reusable.
 //
 class CodeDirectory::Builder {
 public:
-       Builder();
+       Builder(HashAlgorithm digestAlgorithm);
+       ~Builder();
        
        void executable(string path, size_t pagesize, size_t offset, size_t length);
        void reopen(string path, size_t offset, size_t length);
 
-       void special(size_t slot, CFDataRef data);
+       void specialSlot(SpecialSlot slot, CFDataRef data);
        void identifier(const std::string &code) { mIdentifier = code; }
        void flags(uint32_t f) { mFlags = f; }
        
+       Scatter *scatter(unsigned count);                       // allocate that many scatter elements (w/o sentinel)
+       Scatter *scatter() { return mScatter; }         // return already allocated scatter vector
+       
        size_t size();                                                          // calculate size
        CodeDirectory *build();                                         // build CodeDirectory and return it
+
+private:
+       DynamicHash *getHash() const { return CodeDirectory::hashFor(this->mHashType); }
+       
+       Hashing::Byte *specialSlot(SpecialSlot slot)
+               { assert(slot > 0 && slot <= cdSlotMax); return mSpecial + (slot - 1) * mDigestLength; }
+       Hashing::Byte *specialSlot(SpecialSlot slot) const
+               { assert(slot > 0 && slot <= cdSlotMax); return mSpecial + (slot - 1) * mDigestLength; }
        
 private:
-       Hash::SDigest mSpecial[cdSlotCount];            // special slot hashes
+       Hashing::Byte *mSpecial;                                        // array of special slot hashes
        UnixPlusPlus::AutoFileDesc mExec;                       // main executable file
        size_t mExecOffset;                                                     // starting offset in mExec
        size_t mExecLength;                                                     // total bytes of file to sign
        size_t mPageSize;                                                       // page size of executable (bytes)
        uint32_t mFlags;                                                        // CodeDirectory flags
+       uint32_t mHashType;                                                     // digest algorithm code
+       uint32_t mDigestLength;                                         // number of bytes in a single glue digest
        std::string mIdentifier;                                        // canonical identifier
        
        size_t mSpecialSlots;                                           // highest special slot set
        size_t mCodeSlots;                                                      // number of code pages (slots)
        
+       Scatter *mScatter;                                                      // scatter vector
+       size_t mScatterSize;                                            // number of scatter elements allocated (incl. sentinel)
+       
        CodeDirectory *mDir;                                            // what we're building
 };
 
index a74c0e0ed1fbeff9caa4d077f3c5cb1070b989ea..41607e12a425b67ee3d0d47c94542ba5a8a21da4 100644 (file)
@@ -40,6 +40,7 @@ using namespace UnixPlusPlus;
 CFMDiskRep::CFMDiskRep(const char *path)
        : SingleDiskRep(path), mTriedRead(false)
 {
+       CODESIGN_DISKREP_CREATE_CFM(this, (char*)path);
 }
 
 CFMDiskRep::~CFMDiskRep()
@@ -50,15 +51,24 @@ CFMDiskRep::~CFMDiskRep()
 
 
 //
-// CFM filter heuristic
+// CFM filter heuristic.
+// We look for the PEF header within the first scanLength bytes
+// of the file's data fork, at certain alignment boundaries (probably
+// conservative).
 //
-bool CFMDiskRep::candidiate(FileDesc &fd)
+bool CFMDiskRep::candidate(FileDesc &fd)
 {
        static const char magicMarker[] = "Joy!peffpwpc";
        static const size_t magicLength = 12;
-       char marker[magicLength];
-       return fd.read(marker, magicLength, 0) == magicLength
-               && !memcmp(marker, magicMarker, magicLength);
+       static const size_t scanLength = 128;
+       static const size_t scanAlignment = 4;
+       
+       char marker[scanLength];
+       if (fd.read(marker, scanLength, 0) == scanLength)
+               for (size_t p = 0; p <= scanLength - magicLength; p += scanAlignment)
+                       if (!memcmp(marker+p, magicMarker, magicLength))
+                               return true;
+       return false;
 }
 
 
@@ -78,33 +88,6 @@ CFDataRef CFMDiskRep::component(CodeDirectory::SpecialSlot slot)
 }
 
 
-//
-// In Mac OS X, a CFM binary must always be managed by the LaunchCFMApp
-// system tool. Thus, we recommend that this be required as a host.
-//
-static const uint8_t cfm_ireqs[] = {   // host => anchor apple and identifier com.apple.LaunchCFMApp
-       0xfa, 0xde, 0x0c, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
-       0x00, 0x00, 0x00, 0x14, 0xfa, 0xde, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x01,
-       0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16,
-       0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x4c, 0x61, 0x75, 0x6e, 0x63, 0x68,
-       0x43, 0x46, 0x4d, 0x41, 0x70, 0x70, 0x00, 0x00,
-};
-
-const Requirements *CFMDiskRep::defaultRequirements(const Architecture *)
-{
-       return ((const Requirements *)cfm_ireqs)->clone();      // need to pass ownership
-}
-
-
-//
-// Default to system-paged signing
-//
-size_t CFMDiskRep::pageSize()
-{
-       return segmentedPageSize;
-}
-
-
 //
 // The signing limit is the start of the signature if present,
 // or the end of the file otherwise.
@@ -138,6 +121,33 @@ void CFMDiskRep::flush()
 }
 
 
+//
+// In Mac OS X, a CFM binary must always be managed by the LaunchCFMApp
+// system tool. Thus, we recommend that this be required as a host.
+//
+static const uint8_t cfm_ireqs[] = {   // host => anchor apple and identifier com.apple.LaunchCFMApp
+       0xfa, 0xde, 0x0c, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+       0x00, 0x00, 0x00, 0x14, 0xfa, 0xde, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x01,
+       0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16,
+       0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x4c, 0x61, 0x75, 0x6e, 0x63, 0x68,
+       0x43, 0x46, 0x4d, 0x41, 0x70, 0x70, 0x00, 0x00,
+};
+
+const Requirements *CFMDiskRep::defaultRequirements(const Architecture *, const SigningContext &)
+{
+       return ((const Requirements *)cfm_ireqs)->clone();      // need to pass ownership
+}
+
+
+//
+// Default to system-paged signing
+//
+size_t CFMDiskRep::pageSize(const SigningContext &)
+{
+       return segmentedPageSize;
+}
+
+
 //
 // Locate, read, and cache embedded signing data from the CFM binary.
 //
@@ -153,9 +163,7 @@ void CFMDiskRep::readSigningData()
                if (fd.read(&sentinel, sizeof(sentinel), fd.fileSize() - sizeof(Sentinel)) == sizeof(Sentinel))
                        if (sentinel.magic == EmbeddedSignatureBlob::typeMagic) {
                                mSigningOffset = sentinel.offset;
-                               fd.seek(mSigningOffset);
-                               mSigningData = EmbeddedSignatureBlob::readBlob(fd);
-                               if (mSigningData)
+                               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());
index 8eeaa2bea947bc8738565548ec86dd1fc9986574..3ea17ab8488ba25e85e55e6a6eb938f9da09c9c9 100644 (file)
@@ -55,13 +55,14 @@ public:
        ~CFMDiskRep();
        
        CFDataRef component(CodeDirectory::SpecialSlot slot);
-       const Requirements *defaultRequirements(const Architecture *arch);
-       size_t pageSize();
        size_t signingLimit();
        std::string format();
        void flush();
        
-       static bool candidiate(UnixPlusPlus::FileDesc &fd); // could this reasonably be a CFM code?
+       const Requirements *defaultRequirements(const Architecture *arch, const SigningContext &ctx);
+       size_t pageSize(const SigningContext &ctx);
+       
+       static bool candidate(UnixPlusPlus::FileDesc &fd); // could this reasonably be a CFM code?
 
 public:
        //
diff --git a/lib/cfmunge.cpp b/lib/cfmunge.cpp
deleted file mode 100644 (file)
index 214cac5..0000000
+++ /dev/null
@@ -1,597 +0,0 @@
-/*
- * Copyright (c) 2006-2007 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@
- */
-//
-// CoreFoundation building and parsing functions.
-//
-// These classes provide a printf/scanf-like interface to nested data structures
-// of the Property List Subset of CoreFoundation.
-//
-#include "cfmunge.h"
-#include <security_utilities/cfutilities.h>
-#include <security_utilities/errors.h>
-
-namespace Security {
-
-
-//
-// Format codes for consistency
-//
-#define F_ARRAY                        'A'
-#define F_BOOLEAN              'B'
-#define F_DATA                 'X'
-#define F_DICTIONARY   'D'
-#define F_OBJECT               'O'
-#define F_STRING               'S'
-#define F_NUMBER               'N'
-
-
-//
-// Initialize a CFMunge. We start out with the default CFAllocator, and
-// we do not throw errors.
-//
-CFMunge::CFMunge(const char *fmt, va_list arg)
-       : format(fmt), allocator(NULL), error(noErr)
-{
-       va_copy(args, arg);
-}
-
-CFMunge::~CFMunge()
-{
-       va_end(args);
-}
-
-
-//
-// Skip whitespace and other fluff and deliver the next significant character.
-//
-char CFMunge::next()
-{
-       while (*format && (isspace(*format) || *format == ',')) ++format;
-       return *format;
-}
-
-
-//
-// Locate and consume an optional character
-//
-bool CFMunge::next(char c)
-{
-       if (next() == c) {
-               ++format;
-               return true;
-       } else
-               return false;
-}
-
-
-//
-// Process @? parameter specifications.
-// The @ operator is used for side effects, and does not return a value.
-//
-bool CFMunge::parameter()
-{
-       switch (*++format) {
-       case 'A':
-               ++format;
-               allocator = va_arg(args, CFAllocatorRef);
-               return true;
-       case 'E':
-               ++format;
-               error = va_arg(args, OSStatus);
-               return true;
-       default:
-               return false;
-       }
-}
-
-
-//
-// The top constructor.
-//
-CFTypeRef CFMake::make()
-{
-       while (next() == '@')
-               parameter();
-       switch (next()) {
-       case '\0':
-               return NULL;
-       case '{':
-               return makedictionary();
-       case '[':
-               return makearray();
-       case '\'':
-               return makestring();
-       case '%':
-               return makeformat();
-       case '#':
-               return makespecial();
-       case ']':
-       case '}':
-               assert(false);  // unexpected
-               return NULL;    // error
-       default:
-               if (isdigit(*format))
-                       return makenumber();
-               else if (isalpha(*format))
-                       return makestring();
-               else {
-                       assert(false);
-                       return NULL;
-               }
-       }
-}
-
-
-CFTypeRef CFMake::makeformat()
-{
-       ++format;
-       switch (*format++) {
-       case 'b':       // blob (pointer, length)
-               {
-                       const void *data = va_arg(args, const void *);
-                       size_t length = va_arg(args, size_t);
-                       return CFDataCreate(allocator, (const UInt8 *)data, length);
-               }
-       case F_BOOLEAN: // boolean (with int promotion)
-               return va_arg(args, int) ? kCFBooleanTrue : kCFBooleanFalse;
-       case 'd':
-               return makeCFNumber(va_arg(args, int));
-       case 's':
-               return CFStringCreateWithCString(allocator, va_arg(args, const char *),
-                       kCFStringEncodingUTF8);
-       case F_OBJECT:
-               return CFRetain(va_arg(args, CFTypeRef));
-       case 'u':
-               return makeCFNumber(va_arg(args, unsigned int));
-       default:
-               assert(false);
-               return NULL;
-       }
-}
-
-
-CFTypeRef CFMake::makespecial()
-{
-       ++format;
-       switch (*format++) {
-       case 'N':
-               return kCFNull;
-       case 't':
-       case 'T':
-               return kCFBooleanTrue;
-       case 'f':
-       case 'F':
-               return kCFBooleanFalse;
-       default:
-               assert(false);
-               return NULL;
-       }
-}
-
-
-CFTypeRef CFMake::makenumber()
-{
-       double value = strtod(format, (char **)&format);
-       return CFNumberCreate(allocator, kCFNumberDoubleType, &value);
-}      
-
-
-//
-// Embedded strings can either be alphanumeric (only), or delimited with single quotes ''.
-// No escapes are processed within such quotes. If you want arbitrary string values, use %s.
-//
-CFTypeRef CFMake::makestring()
-{
-       const char *start, *end;
-       if (*format == '\'') {
-               start = ++format;       // next quote
-               if (!(end = strchr(format, '\''))) {
-                       assert(false);
-                       return NULL;
-               }
-               format = end + 1;
-       } else {
-               start = format;
-               for (end = start + 1; isalnum(*end); ++end) ;
-               format = end;
-       }
-       return CFStringCreateWithBytes(allocator,
-               (const UInt8 *)start, end - start,
-               kCFStringEncodingUTF8, false);
-}
-
-
-//
-// Construct a CFDictionary
-//
-CFTypeRef CFMake::makedictionary()
-{
-       ++format;       // next '{'
-       next('!');      // indicates mutable (currently always true)
-       CFMutableDictionaryRef dict;
-       if (next('+')) { // {+%O, => copy dictionary argument, then proceed
-               if (next('%') && next('O')) {
-                       CFDictionaryRef source = va_arg(args, CFDictionaryRef);
-                       dict = CFDictionaryCreateMutableCopy(allocator, NULL, source);
-                       if (next('}'))
-                               return dict;
-               } else
-                       return NULL;    // bad syntax
-       } else
-               dict = CFDictionaryCreateMutable(allocator, 0,
-                       &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-       if (add(dict))
-               return dict;
-       else {
-               CFRelease(dict);
-               return NULL;
-       }
-}
-
-CFDictionaryRef CFMake::add(CFMutableDictionaryRef dict)
-{
-       while (next() != '}') {
-               CFTypeRef key = make();
-               if (key == NULL)
-                       return NULL;
-               if (!next('=')) {
-                       CFRelease(key);
-                       return NULL;
-               }
-               if (CFTypeRef value = make()) {
-                       CFDictionaryAddValue(dict, key, value);
-                       CFRelease(key);
-                       CFRelease(value);
-               } else {
-                       CFRelease(key);
-                       return NULL;
-               }
-       }
-       ++format;
-       return dict;
-}
-
-
-CFDictionaryRef CFMake::addto(CFMutableDictionaryRef dict)
-{
-       if (next('{'))
-               return add(dict);
-       else {
-               assert(false);
-               return NULL;
-       }
-}
-
-
-//
-// Construct a CFArray
-//
-CFTypeRef CFMake::makearray()
-{
-       ++format;       // next '['
-       next('!');      // indicates mutable (currently always)
-       CFMutableArrayRef array = makeCFMutableArray(0);
-       while (next() != ']') {
-               CFTypeRef value = make();
-               if (value == NULL) {
-                       CFRelease(array);
-                       return NULL;
-               }
-               CFArrayAppendValue(array, value);
-               CFRelease(value);
-       }
-       ++format;
-       return array;
-}
-
-
-//
-// A CFScan processes its format by parsing through an existing CF object
-// structure, matching and extracting values as directed. Note that CFScan
-// is a structure (tree) scanner rather than a linear parser, and will happily
-// parse out a subset of the input object graph.
-//
-class CFScan : public CFMake {
-public:
-       CFScan(const char *format, va_list args)
-               : CFMake(format, args), suppress(false) { }
-       
-       bool scan(CFTypeRef obj);
-       CFTypeRef dictpath(CFTypeRef obj);
-       
-protected:
-       bool scandictionary(CFDictionaryRef obj);
-       bool scanarray(CFArrayRef obj);
-       bool scanformat(CFTypeRef obj);
-       
-       enum Typescan { fail = -1, more = 0, done = 1 };
-       Typescan typescan(CFTypeRef obj, CFTypeID type);
-
-       template <class Value>
-       bool CFScan::scannumber(CFTypeRef obj);
-       
-       template <class Type>
-       void store(Type value);
-       
-       bool suppress;                          // output suppression
-};
-
-
-//
-// Master scan function
-//
-bool CFScan::scan(CFTypeRef obj)
-{
-       while (next() == '@')
-               parameter();
-       switch (next()) {
-       case '\0':
-               return true;    // done, okay
-       case '{':
-               if (obj && CFGetTypeID(obj) != CFDictionaryGetTypeID())
-                       return false;
-               return scandictionary(CFDictionaryRef(obj));
-       case '[':
-               if (obj && CFGetTypeID(obj) != CFArrayGetTypeID())
-                       return false;
-               return scanarray(CFArrayRef(obj));
-       case '%':       // return this value in some form
-               return scanformat(obj);
-       case '=':       // match value
-               {
-                       ++format;
-                       CFTypeRef match = make();
-                       bool rc = CFEqual(obj, match);
-                       CFRelease(match);
-                       return rc;
-               }
-       case ']':
-       case '}':
-               assert(false);  // unexpected
-               return false;
-       default:
-               assert(false);
-               return false;
-       }
-}
-
-
-//
-// Primitive type-match helper.
-// Ensures the object has the CF runtime type required, and processes
-// the %?o format (return CFTypeRef) and %?n format (ignore value).
-//
-CFScan::Typescan CFScan::typescan(CFTypeRef obj, CFTypeID type)
-{
-       if (obj && CFGetTypeID(obj) != type)
-               return fail;
-       switch (*++format) {
-       case F_OBJECT:  // return CFTypeRef
-               ++format;
-               store<CFTypeRef>(obj);
-               return done;
-       case 'n':       // suppress assignment
-               ++format;
-               return done;
-       default:
-               return more;
-       }
-}
-
-
-//
-// Store a value into the next varargs slot, unless output suppression is on.
-//
-template <class Type>
-void CFScan::store(Type value)
-{
-       if (!suppress)
-               *va_arg(args, Type *) = value;
-}
-
-
-//
-// Convert a CFNumber to an external numeric form
-//
-template <class Value>
-bool CFScan::scannumber(CFTypeRef obj)
-{
-       ++format;       // consume format code
-       if (!obj)
-               return true; // suppressed, okay
-       if (CFGetTypeID(obj) != CFNumberGetTypeID())
-               return false;
-       store<Value>(cfNumber<Value>(CFNumberRef(obj)));
-       return true;
-}
-
-
-//
-// Process % scan forms.
-// This delivers the object value, scanf-style, somehow.
-//
-bool CFScan::scanformat(CFTypeRef obj)
-{
-       switch (*++format) {
-       case F_OBJECT:
-               store<CFTypeRef>(obj);
-               return true;
-       case F_ARRAY:   // %a*
-               return typescan(obj, CFArrayGetTypeID()) == done;
-       case F_BOOLEAN:
-               if (Typescan rc = typescan(obj, CFBooleanGetTypeID()))
-                       return rc == done;
-               switch (*format) {
-               case 'f':       // %Bf - two arguments (value, &variable)
-                       {
-                               unsigned flag = va_arg(args, unsigned);
-                               unsigned *value = va_arg(args, unsigned *);
-                               if (obj == kCFBooleanTrue && !suppress)
-                                       *value |= flag;
-                               return true;
-                       }
-               default:        // %b - CFBoolean as int boolean
-                       store<int>(obj == kCFBooleanTrue);
-                       return true;
-               }
-       case F_DICTIONARY:
-               return typescan(obj, CFDictionaryGetTypeID()) == done;
-       case 'd':       // %d - int
-               return scannumber<int>(obj);
-       case F_NUMBER:
-               return typescan(obj, CFNumberGetTypeID()) == done;
-       case F_STRING:
-       case 's':
-               if (Typescan rc = typescan(obj, CFStringGetTypeID()))
-                       return rc == done;
-               // %s
-               store<std::string>(cfString(CFStringRef(obj)));
-               return true;
-       case 'u':
-               return scannumber<unsigned int>(obj);
-       case F_DATA:
-               return typescan(obj, CFDataGetTypeID()) == done;
-       default:
-               assert(false);
-               return false;
-       }
-}
-
-
-bool CFScan::scandictionary(CFDictionaryRef obj)
-{
-       ++format;       // skip '{'
-       while (next() != '}') {
-               bool optional = next('?');
-               if (CFTypeRef key = make()) {
-                       bool oldSuppress = suppress;
-                       CFTypeRef elem = obj ? CFDictionaryGetValue(obj, key) : NULL;
-                       if (elem || optional) {
-                               suppress |= (elem == NULL);
-                               if (next('=')) {
-                                       if (scan(elem)) {
-                                               suppress = oldSuppress; // restore
-                                               CFRelease(key);
-                                               continue;
-                                       }
-                               }
-                       }
-                       CFRelease(key);
-                       return false;
-               } else {
-                       assert(false);  // bad format
-                       return false;
-               }
-       }
-       return true;
-}
-
-
-bool CFScan::scanarray(CFArrayRef obj)
-{
-       ++format;       // skip '['
-       CFIndex length = CFArrayGetCount(obj);
-       for (int pos = 0; pos < length; ++pos) {
-               if (next() == ']')
-                       return true;
-               if (!scan(CFArrayGetValueAtIndex(obj, pos)))
-                       return false;
-       }
-       return false;   // array length exceeded
-}
-
-
-//
-// Run down a "dictionary path", validating heavily.
-//
-CFTypeRef CFScan::dictpath(CFTypeRef obj)
-{
-       while (next()) {        // while we've got more text
-               next('.');              // optional
-               if (obj == NULL || CFGetTypeID(obj) != CFDictionaryGetTypeID())
-                       return NULL;
-               CFTypeRef key = make();
-               obj = CFDictionaryGetValue(CFDictionaryRef(obj), key);
-               CFRelease(key);
-       }
-       return obj;
-}
-
-
-//
-// The public functions
-//
-CFTypeRef cfmake(const char *format, ...)
-{
-       va_list args;
-       va_start(args, format);
-       CFTypeRef result = CFMake(format, args).make();
-       va_end(args);
-       return result;
-}
-
-CFTypeRef vcfmake(const char *format, va_list args)
-{
-       return CFMake(format, args).make();
-}
-
-CFDictionaryRef cfadd(CFMutableDictionaryRef dict, const char *format, ...)
-{
-       va_list args;
-       va_start(args, format);
-       CFDictionaryRef result = CFMake(format, args).addto(dict);
-       va_end(args);
-       return result;
-}
-
-
-bool cfscan(CFTypeRef obj, const char *format, ...)
-{
-       va_list args;
-       va_start(args, format);
-       bool result = vcfscan(obj, format, args);
-       va_end(args);
-       return result;
-}
-
-bool vcfscan(CFTypeRef obj, const char *format, va_list args)
-{
-       return CFScan(format, args).scan(obj);
-}
-
-
-CFTypeRef cfget(CFTypeRef obj, const char *format, ...)
-{
-       va_list args;
-       va_start(args, format);
-       CFTypeRef result = vcfget(obj, format, args);
-       va_end(args);
-       return result;
-}
-
-CFTypeRef vcfget(CFTypeRef obj, const char *format, va_list args)
-{
-       return CFScan(format, args).dictpath(obj);
-}
-
-}      // end namespace Security
diff --git a/lib/cfmunge.h b/lib/cfmunge.h
deleted file mode 100644 (file)
index 2af591b..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (c) 2000-2004 Apple Computer, 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@
- */
-//
-// CoreFoundation building and parsing functions
-//
-#ifndef _H_CFMUNGE
-#define _H_CFMUNGE
-
-#include <security_utilities/cfutilities.h>
-#include <CoreFoundation/CoreFoundation.h>
-#include <cstdarg>
-
-namespace Security {
-
-
-//
-// Common interface to Mungers.
-// A CFMunge provides a one-pass, non-resettable scan through a format string,
-// performing various actions on the way.
-//
-class CFMunge {
-public:
-       CFMunge(const char *fmt, va_list arg);
-       ~CFMunge();
-
-protected:
-       char next();
-       bool next(char c);
-       
-       bool parameter();
-       
-protected:
-       const char *format;
-       va_list args;
-       CFAllocatorRef allocator;
-       OSStatus error;
-};
-
-
-//
-// A CFMake is a CFMunge for making CF data structures.
-//
-class CFMake : public CFMunge {
-public:
-       CFMake(const char *fmt, va_list arg) : CFMunge(fmt, arg) { }
-       
-       CFTypeRef make();
-       CFDictionaryRef addto(CFMutableDictionaryRef dict);
-       
-protected:
-       CFTypeRef makedictionary();
-       CFTypeRef makearray();
-       CFTypeRef makenumber();
-       CFTypeRef makestring();
-       CFTypeRef makeformat();
-       CFTypeRef makespecial();
-
-       CFDictionaryRef add(CFMutableDictionaryRef dict);
-};
-
-
-//
-// Make a CF object following a general recipee
-//
-CFTypeRef cfmake(const char *format, ...);
-CFTypeRef vcfmake(const char *format, va_list args);
-
-template <class CFType>
-CFType cfmake(const char *format, ...)
-{
-       va_list args;
-       va_start(args, format);
-       CFType result = CFType(vcfmake(format, args));
-       va_end(args);
-       return result;
-}
-
-CFDictionaryRef cfadd(CFMutableDictionaryRef dict, const char *format, ...);
-
-
-//
-// Parse out parts of a CF object following a general recipe.
-// Cfscan returns false on error; cfget throws.
-//
-bool cfscan(CFTypeRef source, const char *format, ...);
-bool vcfscan(CFTypeRef source, const char *format, va_list args);
-
-CFTypeRef cfget(CFTypeRef source, const char *format, ...);
-CFTypeRef vcfget(CFTypeRef source, const char *format, va_list args);
-
-template <class CFType>
-CFType cfget(CFTypeRef source, const char *format, ...)
-{
-       va_list args;
-       va_start(args, format);
-       CFType result = CFType(vcfget(source, format, args));
-       va_end(args);
-       return CFTraits<CFType>::check(result) ? result : NULL;
-}
-
-template <class CFType>
-class CFTemp : public CFRef<CFType> {
-public:
-       CFTemp(const char *format, ...)
-       {
-               va_list args;
-               va_start(args, format);
-               this->take(CFType(vcfmake(format, args)));
-               va_end(args);
-       }
-};
-
-
-}      // end namespace Security
-
-#endif //_H_CFMUNGE
index 5ce2ff6a9ae21c6a7ee357124568e0874326b05c..3eedb3c784ddc82b91fef39656844161f0fac4a6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -25,7 +25,8 @@
 // codedirectory - format and operations for code signing "code directory" structures
 //
 #include "codedirectory.h"
-#include "CSCommon.h"
+#include "csutilities.h"
+#include "CSCommonPriv.h"
 
 using namespace UnixPlusPlus;
 
@@ -75,6 +76,8 @@ unsigned CodeDirectory::slotAttributes(SpecialSlot slot)
                return cdComponentPerArchitecture; // raw
        case cdEntitlementSlot:
                return cdComponentIsBlob; // global
+       case cdIdentificationSlot:
+               return cdComponentPerArchitecture; // raw
        default:
                return 0; // global, raw
        }
@@ -92,26 +95,58 @@ const char * const CodeDirectory::debugSlotName[] = {
        "info",
        "requirements",
        "resources",
-       "application"
+       "application",
+       "entitlement"
 };
 #endif //NDEBUG
 
 
 //
-// Check the version of this CodeDirectory for basic sanity.
+// Check a CodeDirectory for basic integrity. This should ensure that the
+// version is understood by our code, and that the internal structure
+// (offsets etc.) is intact. In particular, it must make sure that no offsets
+// point outside the CodeDirectory.
 // Throws if the directory is corrupted or out of versioning bounds.
 // Returns if the version is usable (perhaps with degraded features due to
 // compatibility hacks).
 //
-void CodeDirectory::checkVersion() const
+// Note: There are some things we don't bother checking because they won't
+// cause crashes, and will just be flagged as nonsense later. For example,
+// a Bad Guy could overlap the identifier and hash fields, which is nonsense
+// but not dangerous.
+//
+void CodeDirectory::checkIntegrity() const
 {
+       // check version for support
        if (!this->validateBlob())
                MacOSError::throwMe(errSecCSSignatureInvalid);  // busted
        if (version > compatibilityLimit)
                MacOSError::throwMe(errSecCSSignatureUnsupported);      // too new - no clue
+       if (version < earliestVersion)
+               MacOSError::throwMe(errSecCSSignatureUnsupported);      // too old - can't support
        if (version > currentVersion)
                secdebug("codedir", "%p version 0x%x newer than current 0x%x",
                        this, uint32_t(version), currentVersion);
+       
+       // 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)))
+               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)
+               unsigned int pagesConsumed = 0;
+               while (scatter->count) {
+                       if (!contains(scatter, sizeof(Scatter)))
+                               MacOSError::throwMe(errSecCSSignatureFailed);
+                       pagesConsumed += scatter->count;
+                       scatter++;
+               }
+               if (!contains(scatter, sizeof(Scatter)))                        // (even sentinel must be in range)
+                       MacOSError::throwMe(errSecCSSignatureFailed);
+               if (!contains((*this)[pagesConsumed-1], hashSize))      // referenced too many main hash slots
+                       MacOSError::throwMe(errSecCSSignatureFailed);
+       }
 }
 
 
@@ -121,9 +156,10 @@ void CodeDirectory::checkVersion() const
 bool CodeDirectory::validateSlot(const void *data, size_t length, Slot slot) const
 {
        secdebug("codedir", "%p validating slot %d", this, int(slot));
-       Hash::Byte digest[Hash::digestLength];
-       hash(data, length, digest);
-       return memcmp(digest, (*this)[slot], Hash::digestLength) == 0;
+       MakeHash<CodeDirectory> hasher(this);
+       Hashing::Byte digest[hasher->digestLength()];
+       generateHash(hasher, data, length, digest);
+       return memcmp(digest, (*this)[slot], hasher->digestLength()) == 0;
 }
 
 
@@ -133,9 +169,10 @@ bool CodeDirectory::validateSlot(const void *data, size_t length, Slot slot) con
 //
 bool CodeDirectory::validateSlot(FileDesc fd, size_t length, Slot slot) const
 {
-       Hash::Digest digest;
-       hash(fd, digest, length);
-       return memcmp(digest, (*this)[slot], Hash::digestLength) == 0;
+       MakeHash<CodeDirectory> hasher(this);
+       Hashing::Byte digest[hasher->digestLength()];
+       generateHash(hasher, fd, digest, length);
+       return memcmp(digest, (*this)[slot], hasher->digestLength()) == 0;
 }
 
 
@@ -147,8 +184,8 @@ bool CodeDirectory::validateSlot(FileDesc fd, size_t length, Slot slot) const
 bool CodeDirectory::slotIsPresent(Slot slot) const
 {
        if (slot >= -Slot(nSpecialSlots) && slot < Slot(nCodeSlots)) {
-               const Hash::Byte *digest = (*this)[slot];
-               for (unsigned n = 0; n < Hash::digestLength; n++)
+               const Hashing::Byte *digest = (*this)[slot];
+               for (unsigned n = 0; n < hashSize; n++)
                        if (digest[n])
                                return true;    // non-zero digest => present
        }
@@ -156,6 +193,27 @@ bool CodeDirectory::slotIsPresent(Slot slot) const
 }
 
 
+//
+// Given a hash type code, create an appropriate subclass of DynamicHash
+// and return it. The caller owns the object and  must delete it when done.
+// This function never returns NULL. It throws if the hashType is unsuupported,
+// or if there's an error creating the hasher.
+//
+DynamicHash *CodeDirectory::hashFor(HashAlgorithm hashType)
+{
+       CCDigestAlg alg;
+       switch (hashType) {
+       case kSecCodeSignatureHashSHA1:                                         alg = kCCDigestSHA1; break;
+       case kSecCodeSignatureHashSHA256:                                       alg = kCCDigestSHA256; break;
+       case kSecCodeSignatureHashPrestandardSkein160x256:      alg = kCCDigestSkein160; break;
+       case kSecCodeSignatureHashPrestandardSkein256x512:      alg = kCCDigestSkein256; break;
+       default:
+               MacOSError::throwMe(errSecCSSignatureUnsupported);
+       }
+       return new CCHashInstance(alg);
+}
+
+
 //
 // Hash the next limit bytes of a file and return the digest.
 // If the file is shorter, hash as much as you can.
@@ -163,48 +221,34 @@ bool CodeDirectory::slotIsPresent(Slot slot) const
 // Return how many bytes were actually hashed.
 // Throw on any errors.
 //
-size_t CodeDirectory::hash(FileDesc fd, Hash::Byte *digest, size_t limit)
+size_t CodeDirectory::generateHash(DynamicHash *hasher, FileDesc fd, Hashing::Byte *digest, size_t limit)
 {
-       IFDEBUG(size_t hpos = fd.position());
-       IFDEBUG(size_t hlimit = limit);
-       unsigned char buffer[4096];
-       Hash hash;
-       size_t total = 0;
-       for (;;) {
-               size_t size = sizeof(buffer);
-               if (limit && limit < size)
-                       size = limit;
-               size_t got = fd.read(buffer, size);
-               total += got;
-               if (fd.atEnd())
-                       break;
-               hash(buffer, got);
-               if (limit && (limit -= got) == 0)
-                       break;
-       }
-       hash.finish(digest);
-       secdebug("cdhash", "fd %d %zd@0x%zx => %2x.%2x.%2x...",
-               fd.fd(), hpos, hlimit, digest[0], digest[1], digest[2]);
-       return total;
+       size_t size = hashFileData(fd, hasher, limit);
+       hasher->finish(digest);
+       return size;
 }
 
 
 //
 // Ditto, but hash a memory buffer instead.
 //
-size_t CodeDirectory::hash(const void *data, size_t length, Hash::Byte *digest)
+size_t CodeDirectory::generateHash(DynamicHash *hasher, const void *data, size_t length, Hashing::Byte *digest)
 {
-       Hash hash;
-       hash(data, length);
-       hash.finish(digest);
+       hasher->update(data, length);
+       hasher->finish(digest);
        return length;
 }
 
 
+}      // CodeSigning
+}      // Security
+
+
 //
-// Canonical text form for user-settable code directory flags
+// Canonical text form for user-settable code directory flags.
+// Note: This table is actually exported from Security.framework.
 //
-const CodeDirectory::FlagItem CodeDirectory::flagItems[] = {
+const SecCodeDirectoryFlagTable kSecCodeDirectoryFlagTable[] = {
        { "host",               kSecCodeSignatureHost,                  true },
        { "adhoc",              kSecCodeSignatureAdhoc,                 false },
        { "hard",               kSecCodeSignatureForceHard,             true },
@@ -212,33 +256,3 @@ const CodeDirectory::FlagItem CodeDirectory::flagItems[] = {
        { "expires",    kSecCodeSignatureForceExpiration, true },
        { NULL }
 };
-
-
-//
-// Parse a canonical text description of code flags, in the form
-//     flag,...,flag
-// where each flag can be a prefix of a known flag name.
-// Internally set flags are not accepted.
-//
-uint32_t CodeDirectory::textFlags(std::string text)
-{
-       uint32_t flags = 0;
-       for (string::size_type comma = text.find(','); ; text = text.substr(comma+1), comma = text.find(',')) {
-               string word = (comma == string::npos) ? text : text.substr(0, comma);
-               const CodeDirectory::FlagItem *item;
-               for (item = CodeDirectory::flagItems; item->name; item++)
-                       if (item->external && !strncmp(word.c_str(), item->name, word.size())) {
-                               flags |= item->value;
-                               break;
-                       }
-               if (!item)      // not found
-                       MacOSError::throwMe(errSecCSInvalidFlags);
-               if (comma == string::npos)      // last word
-                       break;
-       }
-       return flags;
-}
-
-
-}      // CodeSigning
-}      // Security
index 135f2aa81ec016e09b6c4c4723b5e573686c0b75..b6f8b0ede4b584412fe97cc1a8835a799083936e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
 //
 // codedirectory - format and operations for code signing "code directory" structures
 //
-// A CodeDirectory is a contiguous binary blob containing a two-tiered
-// hash of (much of) the contents of a real StaticCode object.
-// It consists of a header followed by an array of hash vector elements.
+// A CodeDirectory is the top level object describing a particular instance
+// of (static) code. It contains hashes of other objects that further describe
+// parts of that code; these hashes hold the various pieces together.
 //
-// This structure is meant to be self-describing, binary stable, and endian independent.
+// This means that if you reliably ascertain the contents of a CodeDirectory,
+// you can verify the integrity of the entire code object it represents - the
+// CodeDirectory can stand as a proxy for that code.
+//
+// Code signatures usually use CMS to sign the CodeDirectory to form full
+// signature blobs; ad-hoc signatures simply record the SHA-1 hash of the
+// CodeDirectory directly. The SHA-1 of the CodeDirectory is also widely
+// used as concordance for a particular code instance - in essence, for
+// different processes (or a process and the kernel) to "compare notes"
+// to make sure they refer to the same code.
 //
 #ifndef _H_CODEDIRECTORY
 #define _H_CODEDIRECTORY
 #include <security_utilities/blob.h>
 #include <security_utilities/cfutilities.h>
 #include <security_utilities/hashing.h>
+#include <Security/CSCommonPriv.h>
 
 
 namespace Security {
 namespace CodeSigning {
 
 
-//
-// Types of hashes supported.
-// Actually, right now, only SHA1 is really supported.
-//
-enum {
-       cdHashTypeSHA1 = 1,
-       cdHashTypeSHA256 = 2,
-       
-       cdHashTypeDefault = cdHashTypeSHA1
-};
-
-
 //
 // Conventional string names for various code signature components.
 // Depending on storage, these may end up as filenames, extended attribute names, etc.
@@ -64,7 +62,7 @@ enum {
 #define kSecCS_REQUIREMENTSFILE                "CodeRequirements"      // internal requirements
 #define kSecCS_RESOURCEDIRFILE         "CodeResources"         // resource directory
 #define kSecCS_APPLICATIONFILE         "CodeApplication"       // application-specific resource
-#define kSecCS_ENTITLEMENTFILE         "CodeEntitlements"      // entitlement configuration (just in case)
+#define kSecCS_ENTITLEMENTFILE         "CodeEntitlements"      // entitlement configuration
 
 
 //
@@ -72,13 +70,20 @@ enum {
 // indices. This enumeration is also used widely in various internal APIs, and as
 // type values in embedded SuperBlobs.
 //
+// How to add a new special slot type:
+//     1. Add the new name at the end of the primary or virtual slot array (below).
+//     2a. For slots representing existing code pieces, follow the ball for cdInfoSlot.
+//     2b. For slots representing global signature components, follow the ball for cdResourceDirSlot.
+//     2c. For slots representing per-architecture signature components, follow the ball for cdEntitlementSlot.
+// ("Follow the ball" -> Global search for that name and do likewise.)
+//
 enum {
        //
        // Primary slot numbers.
        // These values are potentially present in the CodeDirectory hash array
        // under their negative values. They are also used in APIs and SuperBlobs.
        // Note that zero must not be used for these (it's page 0 of the main code array),
-       // and it's good to assign contiguous (very) small values for them.
+       // and it is important to assign contiguous (very) small values for them.
        //
        cdInfoSlot = 1,                                         // Info.plist
        cdRequirementsSlot = 2,                         // internal requirements
@@ -88,19 +93,20 @@ enum {
        // (add further primary slot numbers here)
 
        cdSlotCount,                                            // total number of special slots (+1 for slot 0)
-       cdSlotMax = cdSlotCount - 1,            // highest special slot number
+       cdSlotMax = cdSlotCount - 1,            // highest special slot number (as a positive number)
        
        //
        // Virtual slot numbers.
-       // These values are NOT used in the CodeDirectory hash array. The are used as
-       // internal API identifiers and as types in in-image SuperBlobs.
+       // These values are NOT used in the CodeDirectory hash array. They are used as
+       // internal API identifiers and as types in SuperBlobs.
        // Zero is okay to use here; and we assign that to the CodeDirectory itself so
        // it shows up first in (properly sorted) SuperBlob indices. The rest of the
        // numbers is set Far Away so the primary slot set can expand safely.
-       // It's okay to have gaps in these assignments.
+       // It's okay to have large gaps in these assignments.
        //
        cdCodeDirectorySlot = 0,                        // CodeDirectory
        cdSignatureSlot = 0x10000,                      // CMS signature
+       cdIdentificationSlot,                           // identification blob
        // (add further virtual slot numbers here)
 };
 
@@ -122,20 +128,23 @@ enum {
 // elements packed after it. For help in constructing a CodeDirectory, use the nested
 // Builder class.
 //
-// The hashes are stored as an array of digests. The array covers the range
-// [-nSpecialSlots .. nCodeSlots-1]. Non-negative indices  denote pages of the main
-// executable. Negative indices indicate "special" hashes, each of a different thing
-// (see cd*Slot constants above). Special slots that are in range but not present
-// are zeroed out. Unallocated special slots are also presumed absent; this is not
-// an error. (Thus the range of special slots can be extended at will.)
+// At the heart of a CodeDirectory lies a packed array of hash digests.
+// The array's zero-index element is at offset hashOffset, and the array covers
+// elements in the range [-nSpecialSlots .. nCodeSlots-1]. Non-negative indices
+// denote pages of the main executable. Negative indices indicate "special" hashes,
+// each of a different thing (see cd*Slot constants above).
+// Special slots that are in range but not present are zeroed out. Unallocated special
+// slots are also presumed absent; this is not an error. (Thus the range of special
+// slots can be extended at will.)
 //
 // HOW TO MANAGE COMPATIBILITY:
-// Each CodeDirectory has a format (compatibility) version. Three constants control
+// Each CodeDirectory has a format (compatibility) version. Two constants control
 // versioning:
 //     * currentVersion is the version used for newly created CodeDirectories.
 //  * compatibilityLimit is the highest version the code will accept as compatible.
 // Test for version < currentVersion to detect old formats that may need special
-// handling. The current code rejects those; add backward cases to checkVersion().
+// handling; this is done in checkIntegrity(). The current code rejects versions
+// below earliestVersion.
 // Break backward compatibility by rejecting versions that are unsuitable.
 // Accept currentVersion < version <= compatibilityLimit as versions newer than
 // those understood by this code but engineered (by newer code) to be backward
@@ -144,8 +153,9 @@ enum {
 // When creating a new version, increment currentVersion. When adding new fixed fields,
 // just append them; the flex fields will shift to make room. To add new flex fields,
 // add a fixed field containing the new field's offset and add suitable computations
-// to the Builder to place the new data (right) before the hash array. Older code will
-// then simply ignore your new fields on load/read.
+// to the Builder to place the new data (right) before the hash array. Remember to check
+// for offset in-range in checkIntegrity(). Older code will then simply ignore your
+// new fields on load/read.
 // Add flag bits to the existing flags field to add features that step outside
 // of the linear versioning stream. Leave the 'spare' fields alone unless you need
 // something extraordinarily weird - they're meant to be the final escape when everything
@@ -155,8 +165,7 @@ enum {
 // To break backward compatibility intentionally, move currentVersion beyond the
 // old compatibilityLimit (and move compatibilityLimit further out).
 //
-class CodeDirectory: public Blob<CodeDirectory, 0xfade0c02> {
-       typedef SHA1 Hash;
+class CodeDirectory: public Blob<CodeDirectory, kSecCodeMagicCodeDirectory> {
 public:
        Endian<uint32_t> version;               // compatibility version
        Endian<uint32_t> flags;                 // setup and mode flags
@@ -165,24 +174,30 @@ public:
        Endian<uint32_t> nSpecialSlots; // number of special hash slots
        Endian<uint32_t> nCodeSlots;    // number of ordinary (code) hash slots
        Endian<uint32_t> codeLimit;             // limit to main image signature range
-       uint8_t hashSize;                               // size of each hash in bytes
-       uint8_t hashType;                               // type of hash (cdHashType* constants)
+       uint8_t hashSize;                               // size of each hash digest (bytes)
+       uint8_t hashType;                               // type of hash (kSecCodeSignatureHash* constants)
        uint8_t spare1;                                 // unused (must be zero)
        uint8_t pageSize;                               // log2(page size in bytes); 0 => infinite
        Endian<uint32_t> spare2;                // unused (must be zero)
+       Endian<uint32_t> scatterOffset; // offset of optional scatter vector (zero if absent)
        
        // works with the version field; see comments above
-       static const uint32_t currentVersion = 0x20001;         // "version 2"
+       static const uint32_t currentVersion = 0x20100;         // "version 2.1"
        static const uint32_t compatibilityLimit = 0x2F000;     // "version 3 with wiggle room"
        
-       void checkVersion() const;              // throws if not compatible with this code
+       static const uint32_t earliestVersion = 0x20001;        // earliest supported version
+       static const uint32_t supportsScatter = 0x20100;        // first version to support scatter option
+       
+       void checkIntegrity() const;    // throws if inconsistent or unsupported version
 
+       typedef uint32_t HashAlgorithm; // types of internal glue hashes
        typedef int Slot;                               // slot index (negative for special slots)
        typedef unsigned int SpecialSlot; // positive special slot index (not for code slots)
        
        const char *identifier() const { return at<const char>(identOffset); }
        char *identifier() { return at<char>(identOffset); }
 
+       // main hash array access
        unsigned char *operator [] (Slot slot)
        {
                assert(slot >= int(-nSpecialSlots) && slot < int(nCodeSlots));
@@ -195,36 +210,49 @@ public:
                return at<unsigned char>(hashOffset) + hashSize * slot;
        }
        
-       bool validateSlot(const void *data, size_t size, Slot slot) const;
-       bool validateSlot(UnixPlusPlus::FileDesc fd, size_t size, Slot slot) const;
+       //
+       // The main page hash array can be "scattered" across the code file
+       // by specifying an array of Scatter elements, terminated with an
+       // element whose count field is zero.
+       // The scatter vector is optional; if absent, the hash array covers
+       // a single contiguous range of pages. CodeDirectory versions below
+       // supportsScatter never have scatter vectors (they lack the scatterOffset field).
+       // 
+       struct Scatter {
+               Endian<uint32_t> count;                 // number of pages; zero for sentinel (only)
+               Endian<uint32_t> base;                  // first page number
+               Endian<uint64_t> targetOffset;  // byte offset in target
+               Endian<uint64_t> spare;                 // reserved (must be zero)
+       };
+       Scatter *scatterVector()        // first scatter vector element (NULL if none)
+               { return (version >= supportsScatter && scatterOffset) ? at<Scatter>(scatterOffset) : NULL; }
+       const Scatter *scatterVector() const
+               { return (version >= supportsScatter && scatterOffset) ? at<const Scatter>(scatterOffset) : NULL; }
+       
+public:
+       bool validateSlot(const void *data, size_t size, Slot slot) const;                      // validate memory buffer against page slot
+       bool validateSlot(UnixPlusPlus::FileDesc fd, size_t size, Slot slot) const;     // read and validate file
        bool slotIsPresent(Slot slot) const;
        
        class Builder;
+
+public:
+       static DynamicHash *hashFor(HashAlgorithm hashType);            // create a DynamicHash subclass for (hashType) digests
+       DynamicHash *getHash() const { return hashFor(this->hashType); } // make one for me
        
 protected:
-       static size_t hash(UnixPlusPlus::FileDesc fd, Hash::Byte *digest, size_t limit = 0);
-       static size_t hash(const void *data, size_t length, Hash::Byte *digest);
+       static size_t generateHash(DynamicHash *hash, UnixPlusPlus::FileDesc fd, Hashing::Byte *digest, size_t limit = 0); // hash to count or end of file
+       static size_t generateHash(DynamicHash *hash, const void *data, size_t length, Hashing::Byte *digest); // hash data buffer
        
 public:
        //
-       // Information about SpecialSlots
+       // Information about SpecialSlots.
+       // This specifies meta-data about slots themselves;
+       // it does not work with the contents of hash slots.
        //
        static const char *canonicalSlotName(SpecialSlot slot);
        static unsigned slotAttributes(SpecialSlot slot);
        IFDEBUG(static const char * const debugSlotName[]);
-       
-public:
-       //
-       // Canonical text forms for (only) the user-settable flags
-       //
-       struct FlagItem {
-               const char *name;
-               uint32_t value;
-               bool external;
-       };
-       static const FlagItem flagItems[];      // terminated with NULL item
-
-       static uint32_t textFlags(std::string text);
 };
 
 
index f55a48e7f1775653310571cce43107f2d0eaa029..825e3356af6a8daf6231f61e76bbe8d698cf1807 100644 (file)
@@ -25,7 +25,7 @@
 // cs.h - code signing core header
 //
 #include "cs.h"
-#include "cfmunge.h"
+#include <security_utilities/cfmunge.h>
 
 namespace Security {
 namespace CodeSigning {
@@ -34,13 +34,30 @@ namespace CodeSigning {
 ModuleNexus<CFObjects> gCFObjects;
 
 CFObjects::CFObjects()
-       : Code("SecCode", false),
-         StaticCode("SecStaticCode", false),
-         Requirement("SecRequirements", false),
-         CodeSigner("SecCodeSigner", false)
+       : Code("SecCode"),
+         StaticCode("SecStaticCode"),
+         Requirement("SecRequirements"),
+         CodeSigner("SecCodeSigner")
 {
 }
 
 
+OSStatus dbError(const SQLite3::Error &err)
+{
+       switch (err.error) {
+       case SQLITE_PERM:
+       case SQLITE_READONLY:
+       case SQLITE_AUTH:
+               return errSecCSSigDBDenied;
+       case SQLITE_CANTOPEN:
+       case SQLITE_EMPTY:
+       case SQLITE_NOTADB:
+               return errSecCSSigDBAccess;
+       default:
+               return SecKeychainErrFromOSStatus(err.osStatus());
+       }
+}
+
+
 }      // CodeSigning
 }      // Security
index d7957fc9e4994e0e4246a0c70619040d12773513..dd631560d5ed0cf273832680d556668c420abfe7 100644 (file)
--- a/lib/cs.h
+++ b/lib/cs.h
 #define _H_CS
 
 #include "cserror.h"
-#include <Security/CodeSigning.h>
+#include "codesigning_dtrace.h"
+#include <Security/CSCommonPriv.h>
+#include <Security/SecCodePriv.h>
+#include <Security/SecStaticCodePriv.h>
+#include <Security/SecRequirementPriv.h>
 #include <Security/SecCodeSigner.h>
 #include <Security/SecBasePriv.h>
 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
@@ -36,6 +40,7 @@
 #include <security_utilities/seccfobject.h>
 #include <security_utilities/cfclass.h>
 #include <security_utilities/errors.h>
+#include <security_utilities/sqlite++.h>
 #include <security_utilities/cfutilities.h>
 
 
@@ -70,6 +75,8 @@ extern ModuleNexus<CFObjects> gCFObjects;
 
 static inline SecCSFlags apiFlags() { return gCFObjects().flags(); }
 
+OSStatus dbError(const SQLite3::Error &err);
+
 
 //
 // Code Signing API brackets
@@ -85,9 +92,10 @@ static inline SecCSFlags apiFlags() { return gCFObjects().flags(); }
                default: return err.osStatus(); \
                }} \
     catch (const MacOSError &err) { return err.osStatus(); } \
+    catch (const SQLite3::Error &err) { return dbError(err); } \
     catch (const CommonError &err) { return SecKeychainErrFromOSStatus(err.osStatus()); } \
     catch (const std::bad_alloc &) { return memFullErr; } \
-    catch (...) { return internalComponentErr; } \
+    catch (...) { return errSecCSInternalError; } \
        return noErr;
        
 #define END_CSAPI_ERRORS \
@@ -99,16 +107,17 @@ static inline SecCSFlags apiFlags() { return gCFObjects().flags(); }
                default: return CSError::cfError(errors, err.osStatus()); \
                }} \
     catch (const MacOSError &err) { return CSError::cfError(errors, err.osStatus()); } \
+    catch (const SQLite3::Error &err) { return CSError::cfError(errors, dbError(err)); } \
     catch (const CommonError &err) { return CSError::cfError(errors, SecKeychainErrFromOSStatus(err.osStatus())); } \
     catch (const std::bad_alloc &) { return CSError::cfError(errors, memFullErr); } \
-    catch (...) { return CSError::cfError(errors, internalComponentErr); } \
+    catch (...) { return CSError::cfError(errors, errSecCSInternalError); } \
        return noErr;
        
 #define END_CSAPI1(bad)    } catch (...) { return bad; }
        
 
 //
-// A version of Required
+// A version of CodeSigning::Required
 //
 template <class T>
 static inline T &Required(T *ptr)
@@ -136,6 +145,23 @@ static inline void checkFlags(SecCSFlags flags, SecCSFlags acceptable = 0)
 }
 
 
+//
+// DTrace USDT function bracket.
+// Use like this:
+//     DTRACK(PROVIDER_PROBE_PREFIX, arguments-after-this);
+// which will call
+//     PROVIDER_PROBE_PREFIX_START(this, arguments-after-this)
+// and
+//     PROVIDER_PROBE_PREFIX_END(this)
+//
+#define DTRACK(_prefix, _obj, _args...) \
+       if (_prefix ## _START_ENABLED()) _prefix ## _START((_obj), ## _args); \
+       struct _DTFrame ## _prefix { void *me; \
+               _DTFrame ## _prefix(void *m) : me(m) { } \
+               ~_DTFrame ## _prefix() { _prefix ## _END(me); } \
+       } _dtframe##_prefix((_obj));
+
+
 }      // CodeSigning
 }      // Security
 
diff --git a/lib/csdatabase.cpp b/lib/csdatabase.cpp
new file mode 100644 (file)
index 0000000..5772ee6
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2006-2007 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@
+ */
+
+//
+// csdb - system-supported Code Signing related database interfaces
+//
+#include "csdatabase.h"
+#include "detachedrep.h"
+
+namespace Security {
+namespace CodeSigning {
+
+using namespace SQLite;
+
+
+//
+// The one and only SignatureDatabase object.
+// It auto-adapts to readonly vs. writable use.
+//
+ModuleNexus<SignatureDatabase> signatureDatabase;
+ModuleNexus<SignatureDatabaseWriter> signatureDatabaseWriter;
+
+
+//
+// Default path to the signature database.
+//
+const char SignatureDatabase::defaultPath[] = "/var/db/DetachedSignatures";
+
+
+//
+// Creation commands to initialize the system database.
+//
+const char schema[] = "\
+       create table if not exists code ( \n\
+               id integer primary key on conflict replace autoincrement not null, \n\
+               global integer null references global (id), \n\
+               identifier text not null, \n\
+               architecture integer, \n\
+               identification blob not null unique on conflict replace, \n\
+               signature blob not null, \n\
+               created text default current_timestamp \n\
+       ); \n\
+       create index if not exists identifier_index on code (identifier); \n\
+       create index if not exists architecture_index on code (architecture); \n\
+       create index if not exists id_index on code (identification); \n\
+       \n\
+       create table if not exists global ( \n\
+               id integer primary key on conflict replace autoincrement not null, \n\
+               sign_location text not null, \n\
+               signature blob null \n\
+       ); \n\
+       create index if not exists location_index on global (sign_location); \n\
+";
+
+
+
+//
+// Open the database (creating it if necessary and possible).
+// Note that this isn't creating the schema; we do that on first write.
+//
+SignatureDatabase::SignatureDatabase(const char *path, int flags)
+       : SQLite::Database(path, flags)
+{
+}
+
+SignatureDatabase::~SignatureDatabase()
+{ /* virtual */ }
+
+
+//
+// Consult the database to find code by identification blob.
+// Return the signature and (optional) global data blobs.
+//
+FilterRep *SignatureDatabase::findCode(DiskRep *rep)
+{
+       if (CFRef<CFDataRef> identification = rep->identification())
+               if (!this->empty()) {
+                       SQLite::Statement query(*this,
+                               "select code.signature, global.signature from code, global \
+                                where code.identification = ?1 and code.global = global.id;");
+                       query.bind(1) = identification.get();
+                       if (query.nextRow())
+                               return new DetachedRep(query[0].data(), query[1].data(), rep, "system");
+               }
+
+       // no joy
+       return NULL;
+}
+
+
+//
+// Given a unified detached signature blob, store its data in the database.
+// This writes exactly one Global record, plus one Code record per architecture
+// (where non-architectural code is treated as single-architecture).
+//
+void SignatureDatabaseWriter::storeCode(const BlobCore *sig, const char *location)
+{
+       Transaction xa(*this, Transaction::exclusive);  // lock out everyone
+       if (this->empty())
+               this->execute(schema);                                  // initialize schema
+       if (const EmbeddedSignatureBlob *esig = EmbeddedSignatureBlob::specific(sig)) { // architecture-less
+               int64 globid = insertGlobal(location, NULL);
+               insertCode(globid, 0, esig);
+               xa.commit();
+               return;
+       } else if (const DetachedSignatureBlob *dsblob = DetachedSignatureBlob::specific(sig)) {
+               int64 globid = insertGlobal(location, dsblob->find(0));
+               unsigned count = dsblob->count();
+               for (unsigned n = 0; n < count; n++)
+                       if (uint32_t arch = dsblob->type(n))
+                               insertCode(globid, arch, EmbeddedSignatureBlob::specific(dsblob->blob(n)));
+               xa.commit();
+               return;
+       }
+       
+       MacOSError::throwMe(errSecCSSignatureInvalid);
+
+}
+
+int64 SignatureDatabaseWriter::insertGlobal(const char *location, const BlobCore *blob)
+{
+       Statement insert(*this, "insert into global (sign_location, signature) values (?1, ?2);");
+       insert.bind(1) = location;
+       if (blob)
+               insert.bind(2).blob(blob, blob->length(), true);
+       insert();
+       return lastInsert();
+}
+
+void SignatureDatabaseWriter::insertCode(int64 globid, int arch, const EmbeddedSignatureBlob *sig)
+{
+       // retrieve binary identifier (was added by signer)
+       const BlobWrapper *ident = BlobWrapper::specific(sig->find(cdIdentificationSlot));
+       assert(ident);
+       
+       // extract CodeDirectory to get some information from it
+       const CodeDirectory *cd = CodeDirectory::specific(sig->find(cdCodeDirectorySlot));
+       assert(cd);
+
+       // write the record
+       Statement insert(*this,
+               "insert into code (global, identifier, architecture, identification, signature) values (?1, ?2, ?3, ?4, ?5);");
+       insert.bind(1) = globid;
+       insert.bind(2) = cd->identifier();
+       if (arch)
+               insert.bind(3) = arch;
+       insert.bind(4).blob(ident->data(), ident->length(), true);
+       insert.bind(5).blob(sig, sig->length(), true);
+       insert();
+}
+
+
+
+} // end namespace CodeSigning
+} // end namespace Security
diff --git a/lib/csdatabase.h b/lib/csdatabase.h
new file mode 100644 (file)
index 0000000..95f8e1b
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2007 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@
+ */
+
+//
+// csdb - system-supported Code Signing related database interfaces
+//
+#ifndef _H_CSDATABASE
+#define _H_CSDATABASE
+
+#include "diskrep.h"
+#include "sigblob.h"
+#include <Security/Security.h>
+#include <security_utilities/globalizer.h>
+#include <security_utilities/sqlite++.h>
+#include <security_utilities/cfutilities.h>
+
+
+namespace Security {
+namespace CodeSigning {
+
+namespace SQLite = SQLite3;
+
+
+class SignatureDatabase : public SQLite::Database {
+public:
+       SignatureDatabase(const char *path = defaultPath,
+               int flags = SQLITE_OPEN_READONLY);
+       virtual ~SignatureDatabase();
+       
+       FilterRep *findCode(DiskRep *rep);
+
+public:
+       static const char defaultPath[];
+};
+
+
+class SignatureDatabaseWriter : public SignatureDatabase {
+public:
+       SignatureDatabaseWriter(const char *path = defaultPath,
+               int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE)
+               : SignatureDatabase(path, flags) { }
+
+       void storeCode(const BlobCore *sig, const char *location);
+       
+private:
+       SQLite::int64 insertGlobal(const char *location, const BlobCore *blob);
+       void insertCode(SQLite::int64 globid, int arch, const EmbeddedSignatureBlob *sig);
+};
+
+
+extern ModuleNexus<SignatureDatabase> signatureDatabase;
+extern ModuleNexus<SignatureDatabaseWriter> signatureDatabaseWriter;
+
+
+} // end namespace CodeSigning
+} // end namespace Security
+
+#endif // !_H_CSDATABASE
index 8f3dba0c57225d102a77f9f65c0804fed6ce6858..1673205685855f2f094a36d8a424ae78b14a446b 100644 (file)
@@ -25,7 +25,7 @@
 // cserror.h - extended-diagnostics Code Signing errors
 //
 #include "cs.h"
-#include "cfmunge.h"
+#include <security_utilities/cfmunge.h>
 
 namespace Security {
 namespace CodeSigning {
@@ -57,6 +57,15 @@ void CSError::throwMe(OSStatus rc, CFStringRef key, CFTypeRef value)
 }
 
 
+//
+// Add a key/value pair to the dictionary
+//
+void CSError::augment(CFStringRef key, CFTypeRef value)
+{
+       mInfoDict.take(cfmake<CFDictionaryRef>("{+%O,%O=%O}", mInfoDict.get(), key, value));
+}
+
+
 //
 // Convert exception-carried error information to CFError form
 //
index e872b5087321f82aa6079917f1710514aa3635e2..d737f0f9e77634f6446b44a14311d916c4061dd5 100644 (file)
@@ -48,6 +48,8 @@ public:
        static void throwMe(OSStatus rc, CFDictionaryRef info) __attribute__ ((noreturn)); // takes dict
     static void throwMe(OSStatus rc, CFStringRef key, CFTypeRef value) __attribute__((noreturn));
 
+       void augment(CFStringRef key, CFTypeRef value);
+
        CFDictionaryRef infoDict() const { return mInfoDict; }
        
 public:
index 6840248380a6f41c7ec2c093f9a449e16b6e6c42..44f7b150d2fbb98ba448a788defae9707165a498 100644 (file)
@@ -74,8 +74,7 @@ SecCode *GenericCode::locateGuest(CFDictionaryRef attributes)
                mach_port_t subport;
                CALL(host, findGuest, guestRef(), attrPtr, attrLength,
                        &guestPath, &guestPathLength, &subport);
-               secdebug("genericcode", "%p found guest chain length=%d",
-                       this, guestPathLength);
+               CODESIGN_GUEST_LOCATE_GENERIC(this, guestPath, guestPathLength, subport);
                SecPointer<SecCode> code = this;
                for (unsigned n = 0; n < guestPathLength; n++)
                        code = new GenericCode(code, guestPath[n]);
@@ -86,15 +85,56 @@ SecCode *GenericCode::locateGuest(CFDictionaryRef attributes)
 
 
 //
-// Map a guest to its StaticCode.
+// Identify a guest by returning its StaticCode and running CodeDirectory hash.
 // This uses cshosting RPCs to ask the host (or its proxy).
 //
-SecStaticCode *GenericCode::mapGuestToStatic(SecCode *guest)
+SecStaticCode *GenericCode::identifyGuest(SecCode *guest, CFDataRef *cdhashOut)
+{
+       if (GenericCode *iguest = dynamic_cast<GenericCode *>(guest)) {
+               FilePathOut path;
+               CFRef<CFDataRef> cdhash;
+               CFDictionary attributes(errSecCSHostProtocolInvalidAttribute);
+               identifyGuest(iguest->guestRef(), path, cdhash.aref(), attributes.aref());
+               DiskRep::Context ctx;
+               if (CFNumberRef architecture = attributes.get<CFNumberRef>(kSecGuestAttributeArchitecture)) {
+                       cpu_type_t cpu = cfNumber<cpu_type_t>(architecture);
+                       if (CFNumberRef subarchitecture = attributes.get<CFNumberRef>(kSecGuestAttributeSubarchitecture))
+                               ctx.arch = Architecture(cpu, cfNumber<cpu_subtype_t>(subarchitecture));
+                       else
+                               ctx.arch = Architecture(cpu);
+               }
+               SecPointer<GenericStaticCode> code = new GenericStaticCode(DiskRep::bestGuess(path, &ctx));
+               CODESIGN_GUEST_IDENTIFY_GENERIC(iguest, iguest->guestRef(), code);
+               if (cdhash) {
+                       CODESIGN_GUEST_CDHASH_GENERIC(iguest, (void *)CFDataGetBytePtr(cdhash), CFDataGetLength(cdhash));
+                       *cdhashOut = cdhash.yield();
+               }
+               return code.yield();
+       } else
+               MacOSError::throwMe(errSecCSNotAHost);
+}
+
+// helper to drive the identifyGuest hosting IPC and return results as CF objects
+void GenericCode::identifyGuest(SecGuestRef guest, char *path, CFDataRef &cdhash, CFDictionaryRef &attributes)
 {
        if (Port host = hostingPort()) {
-               char path[MAXPATHLEN];
-               CALL(host, guestPath, safe_cast<GenericCode *>(guest)->guestRef(), path);
-               return (new GenericStaticCode(DiskRep::bestGuess(path)))->retain();
+               HashDataOut hash;
+               uint32_t hashLength;
+               XMLBlobOut attr;
+               uint32_t attrLength;
+               CALL(host, identifyGuest, guest, path, hash, &hashLength, &attr, &attrLength);
+               if (hashLength)
+                       cdhash = makeCFData(hash, hashLength);
+               if (attrLength) {
+                       CFRef<CFDataRef> attrData = makeCFData(attr, attrLength);
+                       attributes = makeCFDictionaryFrom(attrData);
+#if ROSETTA_TEST_HACK
+                       CFMutableDictionaryRef hattr = makeCFMutableDictionary(attributes);
+                       CFDictionaryAddValue(hattr, kSecGuestAttributeArchitecture, CFTempNumber(CPU_TYPE_POWERPC));
+                       CFRelease(attributes);
+                       attributes = hattr;
+#endif
+               }
        } else
                MacOSError::throwMe(errSecCSNotAHost);
 }
@@ -104,7 +144,7 @@ SecStaticCode *GenericCode::mapGuestToStatic(SecCode *guest)
 // Get the Code Signing Status Word for a Code.
 // This uses cshosting RPCs to ask the host (or its proxy).
 //
-uint32_t GenericCode::getGuestStatus(SecCode *guest)
+SecCodeStatus GenericCode::getGuestStatus(SecCode *guest)
 {
        if (Port host = hostingPort()) {
                uint32_t status;
@@ -115,6 +155,28 @@ uint32_t GenericCode::getGuestStatus(SecCode *guest)
 }
 
 
+//
+// Status changes are transmitted through the cshosting RPCs.
+//
+void GenericCode::changeGuestStatus(SecCode *iguest, SecCodeStatusOperation operation, CFDictionaryRef arguments)
+{
+       if (GenericCode *guest = dynamic_cast<GenericCode *>(iguest))
+               switch (operation) {
+               case kSecCodeOperationNull:
+                       break;
+               case kSecCodeOperationInvalidate:
+               case kSecCodeOperationSetHard:
+               case kSecCodeOperationSetKill:
+                       MacOSError::throwMe(errSecCSUnimplemented);
+                       break;
+               default:
+                       MacOSError::throwMe(errSecCSUnimplemented);
+               }
+       else
+               MacOSError::throwMe(errSecCSNoSuchCode);
+}
+
+
 //
 // Return the Hosting Port for this Code.
 // May return MACH_PORT_NULL if the code is not a code host.
@@ -128,8 +190,10 @@ uint32_t GenericCode::getGuestStatus(SecCode *guest)
 Port GenericCode::hostingPort()
 {
        if (!mHostingPort) {
-               if (staticCode()->codeDirectory()->flags & kSecCodeSignatureHost)
+               if (staticCode()->codeDirectory()->flags & kSecCodeSignatureHost) {
                        mHostingPort = getHostingPort();
+                       CODESIGN_GUEST_HOSTINGPORT(this, mHostingPort);
+               }
        }
        return mHostingPort;    
 }
index c84863929e4b148a029a88b929c97d54b777f181..5b953a1c34ed29a819a9d4b6e75a9a60ead6a033 100644 (file)
@@ -51,15 +51,18 @@ public:
        GenericCode(SecCode *host, SecGuestRef guestRef = kSecNoGuest);
        
        SecCode *locateGuest(CFDictionaryRef attributes);
-       SecStaticCode *mapGuestToStatic(SecCode *guest);
-       uint32_t getGuestStatus(SecCode *guest);
+       SecStaticCode *identifyGuest(SecCode *guest, CFDataRef *cdhash);
+       SecCodeStatus getGuestStatus(SecCode *guest);
+       void changeGuestStatus(SecCode *guest, SecCodeStatusOperation operation, CFDictionaryRef arguments);
        
        SecGuestRef guestRef() const { return mGuestRef; }
 
 protected:
        MachPlusPlus::Port hostingPort();
-       
        virtual mach_port_t getHostingPort();
+
+private:
+       void identifyGuest(SecGuestRef guest, char *path, CFDataRef &cdhash, CFDictionaryRef &attributes);
        
 private:
        MachPlusPlus::Port mHostingPort;        // cached hosting port for this Code
index bd39355d668f81f92909d1e27e94664fef29519b..9821465db9645e6482c38e0ce331cc31ee0001ad 100644 (file)
  */
 
 //
-// cskernel - Kernel implementation of the Code Signing Host Interface
+// cskernel - Kernel implementation of the Code Signing Host Interface.
+//
+// The kernel host currently supports only UNIX processes as guests.
+// It tracks then by their pid. Perhaps one day we'll get a more stable
+// means of tracking processes that doesn't involve reusing identifiers.
+//
+// The kernel host could represent non-process guests one day. One candidate
+// are Kernel Extensions.
 //
 #include "cskernel.h"
 #include "csprocess.h"
 #include "kerneldiskrep.h"
+#include "machorep.h"
 #include <libproc.h>
 #include <sys/codesign.h>
 #include <sys/param.h> // MAXPATHLEN
@@ -58,10 +66,11 @@ KernelStaticCode::KernelStaticCode()
 
 
 //
-// We locate a guest (process) by invoking a kernel service.
-// The only attributes supported are ("pid", pid_t).
-// (We could also support task ports if we liked, but those can be translated
-// to pids by the caller without trouble.)
+// Identify our guests (UNIX processes) by attribute.
+// The only supported lookup attribute is currently the pid. (We could support
+// task ports, but those can easily be mapped to pids.)
+// Note that we don't actually validate the pid here; if it's invalid, we'll notice
+// when we try to ask the kernel about it later.
 //
 SecCode *KernelCode::locateGuest(CFDictionaryRef attributes)
 {
@@ -78,14 +87,36 @@ SecCode *KernelCode::locateGuest(CFDictionaryRef attributes)
 
 //
 // We map guests to disk by calling a kernel service.
+// It is here that we verify that our user-space concept of the code identity
+// matches the kernel's idea (to defeat just-in-time switching attacks).
 //
-SecStaticCode *KernelCode::mapGuestToStatic(SecCode *iguest)
+SecStaticCode *KernelCode::identifyGuest(SecCode *iguest, CFDataRef *cdhash)
 {
        if (ProcessCode *guest = dynamic_cast<ProcessCode *>(iguest)) {
                char path[2 * MAXPATHLEN];      // reasonable upper limit
-               if (::proc_pidpath(guest->pid(), path, sizeof(path)))
-                       return (new ProcessStaticCode(DiskRep::bestGuess(path)))->retain();
-               else
+               if (::proc_pidpath(guest->pid(), path, sizeof(path))) {
+                       off_t offset;
+                       csops(guest, CS_OPS_PIDOFFSET, &offset, sizeof(offset));
+                       SecPointer<SecStaticCode> code = new ProcessStaticCode(DiskRep::bestGuess(path, offset));
+                       CODESIGN_GUEST_IDENTIFY_PROCESS(guest, guest->pid(), code);
+                       if (cdhash) {
+                               SHA1::Digest kernelHash;
+                               if (::csops(guest->pid(), CS_OPS_CDHASH, kernelHash, sizeof(kernelHash)) == -1)
+                                       switch (errno) {
+                                       case EBADEXEC:          // means "no CodeDirectory hash for this program"
+                                               *cdhash = NULL;
+                                               break;
+                                       case ESRCH:
+                                               MacOSError::throwMe(errSecCSNoSuchCode);
+                                       default:
+                                               UnixError::throwMe();
+                                       }
+                               else    // succeeded
+                                       *cdhash = makeCFData(kernelHash, sizeof(kernelHash));
+                               CODESIGN_GUEST_CDHASH_PROCESS(guest, kernelHash, sizeof(kernelHash));
+                       }
+                       return code.yield();
+               } else
                        UnixError::throwMe();
        }
        MacOSError::throwMe(errSecCSNoSuchCode);
@@ -95,41 +126,68 @@ SecStaticCode *KernelCode::mapGuestToStatic(SecCode *iguest)
 //
 // We obtain the guest's status by asking the kernel
 //
-uint32_t KernelCode::getGuestStatus(SecCode *iguest)
+SecCodeStatus KernelCode::getGuestStatus(SecCode *iguest)
 {
        if (ProcessCode *guest = dynamic_cast<ProcessCode *>(iguest)) {
                uint32_t pFlags;
-               if (::csops(guest->pid(), CS_OPS_STATUS, &pFlags, 0) == -1) {
-                       secdebug("kcode", "cannot get guest status of %p(%d) errno=%d",
-                               guest, guest->pid(), errno);
-                       switch (errno) {
-                       case ESRCH:
-                               MacOSError::throwMe(errSecCSNoSuchCode);
-                       default:
-                               UnixError::throwMe();
-                       }
-               }
+               csops(guest, CS_OPS_STATUS, &pFlags);
                secdebug("kcode", "guest %p(%d) kernel status 0x%x", guest, guest->pid(), pFlags);
-               
-#if defined(USERSPACE_VALIDATION)
-               // Former static substitute for dynamic kernel validation of executable pages.
-               // This is now done in the kernel's page-in path.
-               guest->staticCode()->validateExecutable();
-#endif //USERSPACE_VALIDATION
-               
                return pFlags;
        } else
                MacOSError::throwMe(errSecCSNoSuchCode);
 }
 
 
+//
+// We tell the kernel to make status changes
+//
+void KernelCode::changeGuestStatus(SecCode *iguest, SecCodeStatusOperation operation, CFDictionaryRef arguments)
+{
+       if (ProcessCode *guest = dynamic_cast<ProcessCode *>(iguest))
+               switch (operation) {
+               case kSecCodeOperationNull:
+                       break;
+               case kSecCodeOperationInvalidate:
+                       csops(guest, CS_OPS_MARKINVALID);
+                       break;
+               case kSecCodeOperationSetHard:
+                       csops(guest, CS_OPS_MARKHARD);
+                       break;
+               case kSecCodeOperationSetKill:
+                       csops(guest, CS_OPS_MARKKILL);
+                       break;
+               default:
+                       MacOSError::throwMe(errSecCSUnimplemented);
+               }
+       else
+               MacOSError::throwMe(errSecCSNoSuchCode);
+}
+
+
 //
 // The StaticCode for the running kernel is explicit.
 // We can't ask our own host for it, naturally.
 //
-SecStaticCode *KernelCode::getStaticCode()
+void KernelCode::identify()
 {
-       return globals().staticCode->retain();
+       mStaticCode.take(globals().staticCode->retain());
+       // the kernel isn't currently signed, so we don't get a cdHash for it
+}
+
+
+//
+// Interface to kernel csops() system call.
+//
+void KernelCode::csops(ProcessCode *proc, unsigned int op, void *addr, size_t length)
+{
+       if (::csops(proc->pid(), op, addr, length) == -1) {
+               switch (errno) {
+               case ESRCH:
+                       MacOSError::throwMe(errSecCSNoSuchCode);
+               default:
+                       UnixError::throwMe();
+               }
+       }
 }
 
 
index b5e272e3cdbb5a23a41c9939370eaa13bc38834f..c50598ee23ec828167e33ae0b139dd39abf5b942 100644 (file)
@@ -35,6 +35,9 @@ namespace Security {
 namespace CodeSigning {
 
 
+class ProcessCode;
+
+
 //
 // The nominal StaticCode representing the kernel on disk.
 // This is barely used, since we don't validate the kernel (it's the root of trust)
@@ -57,8 +60,9 @@ public:
        KernelCode();
 
        SecCode *locateGuest(CFDictionaryRef attributes);
-       SecStaticCode *mapGuestToStatic(SecCode *guest);
-       uint32_t getGuestStatus(SecCode *guest);
+       SecStaticCode *identifyGuest(SecCode *guest, CFDataRef *cdhash);
+       SecCodeStatus getGuestStatus(SecCode *guest);
+       void changeGuestStatus(SecCode *guest, SecCodeStatusOperation operation, CFDictionaryRef arguments);
        
        static KernelCode *active()             { return globals().code; }
        
@@ -71,9 +75,8 @@ public:
        static ModuleNexus<Globals> globals;
 
 protected:
-       SecStaticCode *getStaticCode();
-
-private:
+       void identify();
+       void csops(ProcessCode *proc, unsigned int op, void *addr = NULL, size_t length = 0);
 };
 
 
index 8fe0921ef2511a5110da66a8641d6561f4996b09..a5ffe620c6bb83eaa863d21dfa1a7108611e2f4c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -69,7 +69,7 @@ bool certificateHasField(SecCertificateRef cert, const CssmOid &oid)
        case noErr:
                MacOSError::check(SecCertificateReleaseFirstFieldValue(cert, &oid, value));
                return true;                                    // extension found by oid
-       case CSSMERR_CL_UNKNOWN_TAG:
+       case errSecUnknownTag:
                break;                                                  // oid not recognized by CL - continue below
        default:
                MacOSError::throwMe(rc);                // error: fail
@@ -91,6 +91,66 @@ bool certificateHasField(SecCertificateRef cert, const CssmOid &oid)
        MacOSError::check(SecCertificateReleaseFieldValues(cert, &CSSMOID_X509V3CertificateExtensionCStruct, values));
        return found;
 }
+    
+    
+//
+// Retrieve X.509 policy extension OIDs, if any.
+// This currently ignores policy qualifiers.
+//
+bool certificateHasPolicy(SecCertificateRef cert, const CssmOid &policyOid)
+{
+       bool matched = false;
+       assert(cert);
+       CSSM_DATA *data;
+       if (OSStatus rc = SecCertificateCopyFirstFieldValue(cert, &CSSMOID_CertificatePolicies, &data))
+               MacOSError::throwMe(rc);
+       if (data && data->Data && data->Length == sizeof(CSSM_X509_EXTENSION)) {
+               const CSSM_X509_EXTENSION *ext = (const CSSM_X509_EXTENSION *)data->Data;
+               assert(ext->format == CSSM_X509_DATAFORMAT_PARSED);
+               const CE_CertPolicies *policies = (const CE_CertPolicies *)ext->value.parsedValue;
+               if (policies)
+                       for (unsigned int n = 0; n < policies->numPolicies; n++) {
+                               const CE_PolicyInformation &cp = policies->policies[n];
+                               if (cp.certPolicyId == policyOid) {
+                                       matched = true;
+                                       break;
+                               }
+                       }
+       }
+       SecCertificateReleaseFirstFieldValue(cert, &CSSMOID_PolicyConstraints, data);
+       return matched;
+}
+
+
+//
+// Copyfile
+//
+Copyfile::Copyfile()
+{
+       if (!(mState = copyfile_state_alloc()))
+               UnixError::throwMe();
+}
+       
+void Copyfile::set(uint32_t flag, const void *value)
+{
+       check(::copyfile_state_set(mState, flag, value));
+}
+
+void Copyfile::get(uint32_t flag, void *value)
+{
+       check(::copyfile_state_set(mState, flag, value));
+}
+       
+void Copyfile::operator () (const char *src, const char *dst, copyfile_flags_t flags)
+{
+       check(::copyfile(src, dst, mState, flags));
+}
+
+void Copyfile::check(int rc)
+{
+       if (rc < 0)
+               UnixError::throwMe();
+}
 
 
 } // end namespace CodeSigning
index 13c50742f91bcee0ca483a237b8cd12866daa9d1..fa72d6ab8ef6c6d61e48280b6ad77c2063b1e06d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -32,8 +32,9 @@
 
 #include <Security/Security.h>
 #include <security_utilities/hashing.h>
+#include <security_utilities/unix++.h>
 #include <security_cdsa_utilities/cssmdata.h>
-
+#include <copyfile.h>
 
 namespace Security {
 namespace CodeSigning {
@@ -47,11 +48,101 @@ void hashOfCertificate(const void *certData, size_t certLength, SHA1::Digest dig
 void hashOfCertificate(SecCertificateRef cert, SHA1::Digest digest);
 
 
+//
+// Calculate hashes of (a section of) a file.
+// Starts at the current file position.
+// Extends to end of file, or (if limit > 0) at most limit bytes.
+// Returns number of bytes digested.
+//
+template <class _Hash>
+size_t hashFileData(const char *path, _Hash *hasher)
+{
+       UnixPlusPlus::AutoFileDesc fd(path);
+       return hashFileData(fd, hasher);
+}
+
+template <class _Hash>
+size_t hashFileData(UnixPlusPlus::FileDesc fd, _Hash *hasher, size_t limit = 0)
+{
+       unsigned char buffer[4096];
+       size_t total = 0;
+       for (;;) {
+               size_t size = sizeof(buffer);
+               if (limit && limit < size)
+                       size = limit;
+               size_t got = fd.read(buffer, size);
+               total += got;
+               if (fd.atEnd())
+                       break;
+               hasher->update(buffer, got);
+               if (limit && (limit -= got) == 0)
+                       break;
+       }
+       return total;
+}
+
+
 //
 // 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);
+
+
+//
+// Encapsulation of the copyfile(3) API.
+// This is slated to go into utilities once stable.
+//
+class Copyfile {
+public:
+       Copyfile();
+       ~Copyfile()     { copyfile_state_free(mState); }
+       
+       operator copyfile_state_t () const { return mState; }
+       
+       void set(uint32_t flag, const void *value);
+       void get(uint32_t flag, void *value);
+       
+       void operator () (const char *src, const char *dst, copyfile_flags_t flags);
+
+private:
+       void check(int rc);
+       
+private:
+       copyfile_state_t mState;
+};
+
+
+//
+// A reliable uid set/reset bracket
+//
+class UidGuard {
+public:
+       UidGuard() : mPrevious(-1) { }
+       UidGuard(uid_t uid) : mPrevious(-1) { seteuid(uid); }
+       ~UidGuard()
+       {
+               if (active())
+                       UnixError::check(::seteuid(mPrevious));
+       }
+       
+       bool seteuid(uid_t uid)
+       {
+               if (uid == geteuid())
+                       return true;    // no change, don't bother the kernel
+               if (!active())
+                       mPrevious = ::geteuid();
+               return ::seteuid(uid) == 0;
+       }
+       
+       bool active() const { return mPrevious != uid_t(-1); }
+       operator bool () const { return active(); }
+       uid_t saved() const { assert(active()); return mPrevious; }
+
+private:
+       uid_t mPrevious;
+};
 
 
 } // end namespace CodeSigning
diff --git a/lib/detachedrep.cpp b/lib/detachedrep.cpp
new file mode 100644 (file)
index 0000000..ed59e58
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2006-2008 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@
+ */
+
+//
+// detachedrep - prefix diskrep representing a detached signature stored in a file
+//
+#include "detachedrep.h"
+
+
+namespace Security {
+namespace CodeSigning {
+
+
+//
+// We construct a DetachedRep from the data blob of the detached signature
+// and a reference of the original DiskRep we chain to.
+// We accept an EmbeddedSignatureBlob (for a non-architected signature)
+// or a DetachedSignatureBlob (for architected signatures) that is a SuperBlob
+// of EmbeddedSignatureBlobs.
+//
+DetachedRep::DetachedRep(CFDataRef sig, DiskRep *orig, const std::string &source)
+       : FilterRep(orig), mSig(sig), mSource(source)
+{
+       const BlobCore *sigBlob = reinterpret_cast<const BlobCore *>(CFDataGetBytePtr(sig));
+       if (sigBlob->is<EmbeddedSignatureBlob>()) {             // architecture-less
+               if (mArch = EmbeddedSignatureBlob::specific(sigBlob)) {
+                       mGlobal = NULL;
+                       CODESIGN_DISKREP_CREATE_DETACHED(this, orig, (char*)source.c_str(), NULL);
+                       return;
+               }
+       } else if (sigBlob->is<DetachedSignatureBlob>())        // architecture collection
+               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))) {
+                                                       CODESIGN_DISKREP_CREATE_DETACHED(this, orig, (char*)source.c_str(), (void*)mGlobal);
+                                                       return;
+                                               }
+       MacOSError::throwMe(errSecCSSignatureInvalid);
+}
+
+
+//
+// Here's a version to construct a DetachedRep if we already have the right architecture
+// and (optional) associated global blob. Just take them.
+//
+DetachedRep::DetachedRep(CFDataRef sig, CFDataRef gsig, DiskRep *orig, const std::string &source)
+       : FilterRep(orig), mSig(sig), mGSig(gsig), mSource(source)
+{
+       const BlobCore *sigBlob = reinterpret_cast<const BlobCore *>(CFDataGetBytePtr(sig));
+       mArch = EmbeddedSignatureBlob::specific(sigBlob);
+       if (!mArch)
+               MacOSError::throwMe(errSecCSSignatureInvalid);
+       if (gsig) {
+               const BlobCore *gsigBlob = reinterpret_cast<const BlobCore *>(CFDataGetBytePtr(gsig));
+               mGlobal = EmbeddedSignatureBlob::specific(gsigBlob);
+               if (!mGlobal)
+                       MacOSError::throwMe(errSecCSSignatureInvalid);
+       } else
+               mGlobal = NULL;
+       CODESIGN_DISKREP_CREATE_DETACHED(this, orig, (char*)source.c_str(), (void*)mGlobal);
+}
+
+
+//
+// We look up components by first checking for a per-architecture item,
+// then for a global item in the detached signature, and finally falling
+// back on the original DiskRep (for static components).
+//
+CFDataRef DetachedRep::component(CodeDirectory::SpecialSlot slot)
+{
+       if (CFDataRef result = mArch->component(slot))
+               return result;
+       if (mGlobal)
+               if (CFDataRef result = mGlobal->component(slot))
+                       return result;
+       return this->base()->component(slot);
+}
+
+
+} // end namespace CodeSigning
+} // end namespace Security
diff --git a/lib/detachedrep.h b/lib/detachedrep.h
new file mode 100644 (file)
index 0000000..9802b2e
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2006-2008 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@
+ */
+
+//
+// detachedrep - prefix diskrep representing a detached signature stored in a file
+//
+#ifndef _H_DETACHEDREP
+#define _H_DETACHEDREP
+
+#include "diskrep.h"
+#include "sigblob.h"
+
+namespace Security {
+namespace CodeSigning {
+
+
+//
+// We use a DetachedRep to interpose (filter) the genuine DiskRep representing
+// the code on disk, *if* a detached signature was set on this object. In this
+// situation, mRep will point to a (2 element) chain of DiskReps.
+//
+// This is a neat way of dealing with the (unusual) detached-signature case
+// without disturbing things unduly. Consider DetachedDiskRep to be closely
+// married to SecStaticCode; it's unlikely to work right if you use it elsewhere.
+//
+// Note that there's no *writing* code here. Writing detached signatures is handled
+// specially in the signing code.
+//
+class DetachedRep : public FilterRep {
+public:
+       DetachedRep(CFDataRef sig, DiskRep *orig, const std::string &source); // SuperBlob of all architectures
+       DetachedRep(CFDataRef sig, CFDataRef gsig, DiskRep *orig, const std::string &source); // one architecture + globals
+       
+       CFDataRef component(CodeDirectory::SpecialSlot slot);
+       
+       const std::string &source() const { return mSource; }
+
+private:
+       CFRef<CFDataRef> mSig, mGSig;
+       const EmbeddedSignatureBlob *mArch;             // current architecture; points into mSignature
+       const EmbeddedSignatureBlob *mGlobal;   // shared elements; points into mSignature
+       std::string mSource;                                    // source description (readable)
+};
+
+
+} // end namespace CodeSigning
+} // end namespace Security
+
+#endif // !_H_DETACHEDREP
index 5db86a395ffe0c2e7c7e99b576cf93d177be13a2..395402c65f8650f3ac5fa9427e880ac24af3f25d 100644 (file)
@@ -32,7 +32,7 @@
 #include "filediskrep.h"
 #include "bundlediskrep.h"
 #include "cfmdiskrep.h"
-#include "foreigndiskrep.h"
+#include "slcrep.h"
 
 
 namespace Security {
@@ -49,7 +49,9 @@ DiskRep::DiskRep()
 }
 
 DiskRep::~DiskRep()
-{ /* virtual */ }
+{
+       CODESIGN_DISKREP_DESTROY(this);
+}
 
 
 //
@@ -66,7 +68,13 @@ DiskRep *DiskRep::base()
 //
 DiskRep::Writer *DiskRep::writer()
 {
-       MacOSError::throwMe(errSecCSBadObjectFormat);
+       MacOSError::throwMe(errSecCSUnimplemented);
+}
+
+
+void DiskRep::Writer::addDiscretionary(CodeDirectory::Builder &)
+{
+       // do nothing
 }
 
 
@@ -78,25 +86,38 @@ DiskRep::Writer *DiskRep::writer()
 // fine in ordinary use. If you happen to know what you're looking at
 // (say, a bundle), then just create the suitable subclass of DiskRep directly.
 // That's quite legal.
+// The optional context argument can provide additional information that guides the guess.
 //
-DiskRep *DiskRep::bestGuess(const char *path)
+DiskRep *DiskRep::bestGuess(const char *path, const Context *ctx)
 {
        try {
-    struct stat st;
-    if (::stat(path, &st))
-        UnixError::throwMe();
+               if (!(ctx && ctx->fileOnly)) {
+                       struct stat st;
+                       if (::stat(path, &st))
+                               UnixError::throwMe();
+                               
+                       // if it's a directory, assume it's a bundle
+                       if ((st.st_mode & S_IFMT) == S_IFDIR)   // directory - assume bundle
+                               return new BundleDiskRep(path, ctx);
+                       
+                       // see if it's the main executable of a recognized bundle
+                       if (CFRef<CFURLRef> pathURL = makeCFURL(path))
+                               if (CFRef<CFBundleRef> bundle = _CFBundleCreateWithExecutableURLIfMightBeBundle(NULL, pathURL))
+                                               return new BundleDiskRep(bundle, ctx);
+               }
                
-       // if it's a directory, assume it's a bundle
-    if ((st.st_mode & S_IFMT) == S_IFDIR)      // directory - assume bundle
-               return new BundleDiskRep(path);
-       
-       // see if it's the main executable of a recognized bundle
-       if (CFRef<CFURLRef> pathURL = makeCFURL(path))
-               if (CFRef<CFBundleRef> bundle = _CFBundleCreateWithExecutableURLIfMightBeBundle(NULL, pathURL))
-                               return new BundleDiskRep(bundle);
-       
-       // follow the file choosing rules
-       return bestFileGuess(path);
+               // try the various single-file representations
+               AutoFileDesc fd(path, O_RDONLY);
+               if (MachORep::candidate(fd))
+                       return new MachORep(path, ctx);
+               if (CFMDiskRep::candidate(fd))
+                       return new CFMDiskRep(path);
+               if (DYLDCacheRep::candidate(fd))
+                       return new DYLDCacheRep(path);
+
+               // ultimate fallback - the generic file representation
+               return new FileDiskRep(path);
+
        } catch (const CommonError &error) {
                switch (error.unixError()) {
                case ENOENT:
@@ -108,17 +129,43 @@ DiskRep *DiskRep::bestGuess(const char *path)
 }
 
 
-DiskRep *DiskRep::bestFileGuess(const char *path)
+DiskRep *DiskRep::bestFileGuess(const char *path, const Context *ctx)
 {
-       AutoFileDesc fd(path, O_RDONLY);
-       if (MachORep::candidiate(fd))
-               return new MachORep(path);
-       if (CFMDiskRep::candidiate(fd))
-               return new CFMDiskRep(path);
-       if (ForeignDiskRep::candidate(fd))
-               return new ForeignDiskRep(path);
+       Context dctx;
+       if (ctx)
+               dctx = *ctx;
+       dctx.fileOnly = true;
+       return bestGuess(path, &dctx);
+}
 
-       return new FileDiskRep(path);
+
+//
+// Given a main executable known to be a Mach-O binary, and an offset into
+// the file of the actual architecture desired (of a Universal file),
+// produce a suitable MachORep.
+// This function does not consider non-MachO binaries. It does however handle
+// bundles with Mach-O main executables correctly.
+//
+DiskRep *DiskRep::bestGuess(const char *path, size_t archOffset)
+{
+       try {
+               // is it the main executable of a bundle?
+               if (CFRef<CFURLRef> pathURL = makeCFURL(path))
+                       if (CFRef<CFBundleRef> bundle = _CFBundleCreateWithExecutableURLIfMightBeBundle(NULL, pathURL)) {
+                               Context ctx; ctx.offset = archOffset;
+                               return new BundleDiskRep(bundle, &ctx); // ask bundle to make bundle-with-MachO-at-offset
+                       }
+               // else, must be a Mach-O binary
+               Context ctx; ctx.offset = archOffset;
+               return new MachORep(path, &ctx);
+       } catch (const CommonError &error) {
+               switch (error.unixError()) {
+               case ENOENT:
+                       MacOSError::throwMe(errSecCSStaticCodeNotFound);
+               default:
+                       throw;
+               }
+       }
 }
 
 
@@ -130,31 +177,16 @@ string DiskRep::resourcesRootPath()
        return "";              // has no resources directory
 }
 
-CFDictionaryRef DiskRep::defaultResourceRules()
-{
-       return NULL;    // none
-}
-
 void DiskRep::adjustResources(ResourceBuilder &builder)
 {
        // do nothing
 }
 
-const Requirements *DiskRep::defaultRequirements(const Architecture *)
-{
-       return NULL;    // none
-}
-
 Universal *DiskRep::mainExecutableImage()
 {
        return NULL;    // no Mach-O executable
 }
 
-size_t DiskRep::pageSize()
-{
-       return monolithicPageSize;      // unpaged (monolithic)
-}
-
 size_t DiskRep::signingBase()
 {
        return 0;               // whole file (start at beginning)
@@ -173,6 +205,72 @@ void DiskRep::flush()
 }
 
 
+CFDictionaryRef DiskRep::defaultResourceRules(const SigningContext &)
+{
+       return NULL;    // none
+}
+
+const Requirements *DiskRep::defaultRequirements(const Architecture *, const SigningContext &)
+{
+       return NULL;    // none
+}
+
+size_t DiskRep::pageSize(const SigningContext &)
+{
+       return monolithicPageSize;      // unpaged (monolithic)
+}
+
+
+//
+// Given some string (usually a pathname), derive a suggested signing identifier
+// in a canonical way (so there's some consistency).
+//
+// This is a heuristic. First we lop off any leading directories and final (non-numeric)
+// extension. Then we walk backwards, eliminating numeric extensions except the first one.
+// Thus, libfrotz7.3.5.dylib becomes libfrotz7, mumble.77.plugin becomes mumble.77,
+// and rumble.rb becomes rumble. This isn't perfect, but it ought to handle 98%+ of
+// the common varieties out there. Specify an explicit identifier for the oddballs.
+//
+// This is called by the various recommendedIdentifier() methods, who are
+// free to modify or override it.
+//
+// Note: We use strchr("...") instead of is*() here because we do not
+// wish to be influenced by locale settings.
+//
+std::string DiskRep::canonicalIdentifier(const std::string &name)
+{
+       string s = name;
+       string::size_type p;
+       
+       // lop off any directory prefixes
+       if ((p = s.rfind('/')) != string::npos)
+               s = s.substr(p+1);
+
+       // remove any final extension (last dot) unless it's numeric
+       if ((p = s.rfind('.')) != string::npos && !strchr("0123456789", s[p+1]))
+               s = s.substr(0, p);
+       
+       // eat numeric suffixes except the first one; roughly:
+       // foo.2.3.4 => foo.2, foo2.3 => foo2, foo.9 => foo.9, foo => foo
+       if (strchr("0123456789.", s[0]))                        // starts with digit or .
+               return s;                                                               // ... so don't mess with it
+       p = s.size()-1;
+       // foo3.5^, foo.3.5^, foo3^, foo.3^, foo^
+       while (strchr("0123456789.", s[p]))
+               p--;
+       // fo^o3.5, fo^o.3.5, fo^o3, fo^o.3, fo^o
+       p++;
+       // foo^3.5, foo^.3.5, foo^3, foo^.3, foo^
+       if (s[p] == '.')
+               p++;
+       // foo^3.5, foo.^3.5, foo^3, foo.^3, foo^
+       while (p < s.size() && strchr("0123456789", s[p]))
+               p++;
+       // foo3^.5, foo.3^.5, foo3^, foo.3^, foo^
+       return s.substr(0, p);
+}
+
+
 //
 // Writers
 //
@@ -190,6 +288,11 @@ uint32_t DiskRep::Writer::attributes() const
 void DiskRep::Writer::flush()
 { /* do nothing */ }
 
+void DiskRep::Writer::remove()
+{
+       MacOSError::throwMe(errSecCSNotSupported);
+}
+
 
 } // end namespace CodeSigning
 } // end namespace Security
index 4442320db2c382608d7d583519037dfa5e345e7f..5d9c2d302769b2f535e2fe5da4f10d09e1c2baa3 100644 (file)
 
 #include "cs.h"
 #include "codedirectory.h"
+#include "cdbuilder.h"
 #include "requirement.h"
 #include "resources.h"
-#include "macho++.h"           // for class Architecture
+#include <security_utilities/macho++.h>                // for class Architecture
 #include <security_utilities/refcount.h>
 #include <security_utilities/superblob.h>
 #include <CoreFoundation/CFData.h>
@@ -47,26 +48,33 @@ namespace CodeSigning {
 // the details of the storage locations or formats.
 //
 class DiskRep : public RefCount {
+public:
+       class SigningContext;
+       
 public:
        DiskRep();
        virtual ~DiskRep();
        virtual DiskRep *base();
        virtual CFDataRef component(CodeDirectory::SpecialSlot slot) = 0; // fetch component
+       virtual CFDataRef identification() = 0;                                 // binary lookup identifier
        virtual std::string mainExecutablePath() = 0;                   // path to main executable
        virtual CFURLRef canonicalPath() = 0;                                   // path to whole code
-       virtual std::string recommendedIdentifier() = 0;                // default identifier
-       virtual std::string resourcesRootPath();                                // resource directory if any
-       virtual CFDictionaryRef defaultResourceRules();                 // default resource rules
-       virtual void adjustResources(ResourceBuilder &builder); // adjust resource rule set
-       virtual const Requirements *defaultRequirements(const Architecture *arch); // default internal requirements
-       virtual Universal *mainExecutableImage();                               // binary if Mach-O/Universal
-       virtual size_t pageSize();                                                              // default main executable page size
-       virtual size_t signingBase();                                                   // start offset of signed area in main executable
+       virtual std::string resourcesRootPath();                                // resource directory if any [none]
+       virtual void adjustResources(ResourceBuilder &builder); // adjust resource rule set [no change]
+       virtual Universal *mainExecutableImage();                               // Mach-O image if Mach-O based [null]
+       virtual size_t signingBase();                                                   // start offset of signed area in main executable [zero]
        virtual size_t signingLimit() = 0;                                              // size of signed area in main executable
        virtual std::string format() = 0;                                               // human-readable type string
-       virtual CFArrayRef modifiedFiles();                                             // list of files modified by signing
-       virtual UnixPlusPlus::FileDesc &fd() = 0;                               // a cached fd for main executable file
+       virtual CFArrayRef modifiedFiles();                                             // list of files modified by signing [main execcutable only]
+       virtual UnixPlusPlus::FileDesc &fd() = 0;                               // a cached file descriptor for main executable file
        virtual void flush();                                                                   // flush caches (refetch as needed)
+
+       // default values for signing operations
+       virtual std::string recommendedIdentifier(const SigningContext &ctx) = 0; // default identifier
+       virtual CFDictionaryRef defaultResourceRules(const SigningContext &ctx); // default resource rules [none]
+       virtual const Requirements *defaultRequirements(const Architecture *arch,
+               const SigningContext &ctx);                                                     // default internal requirements [none]
+       virtual size_t pageSize(const SigningContext &ctx);             // default main executable page size [infinite, i.e. no paging]
        
        bool mainExecutableIsMachO() { return mainExecutableImage() != NULL; }
        
@@ -76,15 +84,43 @@ public:
 
 public:
        class Writer;
-       virtual Writer *writer();
+       virtual Writer *writer();                                                               // Writer factory
 
 public:
-       static DiskRep *bestGuess(const char *path);                    // canonical heuristic, any path
-       static DiskRep *bestFileGuess(const char *path);                // canonical heuristic, single file only
-       
-       static DiskRep *bestGuess(const std::string &path)              { return bestGuess(path.c_str()); }
-       static DiskRep *bestFileGuess(const std::string &path)  { return bestFileGuess(path.c_str()); }
-       
+       // optional information that might be used to create a suitable DiskRep. All optional
+       struct Context {
+               Context() : arch(Architecture::none), version(NULL), offset(0), fileOnly(false), inMemory(NULL) { }
+               Architecture arch;                      // explicit architecture (choose amongst universal variants)
+               const char *version;            // bundle version (string)
+               off_t offset;                           // explicit file offset
+               bool fileOnly;                          // only consider single-file representations (no bundles etc.)
+               const void *inMemory;           // consider using in-memory copy at this address
+       };
+
+       static DiskRep *bestGuess(const char *path, const Context *ctx = NULL); // canonical heuristic, any path
+       static DiskRep *bestFileGuess(const char *path, const Context *ctx = NULL); // ctx (if any) + fileOnly
+       static DiskRep *bestGuess(const char *path, size_t archOffset); // Mach-O at given file offset only
+
+       // versions using std::string paths (merely a convenience)
+       static DiskRep *bestGuess(const std::string &path, const Context *ctx = NULL)
+               { return bestGuess(path.c_str(), ctx); }
+       static DiskRep *bestGuess(const std::string &path, size_t archOffset) { return bestGuess(path.c_str(), archOffset); }
+       static DiskRep *bestFileGuess(const std::string &path, const Context *ctx = NULL) { return bestFileGuess(path.c_str(), ctx); }
+
+public:
+       // see DiskRep::Writer docs for why this is here
+       class SigningContext {
+       protected:
+               SigningContext() { }
+
+       public:
+               virtual std::string sdkPath(const std::string &path) const = 0;
+               virtual bool isAdhoc() const = 0;
+       };
+
+protected:
+       // canonically derive a suggested signing identifier from some string
+       static std::string canonicalIdentifier(const std::string &name);
        
 public:
        static const size_t segmentedPageSize = 4096;   // default page size for system-paged signatures
@@ -99,12 +135,23 @@ public:
 // that supports writing signing data to a place inside the code needs to implement
 // a subclass of Writer and return an instance in the DiskRep::writer() method when asked.
 //
+// The Writer class is subclassed interestingly by the Mach-O multi-architecture signing code,
+// which is handled as a special case. This means that not all Writer subclass objects were made
+// by DiskRep::writer, and it is unwise to assume so.
+//
+// Note that the methods that provide defaults for signing operations are in DiskRep rather
+// than here. That's because writers abstract data *sending*, and are virtual on management
+// of stored data, while DiskRep is virtual on the existing code object, which is where
+// we get our defaults from.
+//
 class DiskRep::Writer : public RefCount {
 public:
        Writer(uint32_t attrs = 0);
        virtual ~Writer();
        virtual void component(CodeDirectory::SpecialSlot slot, CFDataRef data) = 0;
        virtual uint32_t attributes() const;
+       virtual void addDiscretionary(CodeDirectory::Builder &builder);
+       virtual void remove();
        virtual void flush();
 
        bool attribute(uint32_t attr) const             { return mAttributes & attr; }
@@ -127,6 +174,43 @@ enum {
 };
 
 
+//
+// A prefix DiskRep that filters (only) signature-dependent behavior and passes
+// all code-dependent behavior off to an underlying (different) DiskRep.
+// FilterRep subclasses are typically "stacked" on top of their base DiskRep, and
+// then used in their place.
+//
+class FilterRep : public DiskRep {
+public:
+       FilterRep(DiskRep *orig) : mOriginal(orig) { }
+       
+       DiskRep *base()                                                 { return mOriginal; }
+       
+       // things that look at signature components are filtered
+       CFDataRef component(CodeDirectory::SpecialSlot slot) = 0;
+
+       // the rest of the virtual behavior devolves on the original DiskRep
+       CFDataRef identification()                              { return mOriginal->identification(); }
+       std::string mainExecutablePath()                { return mOriginal->mainExecutablePath(); }
+       CFURLRef canonicalPath()                                { return mOriginal->canonicalPath(); }
+       std::string resourcesRootPath()                 { return mOriginal->resourcesRootPath(); }
+       Universal *mainExecutableImage()                { return mOriginal->mainExecutableImage(); }
+       size_t signingBase()                                    { return mOriginal->signingBase(); }
+       size_t signingLimit()                                   { return mOriginal->signingLimit(); }
+       std::string format()                                    { return mOriginal->format(); }
+       UnixPlusPlus::FileDesc &fd()                    { return mOriginal->fd(); }
+       void flush()                                                    { return mOriginal->flush(); }
+       
+       std::string recommendedIdentifier(const SigningContext &ctx)
+               { return mOriginal->recommendedIdentifier(ctx); }
+       CFDictionaryRef defaultResourceRules(const SigningContext &ctx)
+               { return mOriginal->defaultResourceRules(ctx); }
+
+private:
+       RefPointer<DiskRep> mOriginal;                  // underlying representation
+};
+
+
 } // end namespace CodeSigning
 } // end namespace Security
 
index f8a40324671828d365cb536e18959b70f030c7b8..7a098c22a4577c5409923df269096732bff590d5 100644 (file)
@@ -22,7 +22,7 @@
  */
 #include "filediskrep.h"
 #include "StaticCode.h"
-#include "macho++.h"   // may perhaps move into security_utilities...
+#include <security_utilities/macho++.h>
 #include <cstring>
 
 
@@ -38,6 +38,7 @@ using namespace UnixPlusPlus;
 FileDiskRep::FileDiskRep(const char *path)
        : SingleDiskRep(path)
 {
+       CODESIGN_DISKREP_CREATE_FILE(this, (char*)path);
 }
 
 
@@ -57,12 +58,23 @@ string FileDiskRep::attrName(const char *name)
 CFDataRef FileDiskRep::getAttribute(const char *name)
 {
        string aname = attrName(name);
-       ssize_t length = fd().getAttrLength(aname);
-       if (length < 0)
-               return NULL;            // no such attribute
-       CFMallocData buffer(length);
-       fd().getAttr(aname, buffer, length);
-       return buffer;
+       try {
+               ssize_t length = fd().getAttrLength(aname);
+               if (length < 0)
+                       return NULL;            // no such attribute
+               CFMallocData buffer(length);
+               fd().getAttr(aname, buffer, length);
+               return buffer;
+       } catch (const UnixError &err) {
+               // recover some errors that happen in (relatively) benign circumstances
+               switch (err.error) {
+               case ENOTSUP:   // no extended attributes on this filesystem
+               case EPERM:             // filesystem objects to name(?)
+                       return NULL;
+               default:
+                       throw;
+               }
+       }
 }
 
 
@@ -86,7 +98,7 @@ CFDataRef FileDiskRep::component(CodeDirectory::SpecialSlot slot)
 // starts with the magic "#!" script marker, we do suggest that this should
 // be a valid host if we can reasonably make out what that is.
 //
-const Requirements *FileDiskRep::defaultRequirements(const Architecture *)
+const Requirements *FileDiskRep::defaultRequirements(const Architecture *, const SigningContext &ctx)
 {
        // read start of file
        char buffer[256];
@@ -96,19 +108,20 @@ const Requirements *FileDiskRep::defaultRequirements(const Architecture *)
                if (length == sizeof(buffer))
                        length--;
                buffer[length] = '\0';
-               char *path = buffer + 2;
-               path[strcspn(path, " \t\n\r\f")] = '\0';
-               secdebug("filediskrep", "looks like a script for %s", path);
-               if (path[1])
+               char *cmd = buffer + 2;
+               cmd[strcspn(cmd, " \t\n\r\f")] = '\0';
+               secdebug("filediskrep", "looks like a script for %s", cmd);
+               if (cmd[1])
                        try {
                                // find path on disk, get designated requirement (if signed)
+                               string path = ctx.sdkPath(cmd);
                                if (RefPointer<DiskRep> rep = DiskRep::bestFileGuess(path))
                                        if (SecPointer<SecStaticCode> code = new SecStaticCode(rep))
                                                if (const Requirement *req = code->designatedRequirement()) {
+                                                       CODESIGN_SIGN_DEP_INTERP(this, (char*)cmd, (void*)req);
                                                        // package up as host requirement and return that
                                                        Requirements::Maker maker;
                                                        maker.add(kSecHostRequirementType, req->clone());
-                                                       secdebug("filediskrep", "made a scripting host requirement");
                                                        return maker.make();
                                                }
                        } catch (...) {
@@ -142,8 +155,8 @@ DiskRep::Writer *FileDiskRep::writer()
 void FileDiskRep::Writer::component(CodeDirectory::SpecialSlot slot, CFDataRef data)
 {
        try {
-       fd().setAttr(attrName(CodeDirectory::canonicalSlotName(slot)),
-               CFDataGetBytePtr(data), CFDataGetLength(data));
+               fd().setAttr(attrName(CodeDirectory::canonicalSlotName(slot)),
+                       CFDataGetBytePtr(data), CFDataGetLength(data));
        } catch (const UnixError &error) {
                if (error.error == ERANGE)
                        MacOSError::throwMe(errSecCSCMSTooLarge);
@@ -152,6 +165,18 @@ void FileDiskRep::Writer::component(CodeDirectory::SpecialSlot slot, CFDataRef d
 }
 
 
+//
+// Clear all signing data
+//
+void FileDiskRep::Writer::remove()
+{
+       for (CodeDirectory::SpecialSlot slot = 0; slot < cdSlotCount; slot++)
+               if (const char *name = CodeDirectory::canonicalSlotName(slot))
+                       fd().removeAttr(attrName(name));
+       fd().removeAttr(attrName(kSecCS_SIGNATUREFILE));
+}
+
+
 //
 // We are NOT the preferred store for components because our approach
 // (extended attributes) suffers from some serious limitations.
index e84b455baf28d5aa697de5d4f9485d6718f1641f..70410eeaef47ae3a4e17b884440692e4aab35ec6 100644 (file)
@@ -56,9 +56,10 @@ public:
        FileDiskRep(const char *path);
        
        CFDataRef component(CodeDirectory::SpecialSlot slot);
-       const Requirements *defaultRequirements(const Architecture *arch);
        std::string format();
        
+       const Requirements *defaultRequirements(const Architecture *arch, const SigningContext &ctx);
+       
 public:
        DiskRep::Writer *writer();
        class Writer;
@@ -77,6 +78,7 @@ class FileDiskRep::Writer : public SingleDiskRep::Writer {
        friend class FileDiskRep;
 public:
        void component(CodeDirectory::SpecialSlot slot, CFDataRef data);
+       void remove();
        bool preferredStore();
 
 protected:
diff --git a/lib/foreigndiskrep.cpp b/lib/foreigndiskrep.cpp
deleted file mode 100644 (file)
index 89ac70f..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (c) 2007 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@
- */
-//
-// foreigndiskrep - foreign executable disk representation
-//
-#include "foreigndiskrep.h"
-#include <cstring>
-
-
-namespace Security {
-namespace CodeSigning {
-
-using namespace UnixPlusPlus;
-
-
-//
-// Everything's lazy in here
-//
-ForeignDiskRep::ForeignDiskRep(const char *path)
-       : SingleDiskRep(path), mTriedRead(false)
-{
-}
-
-ForeignDiskRep::~ForeignDiskRep()
-{
-       if (mTriedRead)
-               delete mSigningData;
-}
-
-
-//
-// Foreign filter heuristic
-//
-bool ForeignDiskRep::candidate(FileDesc &fd)
-{
-       static const char magicMarker[] = "MZ\0\0\0\0\0\0\0\0\0\0PE\0\0 \b";
-       static const size_t magicLength = 18;
-       char marker[magicLength];
-       return fd.read(marker, magicLength, 0) == magicLength
-               && !memcmp(marker, magicMarker, magicLength);
-}
-
-
-//
-// Extract and return a component by slot number.
-// If we have a Mach-O binary, use embedded components.
-// Otherwise, look for and return the extended attribute, if any.
-//
-CFDataRef ForeignDiskRep::component(CodeDirectory::SpecialSlot slot)
-{
-       if (!mTriedRead)
-               readSigningData();
-       if (mSigningData)
-               return mSigningData->component(slot);
-       else
-               return NULL;
-}
-
-
-//
-// Default to system-paged signing
-//
-size_t ForeignDiskRep::pageSize()
-{
-       return segmentedPageSize;
-}
-
-
-//
-// Various other aspects of our DiskRep personality.
-//
-string ForeignDiskRep::format()
-{
-       return "foreign binary";
-}
-
-
-//
-// Discard cached information
-//
-void ForeignDiskRep::flush()
-{
-       mTriedRead = false;
-       ::free(mSigningData);
-}
-
-
-//
-// Locate, read, and cache embedded signing data from the foreign binary.
-//
-void ForeignDiskRep::readSigningData()
-{
-       if (!mTriedRead) {                              // try it once
-               mSigningData = NULL;            // preset failure
-               mTriedRead = true;                      // we've tried (and perhaps failed)
-               
-               AutoFileDesc fd(cspath(), O_RDONLY);
-               mSigningData = EmbeddedSignatureBlob::readBlob(fd);
-               if (mSigningData)
-                       secdebug("foreignrep", "%zd signing bytes in %d blob(s) from %s(foreign)",
-                               mSigningData->length(), mSigningData->count(),
-                               mainExecutablePath().c_str());
-               else
-                       secdebug("foreignrep", "failed to read signing bytes from %s(foreign)",
-                               mainExecutablePath().c_str());
-       }
-}
-
-
-//
-// Generate the path to the (default) sidecar file
-// This is generated as /path/to/.CS.execfilename.
-// We're assuming that we're only dealing with absolute paths here.
-//
-string ForeignDiskRep::cspath()
-{
-       string p = this->path();
-       string::size_type slash = p.rfind('/');
-       assert(slash != string::npos);
-       return p.substr(0, slash+1) + ".CS." + p.substr(slash+1);       // => /path/to/.CS.executable
-}
-
-
-//
-// ForeignDiskRep::Writers
-//
-DiskRep::Writer *ForeignDiskRep::writer()
-{
-       return new Writer(this);
-}
-
-ForeignDiskRep::Writer::~Writer()
-{
-       delete mSigningData;
-}
-
-
-//
-// Write a component.
-// Note that this isn't concerned with Mach-O writing; this is handled at
-// a much higher level. If we're called, it's extended attribute time.
-//
-void ForeignDiskRep::Writer::component(CodeDirectory::SpecialSlot slot, CFDataRef data)
-{
-       EmbeddedSignatureBlob::Maker::component(slot, data);
-}
-
-
-//
-// Append the superblob we built to the foreign binary.
-// Note: Aligning the signing blob to a 16-byte boundary is not strictly necessary,
-// but it's what the Mach-O case does, and it probably improves performance a bit.
-//
-void ForeignDiskRep::Writer::flush()
-{
-       delete mSigningData;                    // ditch previous blob just in case
-       mSigningData = Maker::make();   // assemble new signature SuperBlob
-       AutoFileDesc fd(rep->cspath(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
-       fd.writeAll(mSigningData, mSigningData->length());
-}
-
-
-} // end namespace CodeSigning
-} // end namespace Security
diff --git a/lib/foreigndiskrep.h b/lib/foreigndiskrep.h
deleted file mode 100644 (file)
index 9a8dd17..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 2007 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@
- */
-
-//
-// foreigndiskrep - foreign executable disk representation
-//
-#ifndef _H_FOREIGNDISKREP
-#define _H_FOREIGNDISKREP
-
-#include "singlediskrep.h"
-#include "sigblob.h"
-#include "signerutils.h"
-#include <security_utilities/unix++.h>
-#include <security_utilities/cfutilities.h>
-
-namespace Security {
-namespace CodeSigning {
-
-
-//
-//
-//
-class ForeignDiskRep : public SingleDiskRep {
-public:
-       ForeignDiskRep(const char *path);
-       ~ForeignDiskRep();
-       
-       CFDataRef component(CodeDirectory::SpecialSlot slot);
-       size_t pageSize();
-       std::string format();
-       void flush();
-       
-       static bool candidate(UnixPlusPlus::FileDesc &fd); // could this reasonably be a CFM code?
-
-public:
-       DiskRep::Writer *writer();
-       class Writer;
-       friend class Writer;
-       
-protected:
-       void readSigningData();                                 // read and cache signing data
-       string cspath();                                                // path to sidecar
-       
-private:
-       bool mTriedRead;                                                // tried to get signing data
-       size_t mSigningOffset;                                  // where we found the signing data
-       EmbeddedSignatureBlob *mSigningData;    // cached signing data
-};
-
-
-//
-// The write side of a FileDiskRep
-//
-class ForeignDiskRep::Writer : public DiskRep::Writer, private EmbeddedSignatureBlob::Maker {
-       friend class ForeignDiskRep;
-public:
-       Writer(ForeignDiskRep *r) : rep(r), mSigningData(NULL) { }
-       ~Writer();
-       
-       void component(CodeDirectory::SpecialSlot slot, CFDataRef data);
-       virtual void flush();
-
-protected:
-       RefPointer<ForeignDiskRep> rep;
-       EmbeddedSignatureBlob *mSigningData;
-};
-
-
-} // end namespace CodeSigning
-} // end namespace Security
-
-#endif // !_H_FOREIGNDISKREP
index 35b5ad724be3fbbabcaef4f4be66455da4186af9..f39cc511f0bf4dc6703a1dc5a4fa93877a63ae98 100644 (file)
@@ -21,6 +21,7 @@
  * @APPLE_LICENSE_HEADER_END@
  */
 #include "kerneldiskrep.h"
+#include <sys/utsname.h>
 
 namespace Security {
 namespace CodeSigning {
@@ -34,6 +35,7 @@ using namespace UnixPlusPlus;
 //
 KernelDiskRep::KernelDiskRep()
 {
+       CODESIGN_DISKREP_CREATE_KERNEL(this);
 }
 
 
@@ -46,14 +48,22 @@ CFDataRef KernelDiskRep::component(CodeDirectory::SpecialSlot slot)
        return NULL;
 }
 
+CFDataRef KernelDiskRep::identification()
+{
+       return NULL;
+}
+
+
 CFURLRef KernelDiskRep::canonicalPath()
 {
        return makeCFURL("/mach_kernel");
 }
 
-string KernelDiskRep::recommendedIdentifier()
+string KernelDiskRep::recommendedIdentifier(const SigningContext &)
 {
-       return "@@kernel@@";    //@@@ use $(uname -whatever)?
+       utsname names;
+       UnixError::check(::uname(&names));
+       return string("kernel.") + names.sysname;
 }
 
 size_t KernelDiskRep::signingLimit()
index 973971cab8d955e719e5e4f59bd955a2f0550cdc..997462f657051789fadca6062f61af218a5a06ee 100644 (file)
@@ -47,12 +47,14 @@ public:
        KernelDiskRep();
        
        CFDataRef component(CodeDirectory::SpecialSlot slot);
+       CFDataRef identification();
        std::string mainExecutablePath();
        CFURLRef canonicalPath();
-       std::string recommendedIdentifier();
        size_t signingLimit();
        std::string format();
        UnixPlusPlus::FileDesc &fd();
+       
+       std::string recommendedIdentifier(const SigningContext &ctx);
 };
 
 
diff --git a/lib/macho++.cpp b/lib/macho++.cpp
deleted file mode 100644 (file)
index 012e0af..0000000
+++ /dev/null
@@ -1,487 +0,0 @@
-/*
- * Copyright (c) 2006 Apple Computer, 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@
- */
-
-//
-// macho++ - Mach-O object file helpers
-//
-#include "macho++.h"
-#include <security_utilities/memutils.h>
-#include <security_utilities/endian.h>
-#include <mach/machine.h>
-
-namespace Security {
-
-
-//
-// Architecture values
-//
-Architecture::Architecture(const fat_arch &arch)
-       : pair<cpu_type_t, cpu_subtype_t>(arch.cputype, arch.cpusubtype)
-{
-}
-
-
-//
-// The local architecture (on demand; cached)
-//
-struct LocalArch {
-       const NXArchInfo *arch;
-       LocalArch() { arch = NXGetLocalArchInfo(); }
-};
-static ModuleNexus<LocalArch> localArch;
-
-Architecture Architecture::local()
-{
-       const NXArchInfo &local = *localArch().arch;
-       return Architecture(local.cputype, local.cpusubtype);
-}
-
-
-#define CPU_SUBTYPE_ARM_V7             ((cpu_subtype_t) 9)
-
-//
-// Translate between names and numbers
-//
-static const char *uob(char *s) { if (*s != 'a') for (char *p = s; *p; p++) *p ^= 0x77; return s; }
-
-const char *Architecture::name() const
-{
-       if (const NXArchInfo *info = NXGetArchInfoFromCpuType(cpuType(), cpuSubtype()))
-               return info->name;
-       else if (cpuType() == CPU_TYPE_ARM)      {      // work-around for non-ARM Leopard systems
-               static char arm5[] = "\026\005\032\001B";
-               static char arm6[] = "\026\005\032\001A";
-               static char arm7[] = "\026\005\032\001@";
-               static char arm[] = "\026\005\032";
-               if (cpuSubtype() == CPU_SUBTYPE_ARM_V5TEJ)
-                       return uob(arm5);
-               else if (cpuSubtype() == CPU_SUBTYPE_ARM_V6)
-                       return uob(arm6);
-               else if (cpuSubtype() == CPU_SUBTYPE_ARM_V7)
-                       return uob(arm7);
-               else
-                       return uob(arm);
-       } else
-               return NULL;
-}
-
-
-//
-// Create a MachO object from an open file and a starting offset.
-// We load (only) the header and load commands into memory at that time.
-//
-MachO::MachO(FileDesc fd, size_t offset, size_t length)
-       : FileDesc(fd), mOffset(offset), mLength(length ? length : (fd.fileSize() - offset))
-{
-       size_t size = fd.read(&mHeader, sizeof(mHeader), mOffset);
-       if (size != sizeof(mHeader))
-               UnixError::throwMe(ENOEXEC);
-       switch (mHeader.magic) {
-       case MH_MAGIC:
-               mFlip = false;
-               m64 = false;
-               break;
-       case MH_CIGAM:
-               mFlip = true;
-               m64 = false;
-               break;
-       case MH_MAGIC_64:
-               mFlip = false;
-               m64 = true;
-               break;
-       case MH_CIGAM_64:
-               mFlip = true;
-               m64 = true;
-               break;
-       default:
-               UnixError::throwMe(ENOEXEC);
-       }
-       
-       size_t cmdSize = flip(mHeader.sizeofcmds);
-       size_t cmdStart = m64 ? sizeof(mach_header_64) : sizeof(mach_header);
-       mCommands = (load_command *)malloc(cmdSize);
-       if (!mCommands)
-               UnixError::throwMe();
-       if (fd.read(mCommands, cmdSize, cmdStart + mOffset) != cmdSize)
-               UnixError::throwMe(ENOEXEC);
-       mEndCommands = LowLevelMemoryUtilities::increment<load_command>(mCommands, cmdSize);
-       secdebug("macho", "%p created fd=%d offset=0x%zx size=0x%zx %s%s %d command(s)",
-               this, this->fd(), mOffset, mLength, mFlip ? " flipped" : "", m64 ? " 64-bit" : "",
-               flip(mHeader.ncmds));
-}
-
-
-//
-// Destroy a MachO.
-// Note that we don't close the file descriptor.
-//
-MachO::~MachO()
-{
-       secdebug("macho", "%p destroyed", this);
-       ::free(mCommands);
-}
-
-
-//
-// Return various header fields
-//
-Architecture MachO::architecture() const
-{
-       return Architecture(flip(mHeader.cputype), flip(mHeader.cpusubtype));
-}
-
-uint32_t MachO::type() const
-{
-       return flip(mHeader.filetype);
-}
-
-uint32_t MachO::flags() const
-{
-       return flip(mHeader.flags);
-}
-
-
-//
-// Iterate through load commands
-//
-const load_command *MachO::nextCommand(const load_command *command) const
-{
-       using LowLevelMemoryUtilities::increment;
-       command = increment<const load_command>(command, flip(command->cmdsize));
-       return (command < mEndCommands) ? command : NULL;
-}
-
-
-//
-// Locate a segment command, by name
-//     
-const segment_command *MachO::findSegment(const char *segname) const
-{
-       for (const load_command *command = loadCommands(); command; command = nextCommand(command)) {
-               if (flip(command->cmd) == LC_SEGMENT) {
-                       const segment_command *seg = reinterpret_cast<const segment_command *>(command);
-                       if (!strcmp(seg->segname, segname))
-                               return seg;
-               }
-       }
-       return NULL;
-}
-
-const section *MachO::findSection(const char *segname, const char *sectname) const
-{
-       using LowLevelMemoryUtilities::increment;
-       if (const segment_command *seg = findSegment(segname)) {
-               if (is64()) {
-                       const segment_command_64 *seg64 = reinterpret_cast<const segment_command_64 *>(seg);
-                       const section_64 *sect = increment<const section_64>(seg64 + 1, 0);
-                       for (unsigned n = flip(seg64->nsects); n > 0; n--, sect++) {
-                               if (!strcmp(sect->sectname, sectname))
-                                       return reinterpret_cast<const section *>(sect);
-                       }
-               } else {
-                       const section *sect = increment<const section>(seg + 1, 0);
-                       for (unsigned n = flip(seg->nsects); n > 0; n--, sect++) {
-                               if (!strcmp(sect->sectname, sectname))
-                                       return sect;
-                       }
-               }
-       }
-       return NULL;
-}
-
-
-//
-// Figure out where the Code Signing information starts in the Mach-O binary image.
-// The code signature is at the end of the file, and identified
-// by a specially-named section. So its starting offset is also the end
-// of the signable part.
-// Note that the offset returned is relative to the start of the Mach-O image.
-// Returns zero if not found (usually indicating that the binary was not signed).
-//
-const linkedit_data_command *MachO::findCodeSignature() const
-{
-       for (const load_command *cmd = loadCommands(); cmd; cmd = nextCommand(cmd))
-               if (flip(cmd->cmd) == LC_CODE_SIGNATURE)
-                       return reinterpret_cast<const linkedit_data_command *>(cmd);
-       return NULL;            // not found
-}
-
-size_t MachO::signingOffset() const
-{
-       if (const linkedit_data_command *lec = findCodeSignature())
-               return flip(lec->dataoff);
-       else
-               return 0;
-}
-
-size_t MachO::signingLength() const
-{
-       if (const linkedit_data_command *lec = findCodeSignature())
-               return flip(lec->datasize);
-       else
-               return 0;
-}
-
-
-//
-// Return the signing-limit length for this Mach-O binary image.
-// This is the signingOffset if present, or the full length if not.
-//
-size_t MachO::signingExtent() const
-{
-       if (size_t offset = signingOffset())
-               return offset;
-       else
-               return length();
-}
-
-
-//
-// I/O operations
-//
-void MachO::seek(size_t offset)
-{
-       FileDesc::seek(mOffset + offset);
-}
-
-CFDataRef MachO::dataAt(size_t offset, size_t size)
-{
-       CFMallocData buffer(size);
-       if (this->read(buffer, size, mOffset + offset) != size)
-               UnixError::throwMe();
-       return buffer;
-}
-
-
-//
-// Fat (aka universal) file wrappers
-//
-Universal::Universal(FileDesc fd)
-       : FileDesc(fd)
-{
-       union {
-               fat_header header;              // if this is a fat file
-               mach_header mheader;    // if this is a thin file
-       };
-       const size_t size = max(sizeof(header), sizeof(mheader));
-       if (fd.read(&header, size, 0) != size)
-               UnixError::throwMe(ENOEXEC);
-       switch (header.magic) {
-       case FAT_MAGIC:
-       case FAT_CIGAM:
-               {
-                       mArchCount = ntohl(header.nfat_arch);
-                       size_t archSize = sizeof(fat_arch) * mArchCount;
-                       mArchList = (fat_arch *)malloc(archSize);
-                       if (!mArchList)
-                               UnixError::throwMe();
-                       if (fd.read(mArchList, archSize, sizeof(header)) != archSize) {
-                               ::free(mArchList);
-                               UnixError::throwMe(ENOEXEC);
-                       }
-                       for (fat_arch *arch = mArchList; arch < mArchList + mArchCount; arch++) {
-                               n2hi(arch->cputype);
-                               n2hi(arch->cpusubtype);
-                               n2hi(arch->offset);
-                               n2hi(arch->size);
-                               n2hi(arch->align);
-                       }
-                       secdebug("macho", "%p is a fat file with %d architectures",
-                               this, mArchCount);
-                       break;
-               }
-       case MH_MAGIC:
-       case MH_MAGIC_64:
-               mArchList = NULL;
-               mArchCount = 0;
-               mThinArch = Architecture(mheader.cputype, mheader.cpusubtype);
-               secdebug("macho", "%p is a thin file (%s)", this, mThinArch.name());
-               break;
-       case MH_CIGAM:
-       case MH_CIGAM_64:
-               mArchList = NULL;
-               mArchCount = 0;
-               mThinArch = Architecture(flip(mheader.cputype), flip(mheader.cpusubtype));
-               secdebug("macho", "%p is a thin file (%s)", this, mThinArch.name());
-               break;
-       default:
-               UnixError::throwMe(ENOEXEC);
-       }
-}
-
-Universal::~Universal()
-{
-       ::free(mArchList);
-}
-
-
-//
-// Get the "local" architecture from the fat file
-// Throws ENOEXEC if not found.
-//
-MachO *Universal::architecture() const
-{
-       if (isUniversal())
-               return findImage(bestNativeArch());
-       else
-               return new MachO(*this);
-}
-
-size_t Universal::archOffset() const
-{
-       if (isUniversal())
-               return findArch(bestNativeArch())->offset;
-       else
-               return 0;
-}
-
-
-//
-// Get the specified architecture from the fat file
-// Throws ENOEXEC if not found.
-//
-MachO *Universal::architecture(const Architecture &arch) const
-{
-       if (isUniversal())
-               return findImage(arch);
-       else if (mThinArch.matches(arch))
-               return new MachO(*this);
-       else
-               UnixError::throwMe(ENOEXEC);
-}
-
-size_t Universal::archOffset(const Architecture &arch) const
-{
-       if (isUniversal())
-               return findArch(arch)->offset;
-       else if (mThinArch.matches(arch))
-               return 0;
-       else
-               UnixError::throwMe(ENOEXEC);
-}
-
-
-//
-// Locate an architecture from the fat file's list.
-// Throws ENOEXEC if not found.
-//
-const fat_arch *Universal::findArch(const Architecture &target) const
-{
-       assert(isUniversal());
-       const fat_arch *end = mArchList + mArchCount;
-       // exact match
-       for (const fat_arch *arch = mArchList; arch < end; ++arch)
-               if (arch->cputype == target.cpuType()
-                       && arch->cpusubtype == target.cpuSubtype())
-                       return arch;
-       // match for generic model of main architecture
-       for (const fat_arch *arch = mArchList; arch < end; ++arch)
-               if (arch->cputype == target.cpuType() && arch->cpusubtype == 0)
-                       return arch;
-       // match for any subarchitecture of the main architeture (questionable)
-       for (const fat_arch *arch = mArchList; arch < end; ++arch)
-               if (arch->cputype == target.cpuType())
-                       return arch;
-       // no match
-       UnixError::throwMe(ENOEXEC);    // not found    
-}
-
-MachO *Universal::findImage(const Architecture &target) const
-{
-       const fat_arch *arch = findArch(target);
-       return new MachO(*this, arch->offset, arch->size);
-}
-
-
-//
-// Find the best-matching architecture for this fat file.
-// We pick the native architecture if it's available.
-// If it contains exactly one architecture, we take that.
-// Otherwise, we throw.
-//
-Architecture Universal::bestNativeArch() const
-{
-       if (isUniversal()) {
-               // ask the NXArch API for our native architecture
-               const Architecture native = Architecture::local();
-               if (fat_arch *match = NXFindBestFatArch(native.cpuType(), native.cpuSubtype(), mArchList, mArchCount))
-                       return *match;
-               // if the system can't figure it out, pick (arbitrarily) the first one
-               return mArchList[0];
-       } else
-               return mThinArch;
-}
-
-
-//
-// List all architectures from the fat file's list.
-//
-void Universal::architectures(Architectures &archs)
-{
-       if (isUniversal()) {
-               for (unsigned n = 0; n < mArchCount; n++)
-                       archs.insert(mArchList[n]);
-       } else {
-               auto_ptr<MachO> macho(architecture());
-               archs.insert(macho->architecture());
-       }
-}
-
-
-//
-// Quickly guess the Mach-O type of a file.
-// Returns type zero if the file isn't Mach-O or Universal.
-// Does not reposition the file.
-//
-uint32_t Universal::typeOf(FileDesc fd)
-{
-       mach_header header;
-       if (fd.read(&header, sizeof(header), 0) != sizeof(header))
-               return false;
-       for (;;) {
-               switch (header.magic) {
-               case MH_MAGIC:
-               case MH_MAGIC_64:
-                       return header.filetype;
-                       break;
-               case MH_CIGAM:
-               case MH_CIGAM_64:
-                       return flip(header.filetype);
-                       break;
-               case FAT_MAGIC:
-               case FAT_CIGAM:
-                       {
-                               const fat_arch *arch1 =
-                                       LowLevelMemoryUtilities::increment<fat_arch>(&header, sizeof(fat_header));
-                               if (fd.read(&header, sizeof(header), ntohl(arch1->offset)) != sizeof(header))
-                                       return 0;
-                               continue;
-                       }
-               default:
-                       return 0;
-               }
-       }
-}
-
-
-} // Security
diff --git a/lib/macho++.h b/lib/macho++.h
deleted file mode 100644 (file)
index abf6118..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (c) 2006 Apple Computer, 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@
- */
-
-//
-// macho++ - Mach-O object file helpers
-//
-#ifndef _H_MACHOPLUSPLUS
-#define _H_MACHOPLUSPLUS
-
-#include <mach-o/loader.h>
-#include <mach-o/fat.h>
-#include <mach-o/arch.h>
-#include <security_utilities/globalizer.h>
-#include <security_utilities/endian.h>
-#include <security_utilities/unix++.h>
-#include <security_utilities/cfutilities.h>
-
-namespace Security {
-
-
-//
-// An architecture specification.
-// Simply a pair or (cpu type, cpu subtype), really.
-//
-class Architecture : public std::pair<cpu_type_t, cpu_subtype_t> {
-       typedef std::pair<cpu_type_t, cpu_subtype_t> _Pair;
-public:
-       Architecture() { }
-       explicit Architecture(cpu_type_t type, cpu_subtype_t sub = CPU_SUBTYPE_MULTIPLE)
-               : std::pair<cpu_type_t, cpu_subtype_t>(type, sub) { }
-       Architecture(const fat_arch &archInFile);
-
-       cpu_type_t cpuType() const { return this->first; }
-       cpu_subtype_t cpuSubtype() const { return this->second; }
-       const char *name() const;
-
-       static const cpu_type_t none = 0;
-       operator bool () const { return cpuType() != none; }
-       bool operator ! () const { return cpuType() == none; }
-       
-public:
-       friend bool operator == (const Architecture &a1, const Architecture &a2)
-       { return _Pair(a1) == _Pair(a2); }
-
-       friend bool operator < (const Architecture &a1, const Architecture &a2)
-       { return _Pair(a1) < _Pair(a2); }
-
-       bool matches(const Architecture &templ) const
-       { return first == templ.first && (second == templ.second || templ.second == 0 || templ.second == CPU_SUBTYPE_MULTIPLE); }
-
-public:
-       static Architecture local();
-};
-
-
-//
-// A Mach-O formatted file segment.
-//
-class MachO : public UnixPlusPlus::FileDesc {
-public:
-       MachO(FileDesc fd, size_t offset = 0, size_t length = 0);
-       ~MachO();
-       
-       size_t offset() const { return mOffset; }
-       size_t length() const { return mLength; }
-       
-       template <class T>
-       T flip(T value) const
-       { return mFlip ? Security::flip(value) : value; }
-       
-       bool isFlipped() const { return mFlip; }
-       bool is64() const { return m64; }
-       
-       Architecture architecture() const;
-       uint32_t type() const;
-       uint32_t flags() const;
-       
-       const load_command *loadCommands() const { return mCommands; }
-       const load_command *nextCommand(const load_command *command) const;
-       
-       const segment_command *findSegment(const char *segname) const;
-       const section *findSection(const char *segname, const char *sectname) const;
-
-       const linkedit_data_command *findCodeSignature() const;
-       
-       size_t signingOffset() const;   // starting offset of CS section, or 0 if none
-       size_t signingLength() const;   // length of CS section, or 0 if none
-       size_t signingExtent() const;   // signingOffset, or file length if none
-       
-       void seek(size_t offset);       // relative to start of image
-       CFDataRef dataAt(size_t offset, size_t size);
-
-private:
-       size_t mOffset;                 // starting file offset
-       size_t mLength;                 // Mach-O file length
-       bool m64;                               // is 64-bit
-       bool mFlip;                             // wrong byte order (flip all integers)
-       mach_header mHeader;    // Mach-O header
-       load_command *mCommands; // load commands
-       load_command *mEndCommands; // end of load commands
-};
-
-
-//
-// A Universal object represents a Mach-O binary image (whole) file.
-// It can represent a true Universal (aka "Fat") file with multiple
-// architectures; but it will also represent a single Mach-O ("thin")
-// binary and make you believe it's a Universal with just one architecture.
-//
-class Universal : public UnixPlusPlus::FileDesc {
-public:
-       Universal(FileDesc fd);
-       ~Universal();
-       
-       // return a genuine MachO object for the given architecture
-       MachO *architecture() const;            // native
-       MachO *architecture(const Architecture &arch) const; // given
-       
-       // return (just) the starting offset of an architecture
-       size_t archOffset() const;                      // native
-       size_t archOffset(const Architecture &arch) const; // given
-       
-       // return a set of architectures contained
-       typedef std::set<Architecture> Architectures;
-       void architectures(Architectures &archs);
-       
-       bool isUniversal() const { return mArchList != NULL; }
-       Architecture bestNativeArch() const;
-       
-public:
-       static uint32_t typeOf(FileDesc fd);
-
-private:
-       const fat_arch *findArch(const Architecture &arch) const;
-       MachO *findImage(const Architecture &arch) const;
-
-private:
-       fat_arch *mArchList;            // architectures (NULL if thin file)
-       unsigned mArchCount;            // number of architectures (if fat)
-       Architecture mThinArch;         // single architecture (if thin)
-};
-
-
-} // end namespace Security
-
-#endif // !_H_MACHOPLUSPLUS
index dae7c2525162fb74849ad2591bf2b4b78269dac0..8753ca609bfa2cc9db04201b0b3de66ea6598d28 100644 (file)
@@ -25,6 +25,8 @@
 // machorep - DiskRep mix-in for handling Mach-O main executables
 //
 #include "machorep.h"
+#include "StaticCode.h"
+#include "reqmaker.h"
 
 
 namespace Security {
@@ -36,11 +38,25 @@ using namespace UnixPlusPlus;
 //
 // Object management.
 // We open the main executable lazily, so nothing much happens on construction.
+// If the context specifies a file offset, we directly pick that Mach-O binary (only).
+// if it specifies an architecture, we try to pick that. Otherwise, we deliver the whole
+// Universal object (which will usually deliver the "native" architecture later).
 //
-MachORep::MachORep(const char *path)
+MachORep::MachORep(const char *path, const Context *ctx)
        : SingleDiskRep(path), mSigningData(NULL)
 {
-       mExecutable = new Universal(fd());
+       if (ctx)
+               if (ctx->offset)
+                       mExecutable = new Universal(fd(), ctx->offset);
+               else if (ctx->arch) {
+                       auto_ptr<Universal> full(new Universal(fd()));
+                       mExecutable = new Universal(fd(), full->archOffset(ctx->arch));
+               } else
+                       mExecutable = new Universal(fd());
+       else
+               mExecutable = new Universal(fd());
+       assert(mExecutable);
+       CODESIGN_DISKREP_CREATE_MACHO(this, (char*)path, (void*)ctx);
 }
 
 MachORep::~MachORep()
@@ -53,7 +69,7 @@ MachORep::~MachORep()
 //
 // Sniffer function for "plausible Mach-O binary"
 //
-bool MachORep::candidiate(FileDesc &fd)
+bool MachORep::candidate(FileDesc &fd)
 {
        switch (Universal::typeOf(fd)) {
        case MH_EXECUTE:
@@ -70,56 +86,54 @@ bool MachORep::candidiate(FileDesc &fd)
 }
 
 
-//
-// For Mach-O binaries that are of PowerPC architecture, we recommend
-// allowing the Rosetta translator as a host. Otherwise, no suggestions.
-//
-static const uint8_t ppc_ireqs[] = {   // host => anchor apple and identifier com.apple.translate
-       0xfa, 0xde, 0x0c, 0x01, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
-       0x00, 0x00, 0x00, 0x14, 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)
-{
-       assert(arch);           // enforced by signing infrastructure
-       if (arch->cpuType() == CPU_TYPE_POWERPC)
-               return ((const Requirements *)ppc_ireqs)->clone();      // need to pass ownership
-       else
-               return NULL;
-}
-
 
 //
-// Obtain, cache, and return a Universal reference to the main executable,
-// IF the main executable is a Mach-O binary (or fat version thereof).
-// Returns NULL if the main executable can't be opened as such.
+// Nowadays, the main executable object is created upon construction.
 //
 Universal *MachORep::mainExecutableImage()
 {
-       if (!mExecutable)
-               mExecutable = new Universal(fd());
        return mExecutable;
 }
 
 
 //
-// Default to system page size for segmented (paged) signatures
+// Signing base is the start of the Mach-O architecture we're using
 //
-size_t MachORep::pageSize()
+size_t MachORep::signingBase()
 {
-       return segmentedPageSize;
+       return mainExecutableImage()->archOffset();
 }
 
 
 //
-// Signing base is the start of the Mach-O architecture we're using
+// We choose the binary identifier for a Mach-O binary as follows:
+//     - If the Mach-O headers have a UUID command, use the UUID.
+//     - Otherwise, use the SHA-1 hash of the (entire) load commands.
 //
-size_t MachORep::signingBase()
+CFDataRef MachORep::identification()
 {
-       return mainExecutableImage()->archOffset();
+       std::auto_ptr<MachO> macho(mainExecutableImage()->architecture());
+       return identificationFor(macho.get());
+}
+
+CFDataRef MachORep::identificationFor(MachO *macho)
+{
+       // if there is a LC_UUID load command, use the UUID contained therein
+       if (const load_command *cmd = macho->findCommand(LC_UUID)) {
+               const uuid_command *uuidc = reinterpret_cast<const uuid_command *>(cmd);
+               char result[4 + sizeof(uuidc->uuid)];
+               memcpy(result, "UUID", 4);
+               memcpy(result+4, uuidc->uuid, sizeof(uuidc->uuid));
+               return makeCFData(result, sizeof(result));
+       }
+       
+       // otherwise, use the SHA-1 hash of the entire load command area
+       SHA1 hash;
+       hash(&macho->header(), sizeof(mach_header));
+       hash(macho->loadCommands(), macho->commandLength());
+       SHA1::Digest digest;
+       hash.finish(digest);
+       return makeCFData(digest, sizeof(digest));
 }
 
 
@@ -152,24 +166,23 @@ CFDataRef MachORep::component(CodeDirectory::SpecialSlot slot)
 //
 CFDataRef MachORep::embeddedComponent(CodeDirectory::SpecialSlot slot)
 {
-       if (!mSigningData)              // fetch and cache
-               try {
-                       auto_ptr<MachO> macho(mainExecutableImage()->architecture());
-                       if (macho.get())
-                               if (size_t offset = macho->signingOffset()) {
-                                       macho->seek(offset);
-                                       mSigningData = EmbeddedSignatureBlob::readBlob(macho->fd());
-                                       if (mSigningData)
-                                               secdebug("machorep", "%zd signing bytes in %d blob(s) from %s(%s)",
-                                                       mSigningData->length(), mSigningData->count(),
-                                                       mainExecutablePath().c_str(), macho->architecture().name());
-                                       else
-                                               secdebug("machorep", "failed to read signing bytes from %s(%s)",
-                                                       mainExecutablePath().c_str(), macho->architecture().name());
+       if (!mSigningData) {            // fetch and cache
+               auto_ptr<MachO> macho(mainExecutableImage()->architecture());
+               if (macho.get())
+                       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)) {
+                                       secdebug("machorep", "%zd signing bytes in %d blob(s) from %s(%s)",
+                                               mSigningData->length(), mSigningData->count(),
+                                               mainExecutablePath().c_str(), macho->architecture().name());
+                               } else {
+                                       secdebug("machorep", "failed to read signing bytes from %s(%s)",
+                                               mainExecutablePath().c_str(), macho->architecture().name());
+                                       MacOSError::throwMe(errSecCSSignatureInvalid);
                                }
-               } catch (...) {
-                       secdebug("machorep", "exception reading Mach-O from universal");
-               }
+                       }
+       }
        if (mSigningData)
                return mSigningData->component(slot);
        
@@ -190,9 +203,9 @@ CFDataRef MachORep::infoPlist()
                if (const section *sect = macho->findSection("__TEXT", "__info_plist")) {
                        if (macho->is64()) {
                                const section_64 *sect64 = reinterpret_cast<const section_64 *>(sect);
-                               info = macho->dataAt(macho->flip(sect64->offset), macho->flip(sect64->size));
+                               info.take(macho->dataAt(macho->flip(sect64->offset), macho->flip(sect64->size)));
                        } else {
-                               info = macho->dataAt(macho->flip(sect->offset), macho->flip(sect->size));
+                               info.take(macho->dataAt(macho->flip(sect->offset), macho->flip(sect->size)));
                        }
                }
        } catch (...) {
@@ -202,29 +215,6 @@ CFDataRef MachORep::infoPlist()
 }
 
 
-//
-// Return a recommended unique identifier.
-// If our file has an embedded Info.plist, use the CFBundleIdentifier from that.
-// Otherwise, use the default.
-//
-string MachORep::recommendedIdentifier()
-{
-       if (CFDataRef info = infoPlist()) {
-               if (CFDictionaryRef dict = makeCFDictionaryFrom(info)) {
-                       CFStringRef code = CFStringRef(CFDictionaryGetValue(dict, kCFBundleIdentifierKey));
-                       if (code && CFGetTypeID(code) != CFStringGetTypeID())
-                               MacOSError::throwMe(errSecCSBadDictionaryFormat);
-                       if (code)
-                               return cfString(code);
-               } else
-                       MacOSError::throwMe(errSecCSBadDictionaryFormat);
-       }
-       
-       // ah well. Use the default
-       return SingleDiskRep::recommendedIdentifier();
-}
-
-
 //
 // Provide a (vaguely) human readable characterization of this code
 //
@@ -239,15 +229,15 @@ string MachORep::format()
                                        it != archs.end(); ++it) {
                                if (it != archs.begin())
                                        s += " ";
-                               s += it->name();
+                               s += it->displayName();
                        }
                        return s + ")";
                } else {
                        assert(archs.size() == 1);
-                       return string("Mach-O thin (") + archs.begin()->name() + ")";
+                       return string("Mach-O thin (") + archs.begin()->displayName() + ")";
                }
        } else
-               return "not Mach-O";            // (you don't usually show that one to the user)
+               return "Mach-O (unrecognized format)";
 }
 
 
@@ -261,6 +251,104 @@ void MachORep::flush()
        ::free(mSigningData);
        mSigningData = NULL;
        SingleDiskRep::flush();
+       mExecutable = new Universal(fd());
+}
+
+
+//
+// Return a recommended unique identifier.
+// If our file has an embedded Info.plist, use the CFBundleIdentifier from that.
+// Otherwise, use the default.
+//
+string MachORep::recommendedIdentifier(const SigningContext &ctx)
+{
+       if (CFDataRef info = infoPlist()) {
+               if (CFDictionaryRef dict = makeCFDictionaryFrom(info)) {
+                       CFStringRef code = CFStringRef(CFDictionaryGetValue(dict, kCFBundleIdentifierKey));
+                       if (code && CFGetTypeID(code) != CFStringGetTypeID())
+                               MacOSError::throwMe(errSecCSBadDictionaryFormat);
+                       if (code)
+                               return cfString(code);
+               } else
+                       MacOSError::throwMe(errSecCSBadDictionaryFormat);
+       }
+       
+       // ah well. Use the default
+       return SingleDiskRep::recommendedIdentifier(ctx);
+}
+
+
+//
+// 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))
+               maker.add(kSecLibraryRequirementType, libreq);  // takes ownership
+
+       // that's all
+       return maker.make();
+}
+
+Requirement *MachORep::libraryRequirements(const Architecture *arch, const SigningContext &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)");
+                                       }
+                               else
+                                       CODESIGN_SIGN_DEP_MACHO(this, NULL, NULL);
+                       }
+               }
+       }
+       if (chain.empty())
+               return NULL;
+       else
+               return maker.make();
+}
+
+
+//
+// Default to system page size for segmented (paged) signatures
+//
+size_t MachORep::pageSize(const SigningContext &)
+{
+       return segmentedPageSize;
 }
 
 
@@ -281,6 +369,7 @@ DiskRep::Writer *MachORep::writer()
 //
 void MachORep::Writer::component(CodeDirectory::SpecialSlot slot, CFDataRef data)
 {
+       assert(false);
        MacOSError::throwMe(errSecCSInternalError);
 }
 
index 4b05cf86ac7eb20570ebb38a27525d3a87020f18..2486139533924d034e005e8839ffaf4a0a0b21c6 100644 (file)
 #include "singlediskrep.h"
 #include "sigblob.h"
 #include <security_utilities/unix++.h>
-#include <security_codesigning/macho++.h>
+#include <security_utilities/macho++.h>
 
 namespace Security {
 namespace CodeSigning {
 
 
 //
-// MachORep is a mix-in class that supports reading
-// Code Signing resources from the main executable.
+// MachORep is a DiskRep class that supports code signatures
+// directly embedded in Mach-O binary files.
 //
 // It does not have write support (for writing signatures);
 // writing multi-architecture binaries is complicated enough
@@ -47,20 +47,25 @@ namespace CodeSigning {
 //
 class MachORep : public SingleDiskRep {
 public:
-       MachORep(const char *path);
+       MachORep(const char *path, const Context *ctx = NULL);
        virtual ~MachORep();
        
        CFDataRef component(CodeDirectory::SpecialSlot slot);
-       std::string recommendedIdentifier();
-       const Requirements *defaultRequirements(const Architecture *arch);
+       CFDataRef identification();
        Universal *mainExecutableImage();
-       size_t pageSize();
        size_t signingBase();
        std::string format();
        
+       std::string recommendedIdentifier(const SigningContext &ctx);
+       const Requirements *defaultRequirements(const Architecture *arch, const SigningContext &ctx);
+       size_t pageSize(const SigningContext &ctx);
+       
        void flush();           // flush cache
        
-       static bool candidiate(UnixPlusPlus::FileDesc &fd);
+       static bool candidate(UnixPlusPlus::FileDesc &fd);
+       
+public:
+       static CFDataRef identificationFor(MachO *macho);
        
 public:
        DiskRep::Writer *writer();
@@ -70,6 +75,7 @@ public:
 protected:
        CFDataRef embeddedComponent(CodeDirectory::SpecialSlot slot);
        CFDataRef infoPlist();
+       Requirement *libraryRequirements(const Architecture *arch, const SigningContext &ctx);
 
 private:
        Universal *mExecutable; // cached Mach-O/Universal reference to mainExecutablePath()
@@ -78,7 +84,9 @@ private:
 
 
 //
-// The write side of a FileDiskRep
+// The write side of a MachORep.
+// This is purposely dysfunctional; Mach-O signatures are written
+// by code in signerutils, not by DiskRep::Writers.
 //
 class MachORep::Writer : public SingleDiskRep::Writer {
        friend class FileDiskRep;
index 8ab499e9ef88c5fd22976815aae07a19b5aee7d8..a5b8e78fadba8436fe8cbe8fb73177c1d47bbb2c 100644 (file)
@@ -39,7 +39,7 @@ ResourceEnumerator::ResourceEnumerator(string path)
 {
        assert(!mPath.empty());
        const char * paths[2] = { path.c_str(), NULL };
-       mFTS = fts_open((char * const *)paths, FTS_PHYSICAL, NULL);
+       mFTS = fts_open((char * const *)paths, FTS_PHYSICAL | FTS_COMFOLLOW | FTS_NOCHDIR, NULL);
        if (!mFTS)
                UnixError::throwMe();
 }
index 8fbd4446c424ad7d8b1bbe7a9345cc34848a3477..ec6cd64390f37071d5b5e0e316460c51d2700588 100644 (file)
@@ -34,6 +34,16 @@ namespace CodeSigning {
 using namespace UnixPlusPlus;
 
 
+//
+// Table of reserved words (keywords), generated by ANTLR
+//
+static const char * const keywords[] = {
+#include "RequirementKeywords.h"
+       "",
+       NULL
+};
+
+
 //
 // Printf to established output channel
 //
@@ -147,7 +157,7 @@ void Dumper::expr(SyntaxLevel level)
                print("anchor apple generic");
                break;
        case opAnchorHash:
-               print("anchor"); certSlot(); print(" = "); hashData();
+               print("certificate"); certSlot(); print(" = "); hashData();
                break;
        case opInfoKeyValue:
                if (mDebug)
@@ -198,12 +208,27 @@ void Dumper::expr(SyntaxLevel level)
                }
                print("]"); match();
                break;
+       case opCertPolicy:
+               print("certificate"); certSlot(); print("[");
+               {
+                       const unsigned char *data; size_t length;
+                       getData(data, length);
+                       print("policy.%s", CssmOid((unsigned char *)data, length).toOid().c_str());
+               }
+               print("]"); match();
+               break;
        case opTrustedCert:
                print("certificate"); certSlot(); print("trusted");
                break;
        case opTrustedCerts:
                print("anchor trusted");
                break;
+       case opNamedAnchor:
+               print("anchor apple "); data();
+               break;
+       case opNamedCode:
+               print("("); data(); print(")");
+               break;
        default:
                if (op & opGenericFalse) {
                        print(" false /* opcode %d */", op & ~opFlagMask);
@@ -220,7 +245,7 @@ void Dumper::expr(SyntaxLevel level)
 
 void Dumper::certSlot()
 {
-       switch (uint32_t slot = get<uint32_t>()) {
+       switch (int32_t slot = get<int32_t>()) {
        case Requirement::anchorCert:
                print(" root");
                break;
@@ -237,7 +262,7 @@ void Dumper::match()
 {
        switch (MatchOperation op = MatchOperation(get<uint32_t>())) {
        case matchExists:
-               print(" exists");
+               print(" /* exists */");
                break;
        case matchEqual:
                print(" = "); data();
@@ -294,9 +319,15 @@ void Dumper::data(PrintMode bestMode /* = isSimple */, bool dotOkay /* = false *
                        break;          // pessimal
                }
        
-       if (length == 0 && bestMode == isSimple)
-               bestMode = isPrintable;     // force quotes for empty string
-
+       if (bestMode == isSimple) {
+               string s((const char *)data, length);
+               for (const char * const * k = keywords; *k; k++)
+                       if (s == *k) {
+                               bestMode = isPrintable;         // reserved word; need quotes
+                               break;
+                       }
+       }
+               
        switch (bestMode) {
        case isSimple:
                print("%.*s", length, data);
index 089154bad8a5f855e719f854563c38e4fb457657..f8b39d3b9f2b558f22ff4fc3b13427a26a5e1816 100644 (file)
 // reqinterp - Requirement language (exprOp) interpreter
 //
 #include "reqinterp.h"
+#include "codesigning_dtrace.h"
 #include <Security/SecTrustSettingsPriv.h>
 #include <Security/SecCertificatePriv.h>
 #include <security_utilities/memutils.h>
+#include <security_utilities/logging.h>
 #include "csutilities.h"
 
 namespace Security {
 namespace CodeSigning {
 
 
-static CFStringRef appleIntermediateCN = CFSTR("Apple Code Signing Certification Authority");
-static CFStringRef appleIntermediateO = CFSTR("Apple Inc.");
+//
+// Fragment fetching, caching, and evaluation.
+//
+// Several language elements allow "calling" of separate requirement programs
+// stored on disk as (binary) requirement blobs. The Fragments class takes care
+// of finding, loading, caching, and evaluating them.
+//
+// This is a singleton for (process global) caching. It works fine as multiple instances,
+// at a loss of caching effectiveness.
+//
+class Fragments {
+public:
+       Fragments();
+       
+       bool named(const std::string &name, const Requirement::Context &ctx)
+               { return evalNamed("subreq", name, ctx); }
+       bool namedAnchor(const std::string &name, const Requirement::Context &ctx)
+               { return evalNamed("anchorreq", name, ctx); }
+
+private:
+       bool evalNamed(const char *type, const std::string &name, const Requirement::Context &ctx);
+       CFDataRef fragment(const char *type, const std::string &name);
+       
+       typedef std::map<std::string, CFRef<CFDataRef> > FragMap;
+       
+private:
+       CFBundleRef mMyBundle;                  // Security.framework bundle
+       Mutex mLock;                                    // lock for all of the below...
+       FragMap mFragments;                             // cached fragments
+};
+
+static ModuleNexus<Fragments> fragments;
 
 
 //
-// Construct an interpreter given a Requirement and an evaluation context.
+// Magic certificate features
 //
-Requirement::Interpreter::Interpreter(const Requirement *req, const Context *ctx)
-       : Reader(req), mContext(ctx)
-{
-}
+static CFStringRef appleIntermediateCN = CFSTR("Apple Code Signing Certification Authority");
+static CFStringRef appleIntermediateO = CFSTR("Apple Inc.");
 
 
 //
@@ -56,6 +86,7 @@ Requirement::Interpreter::Interpreter(const Requirement *req, const Context *ctx
 bool Requirement::Interpreter::evaluate()
 {
        ExprOp op = ExprOp(get<uint32_t>());
+       CODESIGN_EVAL_REQINT_OP(op, this->pc() - sizeof(uint32_t));
        switch (op & ~opFlagMask) {
        case opFalse:
                return false;
@@ -115,20 +146,31 @@ bool Requirement::Interpreter::evaluate()
                        Match match(*this);
                        return certFieldGeneric(key, match, cert);
                }
+       case opCertPolicy:
+               {
+                       SecCertificateRef cert = mContext->cert(get<int32_t>());
+                       string key = getString();
+                       Match match(*this);
+                       return certFieldPolicy(key, match, cert);
+               }
        case opTrustedCert:
                return trustedCert(get<int32_t>());
        case opTrustedCerts:
                return trustedCerts();
+       case opNamedAnchor:
+               return fragments().namedAnchor(getString(), *mContext);
+       case opNamedCode:
+               return fragments().named(getString(), *mContext);
        default:
                // opcode not recognized - handle generically if possible, fail otherwise
                if (op & (opGenericFalse | opGenericSkip)) {
                        // unknown opcode, but it has a size field and can be safely bypassed
                        skip(get<uint32_t>());
                        if (op & opGenericFalse) {
-                               secdebug("csinterp", "opcode 0x%x interpreted as false", op);
+                               CODESIGN_EVAL_REQINT_UNKNOWN_FALSE(op);
                                return false;
                        } else {
-                               secdebug("csinterp", "opcode 0x%x ignored; continuing", op);
+                               CODESIGN_EVAL_REQINT_UNKNOWN_SKIPPED(op);
                                return evaluate();
                        }
                }
@@ -189,7 +231,7 @@ bool Requirement::Interpreter::certFieldValue(const string &key, const Match &ma
        for (const CertField *cf = certFields; cf->name; cf++)
                if (cf->name == key) {
                        CFRef<CFStringRef> value;
-                       if (IFDEBUG(OSStatus rc =) SecCertificateCopySubjectComponent(cert, cf->oid, &value.aref())) {
+                       if (OSStatus rc = SecCertificateCopySubjectComponent(cert, cf->oid, &value.aref())) {
                                secdebug("csinterp", "cert %p lookup for DN.%s failed rc=%ld", cert, key.c_str(), rc);
                                return false;
                        }
@@ -211,7 +253,7 @@ bool Requirement::Interpreter::certFieldValue(const string &key, const Match &ma
        return false;
 }
 
-
+       
 bool Requirement::Interpreter::certFieldGeneric(const string &key, const Match &match, SecCertificateRef cert)
 {
        // the key is actually a (binary) OID value
@@ -224,6 +266,18 @@ bool Requirement::Interpreter::certFieldGeneric(const CssmOid &oid, const Match
        return cert && certificateHasField(cert, oid) && match(kCFBooleanTrue);
 }
 
+bool Requirement::Interpreter::certFieldPolicy(const string &key, const Match &match, SecCertificateRef cert)
+{
+       // the key is actually a (binary) OID value
+       CssmOid oid((char *)key.data(), key.length());
+       return certFieldPolicy(oid, match, cert);
+}
+
+bool Requirement::Interpreter::certFieldPolicy(const CssmOid &oid, const Match &match, SecCertificateRef cert)
+{
+       return cert && certificateHasPolicy(cert, oid) && match(kCFBooleanTrue);
+}
+
 
 //
 // Check the Apple-signed condition
@@ -243,11 +297,11 @@ bool Requirement::Interpreter::appleAnchored()
 bool Requirement::Interpreter::appleSigned()
 {
        if (appleAnchored())
-                       if (SecCertificateRef intermed = mContext->cert(-2))    // first intermediate
-                               // first intermediate common name match (exact)
-                               if (certFieldValue("subject.CN", Match(appleIntermediateCN, matchEqual), intermed)
+               if (SecCertificateRef intermed = mContext->cert(-2))    // first intermediate
+                       // first intermediate common name match (exact)
+                       if (certFieldValue("subject.CN", Match(appleIntermediateCN, matchEqual), intermed)
                                        && certFieldValue("subject.O", Match(appleIntermediateO, matchEqual), intermed))
-                                       return true;
+                               return true;
        return false;
 }
 
@@ -379,7 +433,7 @@ Requirement::Interpreter::Match::Match(Interpreter &interp)
        case matchGreaterThan:
        case matchLessEqual:
        case matchGreaterEqual:
-               mValue = makeCFString(interp.getString());
+               mValue.take(makeCFString(interp.getString()));
                break;
        default:
                // Assume this (unknown) match type has a single data argument.
@@ -464,5 +518,49 @@ bool Requirement::Interpreter::Match::inequality(CFTypeRef candidate, CFStringCo
 }
 
 
+//
+// External fragments
+//
+Fragments::Fragments()
+{
+       mMyBundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security"));
+}
+
+
+bool Fragments::evalNamed(const char *type, const std::string &name, const Requirement::Context &ctx)
+{
+       if (CFDataRef fragData = fragment(type, name)) {
+               const Requirement *req = (const Requirement *)CFDataGetBytePtr(fragData);       // was prevalidated as Requirement
+               return req->validates(ctx);
+       }
+       return false;
+}
+
+
+CFDataRef Fragments::fragment(const char *type, const std::string &name)
+{
+       string key = name + "!!" + type;        // compound key
+       StLock<Mutex> _(mLock);                         // lock for cache access
+       FragMap::const_iterator it = mFragments.find(key);
+       if (it == mFragments.end()) {
+               CFRef<CFDataRef> fragData;              // will always be set (NULL on any errors)
+               if (CFRef<CFURLRef> fragURL = CFBundleCopyResourceURL(mMyBundle, CFTempString(name), CFSTR("csreq"), CFTempString(type)))
+                       if (CFRef<CFDataRef> data = cfLoadFile(fragURL)) {      // got data
+                               const Requirement *req = (const Requirement *)CFDataGetBytePtr(data);
+                               if (req->validateBlob(CFDataGetLength(data)))   // looks like a Requirement...
+                                       fragData = data;                        // ... so accept it
+                               else
+                                       Syslog::warning("Invalid sub-requirement at %s", cfString(fragURL).c_str());
+                       }
+               if (CODESIGN_EVAL_REQINT_FRAGMENT_LOAD_ENABLED())
+                       CODESIGN_EVAL_REQINT_FRAGMENT_LOAD(type, name.c_str(), fragData ? CFDataGetBytePtr(fragData) : NULL);
+               mFragments[key] = fragData;             // cache it, success or failure
+               return fragData;
+       }
+       CODESIGN_EVAL_REQINT_FRAGMENT_HIT(type, name.c_str());
+       return it->second;
+}
+
+
 }      // CodeSigning
 }      // Security
index fad9a478ee5bde5b0351e4c9918641acaa015157..ad1ddb8495e2b5ded914110d3856c64491eb6225 100644 (file)
@@ -41,7 +41,7 @@ namespace CodeSigning {
 //     
 class Requirement::Interpreter : public Requirement::Reader {  
 public:
-       Interpreter(const Requirement *req, const Context *ctx);
+       Interpreter(const Requirement *req, const Context *ctx) : Reader(req), mContext(ctx) { }
        
        bool evaluate();
        
@@ -52,7 +52,7 @@ protected:
                Match(CFStringRef value, MatchOperation op) : mValue(value), mOp(op) { } // explicit
                Match() : mValue(NULL), mOp(matchExists) { } // explict test for presence
                bool operator () (CFTypeRef candidate) const; // match to candidate
-               
+
        protected:
                bool inequality(CFTypeRef candidate, CFStringCompareFlags flags, CFComparisonResult outcome, bool negate) const;
                
@@ -67,6 +67,8 @@ protected:
        bool certFieldValue(const string &key, const Match &match, SecCertificateRef cert);
        bool certFieldGeneric(const string &key, const Match &match, SecCertificateRef cert);
        bool certFieldGeneric(const CssmOid &oid, const Match &match, SecCertificateRef cert);
+       bool certFieldPolicy(const string &key, const Match &match, SecCertificateRef cert);
+       bool certFieldPolicy(const CssmOid &oid, const Match &match, SecCertificateRef cert);
        bool verifyAnchor(SecCertificateRef cert, const unsigned char *digest);
        bool appleSigned();
        bool appleAnchored();
index 772adb1c1df7d6a468091be55be143c7e3ac67da..ee1da109a801aa711b9128cb18da0964d4de5808 100644 (file)
@@ -86,7 +86,7 @@ public:
        template <class T>
        Endian<T> &insert(const Label &label, size_t length = sizeof(T))
        { return *reinterpret_cast<Endian<T>*>(insert(label, length)); }
-       
+
        //
        // Help with making operator chains (foo AND bar AND baz...).
        // Note that the empty case (no elements at all) must be resolved by the caller.
index e419f35bc0537ec7ec7bb5d322ed3d491343494c..5a8e94e1057589bcae4dc208f6a8fb14065e2cfc 100644 (file)
@@ -27,6 +27,7 @@
 #include "reqparser.h"
 #include "antlrplugin.h"
 #include "cserror.h"
+#include "codesigning_dtrace.h"
 #include <CoreFoundation/CoreFoundation.h>
 #include <security_utilities/osxcode.h>
 
@@ -50,12 +51,11 @@ ModuleNexus<PluginHost> plugin;
 PluginHost::PluginHost()
 {
        if (CFBundleRef securityFramework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security")))
-               if (CFURLRef plugins = CFBundleCopyBuiltInPlugInsURL(securityFramework))
-                       if (CFRef<CFURLRef> pluginURL = CFURLCreateWithFileSystemPathRelativeToBase(NULL,
-                                       CFSTR("csparser.bundle"), kCFURLPOSIXPathStyle, true, plugins)) {
-                               secdebug("antlrplugin", "loading antlr parser plugin from %s", cfString(pluginURL).c_str());
+               if (CFRef<CFURLRef> plugins = CFBundleCopyBuiltInPlugInsURL(securityFramework))
+                       if (CFRef<CFURLRef> pluginURL = makeCFURL("csparser.bundle", true, plugins)) {
                                plugin = new LoadableBundle(cfString(pluginURL).c_str());
                                plugin->load();
+                               CODESIGN_LOAD_ANTLR();
                                antlr = reinterpret_cast<FindAntlrPlugin *>(plugin->lookupSymbol(FINDANTLRPLUGIN))();
                                return;
                        }
index e4f85e8c17eb84e5be6d7b06531f9d7dfa6bc45e..21e1baac524a0e89dc66a0cb549350a56fa2d22d 100644 (file)
@@ -56,7 +56,7 @@ inline const Requirements *parseRequirements(const Input &source)
 { return RequirementParser<Requirements>()(source); }
 
 template <class Input>
-inline const Requirements *parseGeneric(const Input &source)
+inline const BlobCore *parseGeneric(const Input &source)
 { return RequirementParser<BlobCore>()(source); }
 
 
index 066517f78c00af28c6e1d46748fdad89db39a42e..8c79912b186ef2af05a312eaae81c78da082cc07 100644 (file)
@@ -40,6 +40,9 @@ namespace CodeSigning {
 Requirement::Reader::Reader(const Requirement *req)
        : mReq(req), mPC(sizeof(Requirement))
 {
+       assert(req);
+       if (req->kind() != exprForm)
+               MacOSError::throwMe(errSecCSReqUnsupported);
 }
 
 
index 4a7a2513da2a708c7d811cf1fd81cc9874181805..2db501b463af5087f544a593f5ebdde501470f81 100644 (file)
@@ -75,7 +75,7 @@ T Requirement::Reader::get()
 {
        checkSize(sizeof(T));
        const Endian<const T> *value = mReq->at<Endian<const T> >(mPC);
-       mPC += sizeof(value);
+       mPC += sizeof(T);
        return *value;
 }
 
index f4b294ab74336f647329765f29fcc1e8594909aa..714e6c57ef831c4ea0421293b8840ff46c5922ad 100644 (file)
@@ -26,6 +26,7 @@
 //
 #include "requirement.h"
 #include "reqinterp.h"
+#include "codesigning_dtrace.h"
 #include <security_utilities/errors.h>
 #include <security_utilities/unix++.h>
 #include <security_utilities/logging.h>
@@ -56,7 +57,8 @@ const char *const Requirement::typeNames[] = {
        "host",
        "guest",
        "designated",
-       "library"
+       "library",
+       "plugin",
 };
 
 
@@ -65,13 +67,24 @@ const char *const Requirement::typeNames[] = {
 //
 void Requirement::validate(const Requirement::Context &ctx, OSStatus failure /* = errSecCSReqFailed */) const
 {
+       if (!this->validates(ctx, failure))
+               MacOSError::throwMe(failure);
+}
+
+bool Requirement::validates(const Requirement::Context &ctx, OSStatus failure /* = errSecCSReqFailed */) const
+{
+       CODESIGN_EVAL_REQINT_START((void*)this, this->length());
        switch (kind()) {
        case exprForm:
-               if (!Requirement::Interpreter(this, &ctx).evaluate())
-                       MacOSError::throwMe(failure);
-               return;
+               if (Requirement::Interpreter(this, &ctx).evaluate()) {
+                       CODESIGN_EVAL_REQINT_END(this, 0);
+                       return true;
+               } else {
+                       CODESIGN_EVAL_REQINT_END(this, failure);
+                       return false;
+               }
        default:
-               secdebug("reqval", "unrecognized requirement kind %d", kind());
+               CODESIGN_EVAL_REQINT_END(this, errSecCSReqUnsupported);
                MacOSError::throwMe(errSecCSReqUnsupported);
        }
 }
@@ -141,6 +154,20 @@ const SHA1::Digest &Requirement::testAppleAnchorHash()
 #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
index d15fd1a57fb6adfe4971f44b431552ac2084c4d9..9d20fc489ced3f2f239b9ddf342541acff9f84ff 100644 (file)
@@ -67,7 +67,8 @@ public:
        Kind kind() const { return Kind(uint32_t(mKind)); }
        
        // validate this requirement against a code context
-       void validate(const Context &ctx, OSStatus failure = errSecCSReqFailed) const;
+       void validate(const Context &ctx, OSStatus failure = errSecCSReqFailed) const;  // throws on all failures
+       bool validates(const Context &ctx, OSStatus failure = errSecCSReqFailed) const; // returns on clean miss
        
        // certificate positions (within a standard certificate chain)
        static const int leafCert = 0;          // index for leaf (first in chain)
@@ -101,10 +102,10 @@ struct Requirement::Context {
        Context(CFArrayRef certChain, CFDictionaryRef infoDict, CFDictionaryRef entitlementDict, const CodeDirectory *dir)
                : certs(certChain), info(infoDict), entitlements(entitlementDict), directory(dir) { }
        
-       const CFArrayRef certs;
-       const CFDictionaryRef info;
-       const CFDictionaryRef entitlements;
-       const CodeDirectory * const directory;
+       const CFArrayRef certs;                                         // certificate chain
+       const CFDictionaryRef info;                                     // Info.plist
+       const CFDictionaryRef entitlements;                     // entitlement plist
+       const CodeDirectory * const directory;          // CodeDirectory
 
        SecCertificateRef cert(int ix) const;           // get a cert from the cert chain
        unsigned int certCount() const;                         // length of cert chain
@@ -138,11 +139,11 @@ enum ExprOp {
        opIdent,                                                // match canonical code [string]
        opAppleAnchor,                                  // signed by Apple as Apple's product
        opAnchorHash,                                   // match anchor [cert hash]
-       opInfoKeyValue,                                 // *legacy* match Info.plist field [key; value]
-       opAnd,                                                  // binary prefix expr AND expr
-       opOr,                                                   // binary prefix expr OR expr
-       opCDHash,                                               // match hash of CodeDirectory directly
-       opNot,                                                  // logical inverse
+       opInfoKeyValue,                                 // *legacy* - use opInfoKeyField [key; value]
+       opAnd,                                                  // binary prefix expr AND expr [expr; expr]
+       opOr,                                                   // binary prefix expr OR expr [expr; expr]
+       opCDHash,                                               // match hash of CodeDirectory directly [cd hash]
+       opNot,                                                  // logical inverse [expr]
        opInfoKeyField,                                 // Info.plist key field [string; match suffix]
        opCertField,                                    // Certificate field [cert index; field name; match suffix]
        opTrustedCert,                                  // require trust settings to approve one particular cert [cert index]
@@ -150,6 +151,9 @@ enum ExprOp {
        opCertGeneric,                                  // Certificate component by OID [cert index; oid; match suffix]
        opAppleGenericAnchor,                   // signed by Apple in any capacity
        opEntitlementField,                             // entitlement dictionary field [string; match suffix]
+       opCertPolicy,                                   // Certificate policy by OID [cert index; oid; match suffix]
+       opNamedAnchor,                                  // named anchor type
+       opNamedCode,                                    // named subroutine
        exprOpCount                                             // (total opcode count in use)
 };
 
@@ -173,18 +177,49 @@ enum MatchOperation {
 typedef SuperBlob<0xfade0c01> Requirements;
 
 
-}      // 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);
+       operator const Requirements * () const { return mReqs; }
+
+private:
+       const Requirements *mReqs;
+};
 
 
 //
-// Flipper overloads must go directly into the Security namespace
+// Byte order flippers
 //
-inline CodeSigning::ExprOp h2n(CodeSigning::ExprOp op) { return CodeSigning::ExprOp(h2n(uint32_t(op))); }
-inline CodeSigning::ExprOp n2h(CodeSigning::ExprOp op) { return CodeSigning::ExprOp(n2h(uint32_t(op))); }
-inline CodeSigning::MatchOperation h2n(CodeSigning::MatchOperation op) { return CodeSigning::MatchOperation(h2n(uint32_t(op))); }
-inline CodeSigning::MatchOperation n2h(CodeSigning::MatchOperation op) { return CodeSigning::MatchOperation(n2h(uint32_t(op))); }
+inline CodeSigning::ExprOp h2n(CodeSigning::ExprOp op)
+{
+       uint32_t intOp = (uint32_t) op;
+       return (CodeSigning::ExprOp) ::h2n(intOp);
+}
 
+inline CodeSigning::ExprOp n2h(CodeSigning::ExprOp op)
+{
+       uint32_t intOp = (uint32_t) op;
+       return (CodeSigning::ExprOp) ::n2h(intOp);
+}
 
+
+inline CodeSigning::MatchOperation h2n(CodeSigning::MatchOperation op)
+{
+       return CodeSigning::MatchOperation(::h2n((uint32_t) op));
+}
+
+inline CodeSigning::MatchOperation n2h(CodeSigning::MatchOperation op)
+{
+       return CodeSigning::MatchOperation(::n2h((uint32_t) op));
+}
+
+
+}      // CodeSigning
 }      // Security
 
 #endif //_H_REQUIREMENT
index c1f9bb2e10db2389fc54191cee1aca94c7f67aff..785eb0a7b924a58857a965dd4f1faa3d4aa7d2ff 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
 // resource directory construction and verification
 //
 #include "resources.h"
+#include "csutilities.h"
 #include <Security/CSCommon.h>
-#include <security_codesigning/cfmunge.h>
+#include <security_utilities/unix++.h>
+#include <security_utilities/cfmunge.h>
 
 namespace Security {
 namespace CodeSigning {
@@ -35,8 +37,8 @@ namespace CodeSigning {
 //
 // Construction and maintainance
 //
-ResourceBuilder::ResourceBuilder(const std::string &root, CFDictionaryRef rulesDict)
-       : ResourceEnumerator(root)
+ResourceBuilder::ResourceBuilder(const std::string &root, CFDictionaryRef rulesDict, CodeDirectory::HashAlgorithm hashType)
+       : ResourceEnumerator(root), mHashType(hashType)
 {
        CFDictionary rules(rulesDict, errSecCSResourceRulesInvalid);
        rules.apply(this, &ResourceBuilder::addRule);
@@ -94,7 +96,7 @@ FTSENT *ResourceBuilder::next(string &path, Rule * &rule)
                                }
                                if (!bestRule || rule->weight > bestRule->weight)
                                        bestRule = rule;
-                       }
+               }
                }
                if (!bestRule || (bestRule->flags & omitted))
                        continue;
@@ -111,7 +113,7 @@ FTSENT *ResourceBuilder::next(string &path, Rule * &rule)
 CFDictionaryRef ResourceBuilder::build()
 {
        secdebug("codesign", "start building resource directory");
-       CFRef<CFMutableDictionaryRef> files = makeCFMutableDictionary(0);
+       CFRef<CFMutableDictionaryRef> files = makeCFMutableDictionary();
 
        string path;
        Rule *rule;
@@ -129,11 +131,8 @@ CFDictionaryRef ResourceBuilder::build()
        }
        secdebug("codesign", "finished code directory with %d entries",
                int(CFDictionaryGetCount(files)));
-               
-       return makeCFDictionary(2,
-               CFSTR("rules"), mRawRules.get(),
-               CFSTR("files"), files.get()
-       );
+       
+       return cfmake<CFDictionaryRef>("{rules=%O,files=%O}", mRawRules.get(), files.get());
 }
 
 
@@ -142,12 +141,12 @@ CFDictionaryRef ResourceBuilder::build()
 //
 CFDataRef ResourceBuilder::hashFile(const char *path)
 {
-       CFRef<CFDataRef> data = cfLoadFile(path);
-       secdebug("rdirenum", "  %s (%d bytes)", path, int(CFDataGetLength(data)));
-       SHA1 hasher;
-       hasher(CFDataGetBytePtr(data), CFDataGetLength(data));
-       unsigned char digest[CC_SHA1_DIGEST_LENGTH];
-       hasher.finish(digest);
+       UnixPlusPlus::AutoFileDesc fd(path);
+       fd.fcntl(F_NOCACHE, true);              // turn off page caching (one-pass)
+       MakeHash<ResourceBuilder> hasher(this);
+       hashFileData(fd, hasher.get());
+       Hashing::Byte digest[hasher->digestLength()];
+       hasher->finish(digest);
        return CFDataCreate(NULL, digest, sizeof(digest));
 }
 
@@ -182,6 +181,19 @@ bool ResourceBuilder::Rule::match(const char *s) const
 }
 
 
+std::string ResourceBuilder::escapeRE(const std::string &s)
+{
+       string r;
+       for (string::const_iterator it = s.begin(); it != s.end(); ++it) {
+               char c = *it;
+               if (strchr("\\[]{}().+*", c))
+                       r.push_back('\\');
+               r.push_back(c);
+       }
+       return r;
+}
+
+
 //
 // Resource Seals
 //
@@ -194,8 +206,7 @@ ResourceSeal::ResourceSeal(CFTypeRef it)
                mOptional = false;
        } else {
                mOptional = false;
-               if (!cfscan(it, "{hash=%XO,?optional=%B}", &mHash, &mOptional)
-                               || size_t(CFDataGetLength(mHash)) != SHA1::digestLength)
+               if (!cfscan(it, "{hash=%XO,?optional=%B}", &mHash, &mOptional))
                        MacOSError::throwMe(errSecCSResourcesInvalid);
        }
 }
index 834d8945740bcf07e284bd0ab5e9f598f85fcc2a..69c5851b6cb286b1d03b4565190f1eb8bfc4ba1f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -28,6 +28,7 @@
 #define _H_RSIGN
 
 #include "renum.h"
+#include "codedirectory.h"
 #include <security_utilities/utilities.h>
 #include <security_utilities/cfutilities.h>
 #include <security_utilities/hashing.h>
@@ -47,7 +48,7 @@ namespace CodeSigning {
 //
 class ResourceBuilder : public ResourceEnumerator {
 public:
-       ResourceBuilder(const std::string &root, CFDictionaryRef rules);
+       ResourceBuilder(const std::string &root, CFDictionaryRef rules, CodeDirectory::HashAlgorithm hashType);
        ~ResourceBuilder();
 
        CFDictionaryRef build();
@@ -73,17 +74,21 @@ public:
        };
        void addRule(Rule *rule) { mRules.push_back(rule); }
        void addExclusion(const std::string &pattern) { mRules.insert(mRules.begin(), new Rule(pattern, 0, exclusion)); }
+
+       static std::string escapeRE(const std::string &s);
        
        FTSENT *next(std::string &path, Rule * &rule);  // enumerate next file and match rule
 
 protected:
        void addRule(CFTypeRef key, CFTypeRef value);
        CFDataRef hashFile(const char *path);
+       DynamicHash *getHash() const { return CodeDirectory::hashFor(this->mHashType); }
        
 private:
        CFCopyRef<CFDictionaryRef> mRawRules;
        typedef std::vector<Rule *> Rules;
        Rules mRules;
+       CodeDirectory::HashAlgorithm mHashType;
 };
 
 
diff --git a/lib/security_codesigning.d b/lib/security_codesigning.d
new file mode 100644 (file)
index 0000000..e3029da
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * DTrace static providers at the Code Signing layer
+ */
+#define int32_t int
+#define uint32_t unsigned
+#define mach_port_t uint32_t
+
+
+/*
+ * Basic semantic events of the code signing subsystem
+ */
+provider codesign {
+       probe diskrep__create__macho(void *me, const char *path, const void *ctx);
+       probe diskrep__create__bundle__path(void *me, const char *path, void *ctx, void *exec);
+       probe diskrep__create__bundle__ref(void *me, void *cfbundle, void *ctx, void *exec);
+       probe diskrep__create__file(void *me, const char *path);
+       probe diskrep__create__cfm(void *me, const char *path);
+       probe diskrep__create__slc(void *me, const char *path);
+       probe diskrep__create__detached(void *me, void *orig, const char *source, void *glob);
+       probe diskrep__create__kernel(void *me);
+       probe diskrep__destroy(void *me);
+
+       probe static__create(void *me, void *host);
+       probe dynamic__create(void *me, void *rep);
+       
+       probe static__cdhash(void *me, const void *cdhash, uint32_t length);
+       probe static__attach__explicit(void *me, void *rep);
+       probe static__attach__system(void *me, void *rep);
+
+       probe eval__dynamic__start(void *me, const char *path);
+       probe eval__dynamic__end(void *me);
+       probe eval__dynamic__root(void *me);
+       
+       probe eval__static__start(void *me, const char *path);
+       probe eval__static__end(void *me);
+       probe eval__static__reset(void *me);
+       
+       probe eval__static__executable__start(void *me, const char *path, uint32_t pages);
+       probe eval__static__executable__fail(void *me, uint32_t badPage);
+       probe eval__static__executable__end(void *me);
+       probe eval__static__resources__start(void *me, const char *path, int count);
+       probe eval__static__resources__end(void *me);
+       
+       probe eval__static__directory(void *me);
+       probe eval__static__intreq__start(void *me, uint32_t reqType, void *target, int32_t nullError);
+       probe eval__static__intreq__end(void *me);
+       
+       probe eval__static__signature__start(void *me, const char *path);
+       probe eval__static__signature__adhoc(void *me);
+       probe eval__static__signature__result(void *me, uint32_t result, uint32_t chainLength);
+       probe eval__static__signature__expired(void *me);
+       probe eval__static__signature__end(void *me);
+
+       probe eval__reqint__start(const void *reqdata, uint32_t reqlength);
+       probe eval__reqint__end(const void *reqdata, uint32_t result);
+       probe eval__reqint__op(uint32_t opcode, uint32_t offset);
+       probe eval__reqint__unknown_false(uint32_t opcode);
+       probe eval__reqint__unknown_skipped(uint32_t opcode);
+probe eval__reqint__fragment__load(const char *type, const char *name, const void *req);
+probe eval__reqint__fragment__hit(const char *type, const char *name);
+       
+       probe guest__hostingport(void *host, mach_port_t hostingPort);
+       probe guest__locate__generic(void *host, uint32_t *guestPath, uint32_t guestPathLength, mach_port_t subport);
+       probe guest__identify__process(void *guest, uint32_t guestPid, void *code);
+       probe guest__cdhash__process(void *code, const void *cdhash, uint32_t length);
+       probe guest__identify__generic(void *guest, uint32_t guestRef, void *code);
+       probe guest__cdhash__generic(void *code, const void *cdhash, uint32_t length);
+       
+       probe allocate__validate(const char *path, uint32_t pid);
+       probe allocate__arch(const char *arch, uint32_t size);
+       probe allocate__archn(uint32_t cputype, uint32_t cpusubtype, uint32_t size);
+       probe allocate__write(const char *arch, off_t offset, uint32_t length, uint32_t available);
+       
+       probe sign__dep__macho(void *me, const char *name, const void *requirement);
+       probe sign__dep__interp(void *me, const char *name, const void *requirement);
+
+       probe load__antlr();
+};
index e90c088d28cdff53b61e940fa058bd38d170f54e..9ff71aa5969e92c06a8bfbf44f5f063831e291f7 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2006-2007 Apple Inc. All Rights Reserved.
+# Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
 #
 # @APPLE_LICENSE_HEADER_START@
 #
 # @APPLE_LICENSE_HEADER_END@
 #
 _SecCodeGetTypeID
-_SecGetRootCode
 _SecCodeCopySelf
+_SecCodeCopyInternalRequirement
+_SecCodeGetStatus
+_SecCodeSetStatus
 _SecCodeCopyStaticCode
 _SecCodeCopyHost
 _SecCodeCopyGuestWithAttributes
@@ -34,8 +36,12 @@ _SecCodeCopyDesignatedRequirement
 _SecCodeCopySigningInformation
 _SecCodeMapMemory
 _SecCodeSetDetachedSignature
+_kSecCodeAttributeArchitecture
+_kSecCodeAttributeBundleVersion
+_kSecCodeAttributeSubarchitecture
 _SecStaticCodeGetTypeID
 _SecStaticCodeCreateWithPath
+_SecStaticCodeCreateWithPathAndAttributes
 _SecStaticCodeCheckValidity
 _SecStaticCodeCheckValidityWithErrors
 _SecRequirementGetTypeID
@@ -46,6 +52,10 @@ _SecRequirementCreateWithStringAndErrors
 _SecRequirementCreateGroup
 _SecRequirementCopyData
 _SecRequirementCopyString
+_SecRequirementsCreateFromRequirements
+_SecRequirementsCopyRequirements
+_SecRequirementsCreateWithString
+_SecRequirementsCopyString
 _SecCodeSignerGetTypeID
 _SecCodeSignerCreate
 _SecCodeSignerAddSignature
@@ -56,8 +66,10 @@ _SecHostSetGuestStatus
 _SecHostSelectGuest
 _SecHostSelectedGuest
 _SecHostSetHostingPort
+_kSecCodeDirectoryFlagTable
 _kSecCodeSignerApplicationData
 _kSecCodeSignerDetached
+_kSecCodeSignerDigestAlgorithm
 _kSecCodeSignerDryRun
 _kSecCodeSignerEntitlements
 _kSecCodeSignerFlags
@@ -67,6 +79,7 @@ _kSecCodeSignerIdentity
 _kSecCodeSignerPageSize
 _kSecCodeSignerRequirements
 _kSecCodeSignerResourceRules
+_kSecCodeSignerSDKRoot
 _kSecCodeSignerSigningTime
 _kSecCodeInfoCertificates
 _kSecCodeInfoChangedFiles
@@ -75,17 +88,25 @@ _kSecCodeInfoTime
 _kSecCodeInfoDesignatedRequirement
 _kSecCodeInfoEntitlements
 _kSecCodeInfoFormat
+_kSecCodeInfoDigestAlgorithm
 _kSecCodeInfoIdentifier
 _kSecCodeInfoImplicitDesignatedRequirement
 _kSecCodeInfoMainExecutable
 _kSecCodeInfoPList
 _kSecCodeInfoRequirements
 _kSecCodeInfoRequirementData
+_kSecCodeInfoSource
 _kSecCodeInfoStatus
 _kSecCodeInfoTrust
-_kSecGuestAttributePid
+_kSecCodeInfoUnique
+_kSecCodeInfoCodeDirectory
+_kSecCodeInfoCodeOffset
+_kSecCodeInfoResourceDirectory
 _kSecGuestAttributeCanonical
+_kSecGuestAttributeHash
 _kSecGuestAttributeMachPort
+_kSecGuestAttributePid
+_kSecCFErrorArchitecture
 _kSecCFErrorPattern
 _kSecCFErrorResourceSeal
 _kSecCFErrorResourceAdded
@@ -94,3 +115,11 @@ _kSecCFErrorResourceMissing
 _kSecCFErrorInfoPlist
 _kSecCFErrorGuestAttributes
 _kSecCFErrorRequirementSyntax
+
+
+# Entitlements
+_SecTaskGetTypeID
+_SecTaskCreateWithAuditToken
+_SecTaskCopyValueForEntitlement
+_SecTaskCopyValuesForEntitlements
+
index e2d65de1f7884d2567f4b5a63292b0b3c93c1474..95ad32dccd6f24d7a2167189f2553fbf015c09e0 100644 (file)
@@ -25,6 +25,7 @@
 // sigblob - signature (Super)Blob types
 //
 #include "sigblob.h"
+#include "CSCommon.h"
 
 
 namespace Security {
@@ -36,8 +37,10 @@ CFDataRef EmbeddedSignatureBlob::component(CodeDirectory::SpecialSlot slot) cons
        if (const BlobCore *blob = this->find(slot))
                if (CodeDirectory::slotAttributes(slot) & cdComponentIsBlob)
                        return makeCFData(*blob);       // is a native Blob
+               else if (const BlobWrapper *wrap = BlobWrapper::specific(blob))
+                       return makeCFData(*wrap);
                else
-                       return makeCFData(*BlobWrapper::specific(blob)); // unwrap payload
+                       MacOSError::throwMe(errSecCSSignatureInvalid);
        return NULL;
 }
 
index 9bc9c2b5df6ebf4f2e8b3a02671b65458483aa50..23cbfd64006e9a3b1fff52ea03a0281bd0be9ab9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <Security/SecIdentity.h>
 #include <Security/CMSEncoder.h>
 #include <Security/CMSPrivate.h>
+#include <Security/CSCommonPriv.h>
 #include <CoreFoundation/CFBundlePriv.h>
 #include "renum.h"
+#include "machorep.h"
+#include "csutilities.h"
 #include <security_utilities/unix++.h>
 #include <security_utilities/unixchild.h>
-#include <security_codesigning/cfmunge.h>
+#include <security_utilities/cfmunge.h>
 
 namespace Security {
 namespace CodeSigning {
@@ -46,9 +49,45 @@ namespace CodeSigning {
 //
 void SecCodeSigner::Signer::sign(SecCSFlags flags)
 {
-       // set up access to the subject Code
        rep = code->diskRep()->base();
-       
+       this->prepare(flags);
+       if (Universal *fat = state.mNoMachO ? NULL : rep->mainExecutableImage()) {
+               signMachO(fat);
+       } else {
+               signArchitectureAgnostic();
+       }
+}
+
+
+//
+// Remove any existing code signature from code
+//
+void SecCodeSigner::Signer::remove(SecCSFlags flags)
+{
+       // can't remove a detached signature
+       if (state.mDetached)
+               MacOSError::throwMe(errSecCSNotSupported);
+
+       rep = code->diskRep();
+       if (Universal *fat = state.mNoMachO ? NULL : rep->mainExecutableImage()) {
+               // architecture-sensitive removal
+               MachOEditor editor(rep->writer(), *fat, kSecCodeSignatureNoHash, rep->mainExecutablePath());
+               editor.allocate();              // create copy
+               editor.commit();                // commit change
+       } else {
+               // architecture-agnostic removal
+               RefPointer<DiskRep::Writer> writer = rep->writer();
+               writer->remove();
+               writer->flush();
+       }
+}
+
+
+//
+// Contemplate the object-to-be-signed and set up the Signer state accordingly.
+//
+void SecCodeSigner::Signer::prepare(SecCSFlags flags)
+{
        // get the Info.plist out of the rep for some creative defaulting
        CFRef<CFDictionaryRef> infoDict;
        if (CFRef<CFDataRef> infoData = rep->component(cdInfoSlot))
@@ -57,9 +96,11 @@ void SecCodeSigner::Signer::sign(SecCSFlags flags)
        // work out the canonical identifier
        identifier = state.mIdentifier;
        if (identifier.empty()) {
-               identifier = rep->recommendedIdentifier();
-               if (identifier.find('.') == string::npos && !state.mIdentifierPrefix.empty())
+               identifier = rep->recommendedIdentifier(state);
+               if (identifier.find('.') == string::npos)
                        identifier = state.mIdentifierPrefix + identifier;
+               if (identifier.find('.') == string::npos && state.isAdhoc())
+                       identifier = identifier + "-" + uniqueName();
                secdebug("signer", "using default identifier=%s", identifier.c_str());
        } else
                secdebug("signer", "using explicit identifier=%s", identifier.c_str());
@@ -74,37 +115,40 @@ void SecCodeSigner::Signer::sign(SecCSFlags flags)
                        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.dict", cdFlags);
+                                       secdebug("signer", "using numeric cdFlags=0x%x from Info.plist", cdFlags);
                                } else if (CFGetTypeID(csflags) == CFStringGetTypeID()) {
-                                       cdFlags = CodeDirectory::textFlags(cfString(CFStringRef(csflags)));
-                                       secdebug("signer", "using text cdFlags=0x%x from Info.dict", cdFlags);
+                                       cdFlags = cdTextFlags(cfString(CFStringRef(csflags)));
+                                       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 allow that
+               cdFlags |= kSecCodeSignatureAdhoc;      // ... so note that
        
        // prepare the resource directory, if any
        string rpath = rep->resourcesRootPath();
        if (!rpath.empty()) {
                // explicitly given resource rules always win
-               CFCopyRef<CFDictionaryRef> resourceRules(state.mResourceRules);
+               CFCopyRef<CFDictionaryRef> resourceRules = state.mResourceRules;
                
                // embedded resource rules come next
-               if (!resourceRules)
-                       if (CFTypeRef spec = CFDictionaryGetValue(infoDict, _kCFBundleResourceSpecificationKey))
+               if (!resourceRules && infoDict)
+                       if (CFTypeRef spec = CFDictionaryGetValue(infoDict, _kCFBundleResourceSpecificationKey)) {
                                if (CFGetTypeID(spec) == CFStringGetTypeID())
                                        if (CFRef<CFDataRef> data = cfLoadFile(rpath + "/" + cfString(CFStringRef(spec))))
-                                               if (CFRef<CFDictionaryRef> dict = makeCFDictionaryFrom(data))
-                                                       resourceRules = dict;
+                                               if (CFDictionaryRef dict = makeCFDictionaryFrom(data))
+                                                       resourceRules.take(dict);
+                               if (!resourceRules)     // embedded rules present but unacceptable
+                                       MacOSError::throwMe(errSecCSResourceRulesInvalid);
+                       }
 
                // finally, ask the DiskRep for its default
                if (!resourceRules)
-                       resourceRules.take(rep->defaultResourceRules());
+                       resourceRules.take(rep->defaultResourceRules(state));
                
                // build the resource directory
-               ResourceBuilder resources(rpath, cfget<CFDictionaryRef>(resourceRules, "rules"));
-               rep->adjustResources(resources);
+               ResourceBuilder resources(rpath, cfget<CFDictionaryRef>(resourceRules, "rules"), digestAlgorithm());
+               rep->adjustResources(resources);        // DiskRep-specific adjustments
                CFRef<CFDictionaryRef> rdir = resources.build();
                resourceDirectory.take(CFPropertyListCreateXMLData(NULL, rdir));
        }
@@ -122,13 +166,7 @@ void SecCodeSigner::Signer::sign(SecCSFlags flags)
                signingTime = time;
        }
        
-       pagesize = state.mPageSize ? cfNumber<size_t>(state.mPageSize) : rep->pageSize();
-       
-       if (Universal *fat = state.mNoMachO ? NULL : rep->mainExecutableImage()) {
-               signMachO(fat);
-       } else {
-               signArchitectureAgnostic();
-       }
+       pagesize = state.mPageSize ? cfNumber<size_t>(state.mPageSize) : rep->pageSize(state);
 }
 
 
@@ -143,7 +181,7 @@ void SecCodeSigner::Signer::signMachO(Universal *fat)
        // Mach-O executable at the core - perform multi-architecture signing
        auto_ptr<ArchEditor> editor(state.mDetached
                ? static_cast<ArchEditor *>(new BlobEditor(*fat, *this))
-               : new MachOEditor(rep->writer(), *fat, rep->mainExecutablePath()));
+               : new MachOEditor(rep->writer(), *fat, this->digestAlgorithm(), rep->mainExecutablePath()));
        assert(editor->count() > 0);
        if (!editor->attribute(writerNoGlobal)) // can store architecture-common components
                populate(*editor);
@@ -152,11 +190,19 @@ void SecCodeSigner::Signer::signMachO(Universal *fat)
        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));
+               arch.ireqs(state.mRequirements, rep->defaultRequirements(&arch.architecture, state));
                if (editor->attribute(writerNoGlobal))  // can't store globally, add per-arch
                        populate(arch);
                populate(arch.cdbuilder, arch, arch.ireqs,
                        arch.source->offset(), arch.source->signingExtent());
+       
+               // add identification blob (made from this architecture) only if we're making a detached signature
+               if (state.mDetached) {
+                       CFRef<CFDataRef> identification = MachORep::identificationFor(arch.source.get());
+                       arch.add(cdIdentificationSlot, BlobWrapper::alloc(
+                               CFDataGetBytePtr(identification), CFDataGetLength(identification)));
+               }
+               
                // prepare SuperBlob size estimate
                size_t cdSize = arch.cdbuilder.size();
                arch.blobSize = arch.size(cdSize, state.mCMSSize, 0);
@@ -198,11 +244,18 @@ void SecCodeSigner::Signer::signArchitectureAgnostic()
        // non-Mach-O executable - single-instance signing
        RefPointer<DiskRep::Writer> writer = state.mDetached ?
                (new DetachedBlobWriter(*this)) : rep->writer();
-       CodeDirectory::Builder builder;
+       CodeDirectory::Builder builder(state.mDigestAlgorithm);
        InternalRequirements ireqs;
-       ireqs(state.mRequirements, rep->defaultRequirements(NULL));
+       ireqs(state.mRequirements, rep->defaultRequirements(NULL, state));
        populate(*writer);
        populate(builder, *writer, ireqs, rep->signingBase(), rep->signingLimit());
+       
+       // add identification blob (made from this architecture) only if we're making a detached signature
+       if (state.mDetached) {
+               CFRef<CFDataRef> identification = rep->identification();
+               writer->component(cdIdentificationSlot, identification);
+       }
+       
        CodeDirectory *cd = builder.build();
        CFRef<CFDataRef> signature = signCodeDirectory(cd);
        if (!state.mDryRun) {
@@ -238,36 +291,25 @@ void SecCodeSigner::Signer::populate(CodeDirectory::Builder &builder, DiskRep::W
        builder.flags(cdFlags);
        builder.identifier(identifier);
        
-       for (CodeDirectory::Slot slot = cdSlotMax; slot >= 1; --slot)
-               switch (slot) {
-               case cdRequirementsSlot:
-                       if (ireqs) {
-                               CFRef<CFDataRef> data = makeCFData(*ireqs);
-                               writer.component(cdRequirementsSlot, data);
-                               builder.special(slot, data);
-                       }
-                       break;
-               case cdResourceDirSlot:
-                       if (resourceDirectory)
-                               builder.special(slot, resourceDirectory);
-                       break;
-               case cdApplicationSlot:
+       if (CFDataRef data = rep->component(cdInfoSlot))
+               builder.specialSlot(cdInfoSlot, data);
+       if (ireqs) {
+               CFRef<CFDataRef> data = makeCFData(*ireqs);
+               writer.component(cdRequirementsSlot, data);
+               builder.specialSlot(cdRequirementsSlot, data);
+       }
+       if (resourceDirectory)
+               builder.specialSlot(cdResourceDirSlot, resourceDirectory);
 #if NOT_YET
-                       if (state.mApplicationData)
-                               builder.special(slot, state.mApplicationData);
+       if (state.mApplicationData)
+               builder.specialSlot(cdApplicationSlot, state.mApplicationData);
 #endif
-                       break;
-               case cdEntitlementSlot:
-                       if (state.mEntitlementData) {
-                               writer.component(cdEntitlementSlot, state.mEntitlementData);
-                               builder.special(slot, state.mEntitlementData);
-                       }
-                       break;
-               default:
-                       if (CFDataRef data = rep->component(slot))
-                               builder.special(slot, data);
-                       break;
-               }
+       if (state.mEntitlementData) {
+               writer.component(cdEntitlementSlot, state.mEntitlementData);
+               builder.specialSlot(cdEntitlementSlot, state.mEntitlementData);
+       }
+       
+       writer.addDiscretionary(builder);
 }
 
 
@@ -301,5 +343,56 @@ CFDataRef SecCodeSigner::Signer::signCodeDirectory(const CodeDirectory *cd)
 }
 
 
+//
+// Parse a text of the form
+//     flag,...,flag
+// where each flag is the canonical name of a signable CodeDirectory flag.
+// No abbreviations are allowed, and internally set flags are not accepted.
+//
+uint32_t SecCodeSigner::Signer::cdTextFlags(std::string text)
+{
+       uint32_t flags = 0;
+       for (string::size_type comma = text.find(','); ; text = text.substr(comma+1), comma = text.find(',')) {
+               string word = (comma == string::npos) ? text : text.substr(0, comma);
+               const SecCodeDirectoryFlagTable *item;
+               for (item = kSecCodeDirectoryFlagTable; item->name; item++)
+                       if (item->signable && word == item->name) {
+                               flags |= item->value;
+                               break;
+                       }
+               if (!item->name)        // not found
+                       MacOSError::throwMe(errSecCSInvalidFlags);
+               if (comma == string::npos)      // last word
+                       break;
+       }
+       return flags;
+}
+
+
+//
+// Generate a unique string from our underlying DiskRep.
+// We could get 90%+ of the uniquing benefit by just generating
+// a random string here. Instead, we pick the (hex string encoding of)
+// the source rep's unique identifier blob. For universal binaries,
+// this is the canonical local architecture, which is a bit arbitrary.
+// This provides us with a consistent unique string for all architectures
+// of a fat binary, *and* (unlike a random string) is reproducible
+// for identical inputs, even upon resigning.
+//
+std::string SecCodeSigner::Signer::uniqueName() const
+{
+       CFRef<CFDataRef> identification = rep->identification();
+       const UInt8 *ident = CFDataGetBytePtr(identification);
+       const unsigned int length = CFDataGetLength(identification);
+       string result;
+       for (unsigned int n = 0; n < length; n++) {
+               char hex[3];
+               snprintf(hex, sizeof(hex), "%02x", ident[n]);
+               result += hex;
+       }
+       return result;
+}
+
+
 } // end namespace CodeSigning
 } // end namespace Security
index ba236d1f1fdbb5d6d5b8d290497908b43f231766..9bef12705651f52e39cd115dd94eb4d1117ccd43 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -47,11 +47,17 @@ class SecCodeSigner::Signer {
 public:
        Signer(SecCodeSigner &s, SecStaticCode *c) : state(s), code(c) { }
        void sign(SecCSFlags flags);
+       void remove(SecCSFlags flags);
        
        SecCodeSigner &state;
        SecStaticCode * const code;
        
+       CodeDirectory::HashAlgorithm digestAlgorithm() const { return state.mDigestAlgorithm; }
+       
+       std::string path() const { return cfString(rep->canonicalPath()); }
+       
 protected:
+       void prepare(SecCSFlags flags);                         // set up signing parameters
        void signMachO(Universal *fat);                         // sign a Mach-O binary
        void signArchitectureAgnostic();                        // sign anything else
 
@@ -59,6 +65,9 @@ protected:
        void populate(CodeDirectory::Builder &builder, DiskRep::Writer &writer,
                InternalRequirements &ireqs, size_t offset = 0, size_t length = 0);     // per-architecture
        CFDataRef signCodeDirectory(const CodeDirectory *cd);
+
+       uint32_t cdTextFlags(std::string text);         // convert text CodeDirectory flags
+       std::string uniqueName() const;                         // derive unique string from rep
        
 private:
        RefPointer<DiskRep> rep;                // DiskRep of Code being signed
index 6d3bc155364d343046ce683eddeec559c33c6c6e..1f0eab83a4df825faa8f927f5518b2735b25421d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <Security/SecIdentity.h>
 #include <Security/CMSEncoder.h>
 #include "renum.h"
+#include "csutilities.h"
 #include <security_utilities/unix++.h>
 #include <security_utilities/unixchild.h>
 #include <vector>
 
 // for helper validation
 #include "Code.h"
-#include "cfmunge.h"
+#include <security_utilities/cfmunge.h>
 #include <sys/codesign.h>
 
 
@@ -53,21 +54,6 @@ static const char helperOverride[] = "CODESIGN_ALLOCATE";
 static const size_t csAlign = 16;
 
 
-//
-// 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();
-}
-
-
 //
 // BlobWriters
 //
@@ -80,8 +66,8 @@ void BlobWriter::component(CodeDirectory::SpecialSlot slot, CFDataRef data)
 void DetachedBlobWriter::flush()
 {
        EmbeddedSignatureBlob *blob = this->make();
-       signer.code->detachedSignature(CFTempData(*blob));
-       signer.state.returnDetachedSignature(blob);
+       signer.code->detachedSignature(makeCFData(*blob));
+       signer.state.returnDetachedSignature(blob, signer);
        ::free(blob);
 }
 
@@ -89,14 +75,14 @@ void DetachedBlobWriter::flush()
 //
 // ArchEditor
 //
-ArchEditor::ArchEditor(Universal &code, uint32_t attrs /* = 0 */)
+ArchEditor::ArchEditor(Universal &code, CodeDirectory::HashAlgorithm hashType, uint32_t attrs)
        : DiskRep::Writer(attrs)
 {
        Universal::Architectures archList;
        code.architectures(archList);
        for (Universal::Architectures::const_iterator it = archList.begin();
                        it != archList.end(); ++it)
-               architecture[*it] = new Arch(*it);
+               architecture[*it] = new Arch(*it, hashType);
 }
 
 
@@ -110,6 +96,11 @@ ArchEditor::~ArchEditor()
 //
 // BlobEditor
 //
+BlobEditor::BlobEditor(Universal &fat, SecCodeSigner::Signer &s)
+       : ArchEditor(fat, s.digestAlgorithm(), 0), signer(s)
+{ }
+
+
 void BlobEditor::component(CodeDirectory::SpecialSlot slot, CFDataRef data)
 {
        mGlobal.component(slot, data);
@@ -128,7 +119,7 @@ void BlobEditor::commit()
 
        // finish up the superblob and deliver it
        DetachedSignatureBlob *blob = mMaker.make();
-       signer.state.returnDetachedSignature(blob);
+       signer.state.returnDetachedSignature(blob, signer);
        ::free(blob);
 }
 
@@ -138,9 +129,13 @@ void BlobEditor::commit()
 // "drill up" the Mach-O binary for insertion of Code Signing signature data.
 // After the tool succeeds, we open the new file and are ready to write it.
 //
-MachOEditor::MachOEditor(DiskRep::Writer *w, Universal &code, std::string srcPath)
-       : ArchEditor(code, w->attributes()), writer(w), sourcePath(srcPath), tempPath(srcPath + ".cstemp"),
-         mNewCode(NULL), mTempMayExist(false)
+MachOEditor::MachOEditor(DiskRep::Writer *w, Universal &code, CodeDirectory::HashAlgorithm hashType, std::string srcPath)
+       : ArchEditor(code, hashType, w->attributes()),
+         writer(w),
+         sourcePath(srcPath),
+         tempPath(srcPath + ".cstemp"),
+         mNewCode(NULL),
+         mTempMayExist(false)
 {
        if (const char *path = getenv(helperOverride)) {
                mHelperPath = path;
@@ -156,24 +151,7 @@ MachOEditor::~MachOEditor()
        delete mNewCode;
        if (mTempMayExist)
                ::remove(tempPath.c_str());             // ignore error (can't do anything about it)
-
-       //@@@ this code should be in UnixChild::kill() -- migrate it there
-       if (state() == alive) {
-               this->kill(SIGTERM);            // shoot it once
-               checkChildren();                        // check for quick death
-               if (state() == alive) {
-                       usleep(500000);                 // give it some grace
-                       if (state() == alive) { // could have been reaped by another thread
-                               checkChildren();        // check again
-                               if (state() == alive) { // it... just... won't... die...
-                                       this->kill(SIGKILL); // take THAT!
-                                       checkChildren();
-                                       if (state() == alive) // stuck zombie
-                                               abandon();      // leave the body behind
-                               }
-                       }
-               }
-       }
+       this->kill();
 }
 
 
@@ -202,20 +180,26 @@ void MachOEditor::allocate()
        mNewCode = new Universal(mFd);
 }
 
-static const unsigned char appleReq[] = {      // anchor apple
-       0xfa, 0xde, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03,
+static const unsigned char appleReq[] = {
+       // anchor apple and info["Application-Group"] = "com.apple.tool.codesign_allocate"
+       0xfa, 0xde, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06,
+       0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x11, 0x41, 0x70, 0x70, 0x6c,
+       0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x70, 0x70, 0x6c,
+       0x65, 0x2e, 0x74, 0x6f, 0x6f, 0x6c, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x5f,
+       0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x65,
 };
 
 void MachOEditor::parentAction()
 {
        if (mHelperOverridden) {
-               secdebug("machoedit", "validating alternate codesign_allocate at %s (pid=%d)", mHelperPath, this->pid());
+               CODESIGN_ALLOCATE_VALIDATE((char*)mHelperPath, this->pid());
                // check code identity of an overridden allocation helper
                SecPointer<SecStaticCode> code = new SecStaticCode(DiskRep::bestGuess(mHelperPath));
                code->validateDirectory();
                code->validateExecutable();
                code->validateResources();
-               code->validateRequirements((const Requirement *)appleReq, errSecCSReqFailed);
+               code->validateRequirement((const Requirement *)appleReq, errSecCSReqFailed);
        }
 }
 
@@ -229,14 +213,16 @@ void MachOEditor::childAction()
        arguments.push_back(tempPath.c_str());
        
        for (Iterator it = architecture.begin(); it != architecture.end(); ++it) {
-               char *size;                             // we'll leak this (execv is coming soon)
-               asprintf(&size, "%d", LowLevelMemoryUtilities::alignUp(it->second->blobSize, csAlign));
-               secdebug("machoedit", "preparing %s size=%s", it->first.name(), size);
+               size_t size = LowLevelMemoryUtilities::alignUp(it->second->blobSize, csAlign);
+               char *ssize;                    // we'll leak this (execv is coming soon)
+               asprintf(&ssize, "%d", size);
 
                if (const char *arch = it->first.name()) {
+                       CODESIGN_ALLOCATE_ARCH((char*)arch, size);
                        arguments.push_back("-a");
                        arguments.push_back(arch);
                } else {
+                       CODESIGN_ALLOCATE_ARCHN(it->first.cpuType(), it->first.cpuSubtype(), size);
                        arguments.push_back("-A");
                        char *anum;
                        asprintf(&anum, "%d", it->first.cpuType());
@@ -244,7 +230,7 @@ void MachOEditor::childAction()
                        asprintf(&anum, "%d", it->first.cpuSubtype());
                        arguments.push_back(anum);
                }
-               arguments.push_back(size);
+               arguments.push_back(ssize);
        }
        arguments.push_back(NULL);
        
@@ -270,8 +256,7 @@ void MachOEditor::write(Arch &arch, EmbeddedSignatureBlob *blob)
 {
        if (size_t offset = arch.source->signingOffset()) {
                size_t signingLength = arch.source->signingLength();
-               secdebug("codesign", "writing architecture %s at 0x%zx (%zd of %zd)",
-                       arch.architecture.name(), offset, blob->length(), signingLength);
+               CODESIGN_ALLOCATE_WRITE((char*)arch.architecture.name(), offset, blob->length(), signingLength);
                if (signingLength < blob->length())
                        MacOSError::throwMe(errSecCSCMSTooLarge);
                arch.source->seek(offset);
@@ -305,7 +290,14 @@ void MachOEditor::commit()
                UidGuard guard;
                if (!guard.seteuid(0))
                        guard.seteuid(st.st_uid);
+               
+               // copy metadata from original file...
                copy(sourcePath.c_str(), NULL, COPYFILE_SECURITY | COPYFILE_METADATA);
+               
+               // ... but explicitly update the timestamps since we did change the file
+               char buf;
+               mFd.read(&buf, sizeof(buf), 0);
+               mFd.write(&buf, sizeof(buf), 0);
 
                // move the new file into place
                UnixError::check(::rename(tempPath.c_str(), sourcePath.c_str()));
@@ -314,36 +306,5 @@ void MachOEditor::commit()
 }
 
 
-//
-// Copyfile
-//
-Copyfile::Copyfile()
-{
-       if (!(mState = copyfile_state_alloc()))
-               UnixError::throwMe();
-}
-       
-void Copyfile::set(uint32_t flag, const void *value)
-{
-       check(::copyfile_state_set(mState, flag, value));
-}
-
-void Copyfile::get(uint32_t flag, void *value)
-{
-       check(::copyfile_state_set(mState, flag, value));
-}
-       
-void Copyfile::operator () (const char *src, const char *dst, copyfile_flags_t flags)
-{
-       check(::copyfile(src, dst, mState, flags));
-}
-
-void Copyfile::check(int rc)
-{
-       if (rc < 0)
-               UnixError::throwMe();
-}
-
-
 } // end namespace CodeSigning
 } // end namespace Security
index 2c0f958c7299348f5b0bca457499a3e65e2e599d..92d48f37256cbeaa6b552ce4eceb02e3c1de2eef 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
 #include <security_utilities/unix++.h>
 #include <security_utilities/unixchild.h>
 
-extern "C" {
-#include <copyfile.h>
-}
-
 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);
-       operator const Requirements * () const { return mReqs; }
-
-private:
-       const Requirements *mReqs;
-};
-
-
 //
 // A DiskRep::Writer that assembles data in a SuperBlob (in memory)
 //
@@ -85,7 +66,7 @@ public:
 //
 class ArchEditor : public DiskRep::Writer {
 public:
-       ArchEditor(Universal &fat, uint32_t attrs = 0);
+       ArchEditor(Universal &fat, CodeDirectory::HashAlgorithm hashType, uint32_t attrs);
        virtual ~ArchEditor();
 
 public:
@@ -101,7 +82,8 @@ public:
                InternalRequirements ireqs;             // consolidated internal requirements
                size_t blobSize;                                // calculated SuperBlob size
                
-               Arch(const Architecture &arch) : architecture(arch) { }
+               Arch(const Architecture &arch, CodeDirectory::HashAlgorithm hashType)
+                       : architecture(arch), cdbuilder(hashType) { }
        };
 
        //
@@ -131,8 +113,7 @@ protected:
 //
 class BlobEditor : public ArchEditor {
 public:
-       BlobEditor(Universal &fat, SecCodeSigner::Signer &s) : ArchEditor(fat), signer(s) { }
-       ~BlobEditor() { }
+       BlobEditor(Universal &fat, SecCodeSigner::Signer &s);
        
        SecCodeSigner::Signer &signer;
        
@@ -150,10 +131,12 @@ private:
 
 //
 // An ArchEditor that writes its signatures into a (fat) binary file.
+// We do this by forking a helper tool (codesign_allocate) and asking
+// it to make a copy with suitable space "opened up" in the right spots.
 //
 class MachOEditor : public ArchEditor, private UnixPlusPlus::Child {
 public:
-       MachOEditor(DiskRep::Writer *w, Universal &code, std::string srcPath);
+       MachOEditor(DiskRep::Writer *w, Universal &code, CodeDirectory::HashAlgorithm hashType, std::string srcPath);
        ~MachOEditor();
 
        const RefPointer<DiskRep::Writer> writer;
@@ -167,73 +150,21 @@ public:
        void commit();
        
 private:
+       // fork operation
        void childAction();
        void parentAction();
        
+       // controlling the temporary file copy
        Universal *mNewCode;
        UnixPlusPlus::AutoFileDesc mFd;
        bool mTempMayExist;
        
+       // finding and managing the helper tool
        const char *mHelperPath;
        bool mHelperOverridden;
 };
 
 
-//
-// Encapsulation of the copyfile(3) API.
-// This is slated to go into utilities once stable.
-//
-class Copyfile {
-public:
-       Copyfile();
-       ~Copyfile()     { copyfile_state_free(mState); }
-       
-       operator copyfile_state_t () const { return mState; }
-       
-       void set(uint32_t flag, const void *value);
-       void get(uint32_t flag, void *value);
-       
-       void operator () (const char *src, const char *dst, copyfile_flags_t flags);
-
-private:
-       void check(int rc);
-       
-private:
-       copyfile_state_t mState;
-};
-
-
-//
-// A reliable uid set/reset bracket
-//
-class UidGuard {
-public:
-       UidGuard() : mPrevious(-1) { }
-       UidGuard(uid_t uid) : mPrevious(-1) { seteuid(uid); }
-       ~UidGuard()
-       {
-               if (active())
-                       UnixError::check(::seteuid(mPrevious));
-       }
-       
-       bool seteuid(uid_t uid)
-       {
-               if (uid == geteuid())
-                       return true;    // no change, don't bother the kernel
-               if (!active())
-                       mPrevious = ::geteuid();
-               return ::seteuid(uid) == 0;
-       }
-       
-       bool active() const { return mPrevious != uid_t(-1); }
-       operator bool () const { return active(); }
-       uid_t saved() const { assert(active()); return mPrevious; }
-
-private:
-       uid_t mPrevious;
-};
-
-
 } // end namespace CodeSigning
 } // end namespace Security
 
index 8331a5a5eb5ea0d1716dde90bd015c381d93b55c..154ed2e927e9bc5f278e3efd6b27e2cb9b9c571a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -25,7 +25,8 @@
 // singlediskrep - semi-abstract diskrep for a single file of some kind
 //
 #include "singlediskrep.h"
-
+#include "csutilities.h"
+#include <security_utilities/cfutilities.h>
 
 namespace Security {
 namespace CodeSigning {
@@ -36,12 +37,27 @@ using namespace UnixPlusPlus;
 //
 // Construct a SingleDiskRep
 //
-SingleDiskRep::SingleDiskRep(const char *path)
+SingleDiskRep::SingleDiskRep(const std::string &path)
        : mPath(path)
 {
 }
 
 
+//
+// The default binary identification of a SingleDiskRep is the (SHA-1) hash
+// of the entire file itself.
+//
+CFDataRef SingleDiskRep::identification()
+{
+       SHA1 hash;
+       this->fd().seek(0);
+       hashFileData(this->fd(), &hash);
+       SHA1::Digest digest;
+       hash.finish(digest);
+       return makeCFData(digest, sizeof(digest));
+}
+
+
 //
 // Both the canonical and main executable path of a SingleDiskRep is, well, its path.
 //
@@ -56,20 +72,6 @@ string SingleDiskRep::mainExecutablePath()
 }
 
 
-//
-// The recommended identifier of a SingleDiskRep is, absent any better clue,
-// the basename of its path.
-//
-string SingleDiskRep::recommendedIdentifier()
-{      
-       string::size_type p = mPath.rfind('/');
-       if (p == string::npos)
-               return mPath;
-       else
-               return mPath.substr(p+1);
-}
-
-
 //
 // The default signing limit is the size of the file.
 // This will do unless the signing data gets creatively stuck in there somewhere.
@@ -100,6 +102,16 @@ void SingleDiskRep::flush()
 }
 
 
+//
+// The recommended identifier of a SingleDiskRep is, absent any better clue,
+// the basename of its path.
+//
+string SingleDiskRep::recommendedIdentifier(const SigningContext &)
+{
+       return canonicalIdentifier(mPath);
+}
+
+
 //
 // Prototype Writers
 //
index e66ec471459a4a34f754f4b89e80919eac922c44..2ff73e10787a298e530e2e991dc887597c114050 100644 (file)
@@ -44,15 +44,17 @@ namespace CodeSigning {
 //
 class SingleDiskRep : public DiskRep {
 public:
-       SingleDiskRep(const char *path);
+       SingleDiskRep(const std::string &path);
 
+       CFDataRef identification();                                                             // partial file hash
        std::string mainExecutablePath();                                               // base path
        CFURLRef canonicalPath();                                                               // base path
-       std::string recommendedIdentifier();                                    // basename(path)
        size_t signingLimit();                                                                  // size of file
        UnixPlusPlus::FileDesc &fd();                                                   // readable fd for this file
        void flush();                                                                                   // close cached fd
        
+       std::string recommendedIdentifier(const SigningContext &ctx); // basename(path)
+       
 public:
        class Writer;
        
diff --git a/lib/slcrep.cpp b/lib/slcrep.cpp
new file mode 100644 (file)
index 0000000..254d651
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2009 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@
+ */
+
+//
+// slcrep - DiskRep representing the Mac OS Shared Library Cache
+//
+#include "slcrep.h"
+
+
+namespace Security {
+namespace CodeSigning {
+
+using namespace UnixPlusPlus;
+
+
+//
+// Object management.
+// We open the file lazily, so nothing much happens on constructions.
+// We can construct directly from a file path, or from an architecture
+// (represented by Context), which will find the file in its usual
+// location on disk.
+//
+DYLDCacheRep::DYLDCacheRep(const char *path)
+       : SingleDiskRep(path), mCache(path)
+{
+       this->setup();
+}
+
+DYLDCacheRep::DYLDCacheRep(const Context *ctx)
+       : SingleDiskRep(DYLDCache::pathFor(((ctx && ctx->arch) ? ctx->arch : Architecture::local()))),
+         mCache(this->path())
+{
+       this->setup();
+}
+
+void DYLDCacheRep::setup()
+{
+       mSigningData = NULL;
+       if (mCache.totalSize() >= mCache.mapSize() + sizeof(BlobCore)) {
+               const EmbeddedSignatureBlob *blob = mCache.at<const EmbeddedSignatureBlob>(mCache.mapSize());
+               if (mCache.totalSize() >= mCache.mapSize() + blob->length())    // entire blob fits in file
+                       mSigningData = blob;
+       }
+       CODESIGN_DISKREP_CREATE_SLC(this, (char*)this->mainExecutablePath().c_str());
+}
+
+
+//
+// Sniffer function for "plausible shared library cache file".
+//
+bool DYLDCacheRep::candidate(FileDesc &fd)
+{
+       return DYLDCache::validate(fd);
+}
+
+
+//
+// Default to system page size for segmented (paged) signatures
+//
+size_t DYLDCacheRep::pageSize(const SigningContext &)
+{
+       return segmentedPageSize;
+}
+
+
+//
+// Retrieve a component from the executable.
+// Our mCache has mapped the entire file, so we just fish the contents out of
+// the mapped area as needed.
+//
+CFDataRef DYLDCacheRep::component(CodeDirectory::SpecialSlot slot)
+{
+       return mSigningData ? mSigningData->component(slot) : NULL;
+}
+
+
+//
+// Provide a (vaguely) human readable characterization of this code
+//
+string DYLDCacheRep::format()
+{
+       if (const char *name = mCache.architecture().name()) {
+               char result[100];
+               snprintf(result, sizeof(result), "OS X Shared Library Cache (%s @ 0x%llx)",
+                       name, mCache.baseAddress());
+               return result;
+       } else
+               return "OS X Shared Library Cache (unknown type)";
+}
+
+
+//
+// DYLDCacheRep::Writers
+//
+DiskRep::Writer *DYLDCacheRep::writer()
+{
+       return new Writer(this);
+}
+
+
+//
+// Write a component.
+//
+void DYLDCacheRep::Writer::component(CodeDirectory::SpecialSlot slot, CFDataRef data)
+{
+       EmbeddedSignatureBlob::Maker::component(slot, data);
+}
+
+
+//
+// Append the superblob we built to the cache file.
+//
+void DYLDCacheRep::Writer::flush()
+{
+       delete mSigningData;                    // ditch previous blob just in case
+       mSigningData = Maker::make();   // assemble new signature SuperBlob
+       fd().seek(rep->mCache.mapSize()); // end of impage proper
+       fd().writeAll(*mSigningData);
+}
+
+
+//
+// The discretionary additions insert a Scatter vector describing the file's mapping table.
+//
+void DYLDCacheRep::Writer::addDiscretionary(CodeDirectory::Builder &builder)
+{
+       unsigned count = rep->mCache.mappingCount();
+       builder.scatter(count);
+       for (unsigned n = 0; n < count; n++) {
+               const DYLDCache::Mapping dmap = rep->mCache.mapping(n);
+               CodeDirectory::Scatter *scatter = builder.scatter() + n;
+               scatter->targetOffset = dmap.address();
+               scatter->base = dmap.offset() / segmentedPageSize;
+               assert(dmap.offset() % segmentedPageSize == 0);
+               scatter->count = dmap.size() / segmentedPageSize;
+               assert(dmap.size() % segmentedPageSize == 0);
+       }
+}
+
+
+} // end namespace CodeSigning
+} // end namespace Security
diff --git a/lib/slcrep.h b/lib/slcrep.h
new file mode 100644 (file)
index 0000000..4e044ae
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2009 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@
+ */
+
+//
+// slcrep - DiskRep representing the Mac OS Shared Library Cache
+//
+#ifndef _H_SLCREP
+#define _H_SLCREP
+
+#include "singlediskrep.h"
+#include "sigblob.h"
+#include <security_utilities/unix++.h>
+#include <security_utilities/macho++.h>
+#include <security_utilities/dyldcache.h>
+
+namespace Security {
+namespace CodeSigning {
+
+
+//
+// DYLDCacheRep implements the on-disk format for the Mac OS X
+// Shared Library Cache, which coalesces a set of system libraries
+// and frameworks into one big (mappable) code blob in the sky.
+//
+class DYLDCacheRep : public SingleDiskRep {
+public:
+       DYLDCacheRep(const Context *ctx = NULL);
+       DYLDCacheRep(const char *path);
+       
+       CFDataRef component(CodeDirectory::SpecialSlot slot);
+       size_t pageSize(const SigningContext &ctx);
+       std::string format();
+       
+       static bool candidate(UnixPlusPlus::FileDesc &fd);
+       
+public:
+       static CFDataRef identificationFor(MachO *macho);
+       
+public:
+       DiskRep::Writer *writer();
+       class Writer;
+       friend class Writer;
+
+private:
+       void setup();
+
+private:
+       DYLDCache mCache;
+       const EmbeddedSignatureBlob *mSigningData;      // pointer to signature SuperBlob (in mapped memory)
+};
+
+
+//
+// The write side of a FileDiskRep
+//
+class DYLDCacheRep::Writer : public SingleDiskRep::Writer, private EmbeddedSignatureBlob::Maker {
+       friend class FileDiskRep;
+public:
+       Writer(DYLDCacheRep *r) : SingleDiskRep::Writer(r, writerNoGlobal), rep(r), mSigningData(NULL) { }
+       void component(CodeDirectory::SpecialSlot slot, CFDataRef data);
+       void flush();
+       void addDiscretionary(CodeDirectory::Builder &builder);
+       
+private:
+       DYLDCacheRep *rep;
+       EmbeddedSignatureBlob *mSigningData;
+};
+
+
+} // end namespace CodeSigning
+} // end namespace Security
+
+#endif // !_H_SLCREP
index 8178e13957ae6c9c278066875f1573ab3b8ab338..e3e9bd5d913f3ef5dca158c14b6b2367ec16bd53 100644 (file)
@@ -7,6 +7,17 @@
        objects = {
 
 /* Begin PBXAggregateTarget section */
+               C26AC7090DAEB3A7005BFB40 /* DTrace */ = {
+                       isa = PBXAggregateTarget;
+                       buildConfigurationList = C26AC70D0DAEB3C6005BFB40 /* Build configuration list for PBXAggregateTarget "DTrace" */;
+                       buildPhases = (
+                               C26AC7080DAEB3A7005BFB40 /* ShellScript */,
+                       );
+                       dependencies = (
+                       );
+                       name = DTrace;
+                       productName = DTrace;
+               };
                C2D383B80A23A8C4005C63A2 /* Requirements Language */ = {
                        isa = PBXAggregateTarget;
                        buildConfigurationList = C2D383C00A23A8E3005C63A2 /* Build configuration list for PBXAggregateTarget "Requirements Language" */;
 
 /* Begin PBXBuildFile section */
                C2093AA80BB0948000EB8599 /* reqreader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2093AA60BB0948000EB8599 /* reqreader.cpp */; };
-               C2093AA90BB0948000EB8599 /* reqreader.h in Headers */ = {isa = PBXBuildFile; fileRef = C2093AA70BB0948000EB8599 /* reqreader.h */; settings = {ATTRIBUTES = (Public, ); }; };
                C2093AC80BB0967D00EB8599 /* reqreader.h in Headers */ = {isa = PBXBuildFile; fileRef = C2093AA70BB0948000EB8599 /* reqreader.h */; settings = {ATTRIBUTES = (Public, ); }; };
                C21CFC5F0A250D1C006CD5B1 /* reqdumper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C21CFC5D0A250D1C006CD5B1 /* reqdumper.cpp */; };
                C21CFC620A250D1C006CD5B1 /* reqdumper.h in Headers */ = {isa = PBXBuildFile; fileRef = C21CFC5E0A250D1C006CD5B1 /* reqdumper.h */; settings = {ATTRIBUTES = (Public, ); }; };
                C21EA3DD0AD2F81300E6E31C /* SecCodeSigner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C21EA3DB0AD2F81300E6E31C /* SecCodeSigner.cpp */; };
-               C21EA3DE0AD2F81300E6E31C /* SecCodeSigner.h in Headers */ = {isa = PBXBuildFile; fileRef = C21EA3DC0AD2F81300E6E31C /* SecCodeSigner.h */; settings = {ATTRIBUTES = (Private, ); }; };
                C21EA3E00AD2F81300E6E31C /* SecCodeSigner.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C21EA3DC0AD2F81300E6E31C /* SecCodeSigner.h */; settings = {ATTRIBUTES = (Private, ); }; };
                C21EA3E30AD2FA0900E6E31C /* CodeSigner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C21EA3E10AD2FA0900E6E31C /* CodeSigner.cpp */; };
                C224635F0B8620F800626F1B /* RequirementParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383F00A23A9D3005C63A2 /* RequirementParser.cpp */; };
                C22463600B8620F800626F1B /* RequirementLexer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383EE0A23A9D3005C63A2 /* RequirementLexer.cpp */; };
                C22463610B86210100626F1B /* antlrplugin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2CC31130B85254F005FA59D /* antlrplugin.cpp */; };
                C236E3D70AD59446000F5140 /* signer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C236E3D50AD59446000F5140 /* signer.cpp */; };
-               C236E3D80AD59446000F5140 /* signer.h in Headers */ = {isa = PBXBuildFile; fileRef = C236E3D60AD59446000F5140 /* signer.h */; };
                C236E3DB0AD595C2000F5140 /* signerutils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C236E3D90AD595C2000F5140 /* signerutils.cpp */; };
-               C236E3DC0AD595C2000F5140 /* signerutils.h in Headers */ = {isa = PBXBuildFile; fileRef = C236E3DA0AD595C2000F5140 /* signerutils.h */; };
                C250F6C30B5EF1910076098F /* SecIntegrity.h in Headers */ = {isa = PBXBuildFile; fileRef = C250F6C20B5EF1910076098F /* SecIntegrity.h */; };
-               C25942440BA7095000877E56 /* foreigndiskrep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C25942420BA7095000877E56 /* foreigndiskrep.cpp */; };
-               C25942450BA7095000877E56 /* foreigndiskrep.h in Headers */ = {isa = PBXBuildFile; fileRef = C25942430BA7095000877E56 /* foreigndiskrep.h */; };
                C259DFD60AD6D9BA00C9ACC6 /* sigblob.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C259DFD40AD6D9BA00C9ACC6 /* sigblob.cpp */; };
-               C259DFD70AD6D9BA00C9ACC6 /* sigblob.h in Headers */ = {isa = PBXBuildFile; fileRef = C259DFD50AD6D9BA00C9ACC6 /* sigblob.h */; };
                C26B45C10B8A9C0A003C0ACA /* ucspc in Frameworks */ = {isa = PBXBuildFile; fileRef = C26B45C00B8A9C00003C0ACA /* ucspc */; };
+               C26FF62D0E5B375A00F640A0 /* SecIntegrityLib.h in Headers */ = {isa = PBXBuildFile; fileRef = C2CC31040B8523AD005FA59D /* SecIntegrityLib.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               C26FF62E0E5B375A00F640A0 /* SecCodeHostLib.h in Headers */ = {isa = PBXBuildFile; fileRef = C2BC1F340B580DA7003EC9DC /* SecCodeHostLib.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               C26FF62F0E5B376B00F640A0 /* CodeSigning.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383180A237F47005C63A2 /* CodeSigning.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               C26FF6300E5B376B00F640A0 /* CSCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D3831C0A237F47005C63A2 /* CSCommon.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               C26FF6310E5B376B00F640A0 /* CSCommonPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D50CDF0E155A4F0059A195 /* CSCommonPriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               C26FF6320E5B376B00F640A0 /* SecCode.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D3831E0A237F47005C63A2 /* SecCode.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               C26FF6330E5B376B00F640A0 /* SecCodePriv.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E8AF240DE25CA7000F6D3B /* SecCodePriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               C26FF6340E5B376B00F640A0 /* SecStaticCode.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383220A237F47005C63A2 /* SecStaticCode.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               C26FF6350E5B376B00F640A0 /* SecStaticCodePriv.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E8AF260DE25CA7000F6D3B /* SecStaticCodePriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               C26FF6360E5B376B00F640A0 /* SecRequirement.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383260A237F47005C63A2 /* SecRequirement.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               C26FF6370E5B376B00F640A0 /* SecRequirementPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E8AF250DE25CA7000F6D3B /* SecRequirementPriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               C26FF6380E5B376B00F640A0 /* SecCodeSigner.h in Headers */ = {isa = PBXBuildFile; fileRef = C21EA3DC0AD2F81300E6E31C /* SecCodeSigner.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               C26FF6390E5B376B00F640A0 /* SecCodeHost.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383190A237F47005C63A2 /* SecCodeHost.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               C26FF63A0E5B376B00F640A0 /* SecIntegrity.h in Headers */ = {isa = PBXBuildFile; fileRef = C250F6C20B5EF1910076098F /* SecIntegrity.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               C28342E60E366E6800E54360 /* csdatabase.h in Headers */ = {isa = PBXBuildFile; fileRef = C28342E50E366E6800E54360 /* csdatabase.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               C28342E70E366E6800E54360 /* csdatabase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C28342E40E366E6800E54360 /* csdatabase.cpp */; };
+               C28342ED0E36719D00E54360 /* detachedrep.h in Headers */ = {isa = PBXBuildFile; fileRef = C28342EC0E36719D00E54360 /* detachedrep.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               C28342EE0E36719D00E54360 /* detachedrep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C28342EB0E36719D00E54360 /* detachedrep.cpp */; };
                C297DF250B014BB300E94EE0 /* SecCodeSigner.h in Headers */ = {isa = PBXBuildFile; fileRef = C21EA3DC0AD2F81300E6E31C /* SecCodeSigner.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               C2A36B4B0D906C08003412BA /* resources.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E911E10ADEBE3200275CB2 /* resources.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               C2A436150F2133B2007A41A6 /* slcrep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2A436130F2133B2007A41A6 /* slcrep.cpp */; };
+               C2A436160F2133B2007A41A6 /* slcrep.h in Headers */ = {isa = PBXBuildFile; fileRef = C2A436140F2133B2007A41A6 /* slcrep.h */; };
                C2A487530B7914F400849490 /* SecCodeHostLib.h in Headers */ = {isa = PBXBuildFile; fileRef = C2BC1F340B580DA7003EC9DC /* SecCodeHostLib.h */; settings = {ATTRIBUTES = (Private, ); }; };
                C2A487540B79150C00849490 /* SecIntegrity.h in Headers */ = {isa = PBXBuildFile; fileRef = C250F6C20B5EF1910076098F /* SecIntegrity.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               C2A487550B79152A00849490 /* SecIntegrity.h in Headers */ = {isa = PBXBuildFile; fileRef = C250F6C20B5EF1910076098F /* SecIntegrity.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               C2A487560B79152A00849490 /* SecCodeHostLib.h in Headers */ = {isa = PBXBuildFile; fileRef = C2BC1F340B580DA7003EC9DC /* SecCodeHostLib.h */; settings = {ATTRIBUTES = (Private, ); }; };
                C2A752B70B80EAFB004CF655 /* SecIntegrity.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C250F6C20B5EF1910076098F /* SecIntegrity.h */; };
                C2A752B80B80EAFB004CF655 /* SecCodeHostLib.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2BC1F340B580DA7003EC9DC /* SecCodeHostLib.h */; };
                C2A976AA0B8A2E36008B4EA0 /* csutilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2A976A80B8A2E36008B4EA0 /* csutilities.cpp */; };
-               C2A976AB0B8A2E36008B4EA0 /* csutilities.h in Headers */ = {isa = PBXBuildFile; fileRef = C2A976A90B8A2E36008B4EA0 /* csutilities.h */; };
                C2BC1F350B580DA7003EC9DC /* SecCodeHostLib.h in Headers */ = {isa = PBXBuildFile; fileRef = C2BC1F340B580DA7003EC9DC /* SecCodeHostLib.h */; };
                C2BD519C0A9392FD000FE43D /* machorep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2BD519A0A9392FD000FE43D /* machorep.cpp */; };
                C2BD519F0A9392FD000FE43D /* machorep.h in Headers */ = {isa = PBXBuildFile; fileRef = C2BD519B0A9392FD000FE43D /* machorep.h */; settings = {ATTRIBUTES = (Public, ); }; };
                C2BD61BD0AC9C77B0057FD3D /* csgeneric.h in Headers */ = {isa = PBXBuildFile; fileRef = C2BD60F90AC863FC0057FD3D /* csgeneric.h */; settings = {ATTRIBUTES = (Public, ); }; };
                C2C1DF140A2E3D7200D1B02B /* requirement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383350A237F47005C63A2 /* requirement.cpp */; };
                C2C1DFBB0A2F80EB00D1B02B /* reqinterp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2C1DFB90A2F80EB00D1B02B /* reqinterp.cpp */; };
-               C2C1DFBC0A2F80EB00D1B02B /* reqinterp.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C1DFBA0A2F80EB00D1B02B /* reqinterp.h */; settings = {ATTRIBUTES = (Public, ); }; };
                C2C1DFBE0A2F80EB00D1B02B /* reqinterp.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C1DFBA0A2F80EB00D1B02B /* reqinterp.h */; settings = {ATTRIBUTES = (Public, ); }; };
                C2C1DFC30A2F820500D1B02B /* reqmaker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2C1DFC10A2F820500D1B02B /* reqmaker.cpp */; };
-               C2C1DFC40A2F820500D1B02B /* reqmaker.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C1DFC20A2F820500D1B02B /* reqmaker.h */; settings = {ATTRIBUTES = (Public, ); }; };
                C2C1DFC60A2F820500D1B02B /* reqmaker.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C1DFC20A2F820500D1B02B /* reqmaker.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               C2C315D70D9319E800E7AA0C /* csutilities.h in Headers */ = {isa = PBXBuildFile; fileRef = C2A976A90B8A2E36008B4EA0 /* csutilities.h */; settings = {ATTRIBUTES = (Public, ); }; };
                C2C3BC5F0BA1D6FE00E869D1 /* cfmdiskrep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2C3BC5D0BA1D6FE00E869D1 /* cfmdiskrep.cpp */; };
-               C2C3BC600BA1D6FE00E869D1 /* cfmdiskrep.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C3BC5E0BA1D6FE00E869D1 /* cfmdiskrep.h */; };
                C2C3BCD30BA1E47E00E869D1 /* singlediskrep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2C3BCD10BA1E47E00E869D1 /* singlediskrep.cpp */; };
-               C2C3BCD40BA1E47E00E869D1 /* singlediskrep.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C3BCD20BA1E47E00E869D1 /* singlediskrep.h */; };
                C2C931B40AB8BA1200F83950 /* SecCodeHost.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2C931B30AB8BA1200F83950 /* SecCodeHost.cpp */; };
-               C2C931B50AB8BA8200F83950 /* SecCodeHost.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383190A237F47005C63A2 /* SecCodeHost.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               C2C931B60AB8BAC200F83950 /* SecCodeHost.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2D383190A237F47005C63A2 /* SecCodeHost.h */; };
                C2CC31050B8523AD005FA59D /* SecIntegrityLib.h in Headers */ = {isa = PBXBuildFile; fileRef = C2CC31040B8523AD005FA59D /* SecIntegrityLib.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               C2CC31060B8523F8005FA59D /* SecIntegrityLib.h in Headers */ = {isa = PBXBuildFile; fileRef = C2CC31040B8523AD005FA59D /* SecIntegrityLib.h */; settings = {ATTRIBUTES = (Private, ); }; };
                C2CC310F0B852424005FA59D /* SecIntegrityLib.c in Sources */ = {isa = PBXBuildFile; fileRef = C2CC310E0B852424005FA59D /* SecIntegrityLib.c */; };
                C2CC31100B852447005FA59D /* SecIntegrityLib.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2CC31040B8523AD005FA59D /* SecIntegrityLib.h */; };
-               C2CCF0310A3F523D0085795A /* macho++.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2CCF02F0A3F523D0085795A /* macho++.cpp */; };
-               C2CCF0340A3F523D0085795A /* macho++.h in Headers */ = {isa = PBXBuildFile; fileRef = C2CCF0300A3F523D0085795A /* macho++.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               C2CFB9C70DF8789A003F57E4 /* SecCodeHost.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2D383190A237F47005C63A2 /* SecCodeHost.h */; };
+               C2D213870D9844F700E76E7D /* resources.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E911E10ADEBE3200275CB2 /* resources.h */; settings = {ATTRIBUTES = (Public, ); }; };
                C2D3833C0A237F47005C63A2 /* bundlediskrep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383120A237F47005C63A2 /* bundlediskrep.cpp */; };
                C2D3833E0A237F47005C63A2 /* cdbuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383140A237F47005C63A2 /* cdbuilder.cpp */; };
                C2D383400A237F47005C63A2 /* codedirectory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383160A237F47005C63A2 /* codedirectory.cpp */; };
                C2D383440A237F47005C63A2 /* cs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D3831A0A237F47005C63A2 /* cs.cpp */; };
-               C2D383460A237F47005C63A2 /* CSCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D3831C0A237F47005C63A2 /* CSCommon.h */; settings = {ATTRIBUTES = (Private, ); }; };
                C2D383470A237F47005C63A2 /* SecCode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D3831D0A237F47005C63A2 /* SecCode.cpp */; };
-               C2D383480A237F47005C63A2 /* SecCode.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D3831E0A237F47005C63A2 /* SecCode.h */; settings = {ATTRIBUTES = (Private, ); }; };
                C2D383490A237F47005C63A2 /* cskernel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D3831F0A237F47005C63A2 /* cskernel.cpp */; };
                C2D3834B0A237F47005C63A2 /* SecStaticCode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383210A237F47005C63A2 /* SecStaticCode.cpp */; };
-               C2D3834C0A237F47005C63A2 /* SecStaticCode.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383220A237F47005C63A2 /* SecStaticCode.h */; settings = {ATTRIBUTES = (Private, ); }; };
                C2D3834D0A237F47005C63A2 /* csprocess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383230A237F47005C63A2 /* csprocess.cpp */; };
                C2D3834F0A237F47005C63A2 /* SecRequirement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383250A237F47005C63A2 /* SecRequirement.cpp */; };
-               C2D383500A237F47005C63A2 /* SecRequirement.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383260A237F47005C63A2 /* SecRequirement.h */; settings = {ATTRIBUTES = (Private, ); }; };
                C2D383510A237F47005C63A2 /* diskrep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383270A237F47005C63A2 /* diskrep.cpp */; };
                C2D383550A237F47005C63A2 /* filediskrep.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D3832B0A237F47005C63A2 /* filediskrep.cpp */; };
                C2D383570A237F47005C63A2 /* Code.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D3832D0A237F47005C63A2 /* Code.cpp */; };
                C2D3835B0A237F47005C63A2 /* StaticCode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383310A237F47005C63A2 /* StaticCode.cpp */; };
                C2D3835D0A237F47005C63A2 /* reqparser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383330A237F47005C63A2 /* reqparser.cpp */; };
                C2D383610A237F47005C63A2 /* Requirements.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383370A237F47005C63A2 /* Requirements.cpp */; };
-               C2D383630A237F47005C63A2 /* security_codesigning.exp in Sources */ = {isa = PBXBuildFile; fileRef = C2D383390A237F47005C63A2 /* security_codesigning.exp */; };
                C2D383670A237F47005C63A2 /* bundlediskrep.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383130A237F47005C63A2 /* bundlediskrep.h */; settings = {ATTRIBUTES = (Public, ); }; };
                C2D383690A237F47005C63A2 /* cdbuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383150A237F47005C63A2 /* cdbuilder.h */; settings = {ATTRIBUTES = (Public, ); }; };
                C2D3836B0A237F47005C63A2 /* codedirectory.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383170A237F47005C63A2 /* codedirectory.h */; settings = {ATTRIBUTES = (Public, ); }; };
-               C2D3836C0A237F47005C63A2 /* CodeSigning.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383180A237F47005C63A2 /* CodeSigning.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               C2D3836D0A237F47005C63A2 /* SecCodeHost.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383190A237F47005C63A2 /* SecCodeHost.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               C2D3836C0A237F47005C63A2 /* CodeSigning.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383180A237F47005C63A2 /* CodeSigning.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               C2D3836D0A237F47005C63A2 /* SecCodeHost.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383190A237F47005C63A2 /* SecCodeHost.h */; settings = {ATTRIBUTES = (Public, ); }; };
                C2D3836F0A237F47005C63A2 /* cs.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D3831B0A237F47005C63A2 /* cs.h */; settings = {ATTRIBUTES = (Public, ); }; };
-               C2D383700A237F47005C63A2 /* CSCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D3831C0A237F47005C63A2 /* CSCommon.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               C2D383720A237F47005C63A2 /* SecCode.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D3831E0A237F47005C63A2 /* SecCode.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               C2D383700A237F47005C63A2 /* CSCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D3831C0A237F47005C63A2 /* CSCommon.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               C2D383720A237F47005C63A2 /* SecCode.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D3831E0A237F47005C63A2 /* SecCode.h */; settings = {ATTRIBUTES = (Public, ); }; };
                C2D383740A237F47005C63A2 /* cskernel.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383200A237F47005C63A2 /* cskernel.h */; settings = {ATTRIBUTES = (Public, ); }; };
-               C2D383760A237F47005C63A2 /* SecStaticCode.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383220A237F47005C63A2 /* SecStaticCode.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               C2D383760A237F47005C63A2 /* SecStaticCode.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383220A237F47005C63A2 /* SecStaticCode.h */; settings = {ATTRIBUTES = (Public, ); }; };
                C2D383780A237F47005C63A2 /* csprocess.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383240A237F47005C63A2 /* csprocess.h */; settings = {ATTRIBUTES = (Public, ); }; };
-               C2D3837A0A237F47005C63A2 /* SecRequirement.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383260A237F47005C63A2 /* SecRequirement.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               C2D3837A0A237F47005C63A2 /* SecRequirement.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383260A237F47005C63A2 /* SecRequirement.h */; settings = {ATTRIBUTES = (Public, ); }; };
                C2D3837C0A237F47005C63A2 /* diskrep.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383280A237F47005C63A2 /* diskrep.h */; settings = {ATTRIBUTES = (Public, ); }; };
                C2D383800A237F47005C63A2 /* filediskrep.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D3832C0A237F47005C63A2 /* filediskrep.h */; settings = {ATTRIBUTES = (Public, ); }; };
                C2D383820A237F47005C63A2 /* Code.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D3832E0A237F47005C63A2 /* Code.h */; settings = {ATTRIBUTES = (Public, ); }; };
                C2D383920A23803A005C63A2 /* SecCode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2D3831E0A237F47005C63A2 /* SecCode.h */; };
                C2D383930A23803A005C63A2 /* SecStaticCode.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2D383220A237F47005C63A2 /* SecStaticCode.h */; };
                C2D383940A23803A005C63A2 /* SecRequirement.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2D383260A237F47005C63A2 /* SecRequirement.h */; };
-               C2D3839A0A238132005C63A2 /* CodeSigning.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383180A237F47005C63A2 /* CodeSigning.h */; settings = {ATTRIBUTES = (Private, ); }; };
                C2D3839B0A238150005C63A2 /* CodeSigning.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2D383180A237F47005C63A2 /* CodeSigning.h */; };
-               C2D8A07F0AE7F6E300F68F79 /* cfmunge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2D8A07D0AE7F6E300F68F79 /* cfmunge.cpp */; };
-               C2D8A0800AE7F6E300F68F79 /* cfmunge.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D8A07E0AE7F6E300F68F79 /* cfmunge.h */; };
-               C2D8A0980AE7F74500F68F79 /* cfmunge.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D8A07E0AE7F6E300F68F79 /* cfmunge.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               C2D50CE10E155ABC0059A195 /* CSCommonPriv.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2D50CDF0E155A4F0059A195 /* CSCommonPriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               C2D50CE20E155AE60059A195 /* CSCommonPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D50CDF0E155A4F0059A195 /* CSCommonPriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
                C2E2873D0B5D8D80009336A0 /* SecCodeHostLib.c in Sources */ = {isa = PBXBuildFile; fileRef = C2E2873C0B5D8D80009336A0 /* SecCodeHostLib.c */; };
+               C2E8AF2A0DE25D11000F6D3B /* SecCodePriv.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E8AF240DE25CA7000F6D3B /* SecCodePriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               C2E8AF2B0DE25D11000F6D3B /* SecStaticCodePriv.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E8AF260DE25CA7000F6D3B /* SecStaticCodePriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               C2E8AF2C0DE25D11000F6D3B /* SecRequirementPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E8AF250DE25CA7000F6D3B /* SecRequirementPriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               C2E8AF2D0DE25D74000F6D3B /* SecCodePriv.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2E8AF240DE25CA7000F6D3B /* SecCodePriv.h */; };
+               C2E8AF2E0DE25D74000F6D3B /* SecStaticCodePriv.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2E8AF260DE25CA7000F6D3B /* SecStaticCodePriv.h */; };
+               C2E8AF2F0DE25D74000F6D3B /* SecRequirementPriv.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2E8AF250DE25CA7000F6D3B /* SecRequirementPriv.h */; };
                C2E911E20ADEBE3200275CB2 /* resources.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2E911E00ADEBE3200275CB2 /* resources.cpp */; };
-               C2E911E30ADEBE3200275CB2 /* resources.h in Headers */ = {isa = PBXBuildFile; fileRef = C2E911E10ADEBE3200275CB2 /* resources.h */; settings = {ATTRIBUTES = (Public, ); }; };
                C2EF10100A49BD89005A44BB /* renum.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2EF100E0A49BD89005A44BB /* renum.cpp */; };
-               C2EF10110A49BD89005A44BB /* renum.h in Headers */ = {isa = PBXBuildFile; fileRef = C2EF100F0A49BD89005A44BB /* renum.h */; settings = {ATTRIBUTES = (Public, ); }; };
                C2EF10130A49BD89005A44BB /* renum.h in Headers */ = {isa = PBXBuildFile; fileRef = C2EF100F0A49BD89005A44BB /* renum.h */; settings = {ATTRIBUTES = (Public, ); }; };
                C2F6566E0BCBFB250078779E /* cserror.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2F6566C0BCBFB250078779E /* cserror.cpp */; };
-               C2F6566F0BCBFB250078779E /* cserror.h in Headers */ = {isa = PBXBuildFile; fileRef = C2F6566D0BCBFB250078779E /* cserror.h */; };
                C2F656930BCBFFF40078779E /* cserror.h in Headers */ = {isa = PBXBuildFile; fileRef = C2F6566D0BCBFB250078779E /* cserror.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               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 */; };
+               FEB30CA410DAC97400557BA2 /* SecTask.h in Headers */ = {isa = PBXBuildFile; fileRef = FEB30C9410DAC8A500557BA2 /* SecTask.h */; settings = {ATTRIBUTES = (Public, ); }; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
                        remoteGlobalIDString = C2BC1F250B580D3A003EC9DC;
                        remoteInfo = libintegrity;
                };
+               C26AC70E0DAEB400005BFB40 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 4CA1FEAB052A3C3800F22E42 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = C26AC7090DAEB3A7005BFB40;
+                       remoteInfo = DTrace;
+               };
                C2E287400B5D8F97009336A0 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4CA1FEAB052A3C3800F22E42 /* Project object */;
                        dstPath = SecurityPieces/Headers/Security;
                        dstSubfolderSpec = 16;
                        files = (
+                               FEB30CA310DAC91800557BA2 /* SecTask.h in CopyFiles */,
+                               C2D3839B0A238150005C63A2 /* CodeSigning.h in CopyFiles */,
+                               C2D383910A23803A005C63A2 /* CSCommon.h in CopyFiles */,
+                               C2D383920A23803A005C63A2 /* SecCode.h in CopyFiles */,
+                               C2D383930A23803A005C63A2 /* SecStaticCode.h in CopyFiles */,
+                               C2D383940A23803A005C63A2 /* SecRequirement.h in CopyFiles */,
+                               C2CFB9C70DF8789A003F57E4 /* SecCodeHost.h in CopyFiles */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        dstPath = SecurityPieces/PrivateHeaders/Security;
                        dstSubfolderSpec = 16;
                        files = (
+                               C2D50CE10E155ABC0059A195 /* CSCommonPriv.h in CopyFiles */,
+                               C2E8AF2D0DE25D74000F6D3B /* SecCodePriv.h in CopyFiles */,
+                               C2E8AF2E0DE25D74000F6D3B /* SecStaticCodePriv.h in CopyFiles */,
+                               C2E8AF2F0DE25D74000F6D3B /* SecRequirementPriv.h in CopyFiles */,
                                C2CC31100B852447005FA59D /* SecIntegrityLib.h in CopyFiles */,
                                C21EA3E00AD2F81300E6E31C /* SecCodeSigner.h in CopyFiles */,
-                               C2D3839B0A238150005C63A2 /* CodeSigning.h in CopyFiles */,
-                               C2D383910A23803A005C63A2 /* CSCommon.h in CopyFiles */,
-                               C2D383920A23803A005C63A2 /* SecCode.h in CopyFiles */,
-                               C2D383930A23803A005C63A2 /* SecStaticCode.h in CopyFiles */,
-                               C2D383940A23803A005C63A2 /* SecRequirement.h in CopyFiles */,
-                               C2C931B60AB8BAC200F83950 /* SecCodeHost.h in CopyFiles */,
                                C2A752B70B80EAFB004CF655 /* SecIntegrity.h in CopyFiles */,
                                C2A752B80B80EAFB004CF655 /* SecCodeHostLib.h in CopyFiles */,
                        );
 
 /* Begin PBXFileReference section */
                4C56351E0540A55300DCF0C8 /* security_codesigning.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = security_codesigning.framework; sourceTree = BUILT_PRODUCTS_DIR; };
-               4CA1FEBE052A3C8100F22E42 /* security_codesigning */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; path = security_codesigning; sourceTree = BUILT_PRODUCTS_DIR; };
+               4CA1FEBE052A3C8100F22E42 /* security_codesigning */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = security_codesigning; sourceTree = BUILT_PRODUCTS_DIR; };
                C2093AA60BB0948000EB8599 /* reqreader.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = reqreader.cpp; sourceTree = "<group>"; };
                C2093AA70BB0948000EB8599 /* reqreader.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = reqreader.h; sourceTree = "<group>"; };
                C21CFC5D0A250D1C006CD5B1 /* reqdumper.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = reqdumper.cpp; sourceTree = "<group>"; };
                C236E3DA0AD595C2000F5140 /* signerutils.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = signerutils.h; sourceTree = "<group>"; };
                C250F6C20B5EF1910076098F /* SecIntegrity.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SecIntegrity.h; sourceTree = "<group>"; };
                C250F6C60B5EF5B50076098F /* SecIntegrity.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = SecIntegrity.cpp; sourceTree = "<group>"; };
-               C25942420BA7095000877E56 /* foreigndiskrep.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = foreigndiskrep.cpp; sourceTree = "<group>"; };
-               C25942430BA7095000877E56 /* foreigndiskrep.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = foreigndiskrep.h; sourceTree = "<group>"; };
                C259DFD40AD6D9BA00C9ACC6 /* sigblob.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = sigblob.cpp; sourceTree = "<group>"; };
                C259DFD50AD6D9BA00C9ACC6 /* sigblob.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = sigblob.h; sourceTree = "<group>"; };
+               C26AC6FD0DAEB2C4005BFB40 /* security_codesigning.d */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.dtrace; path = security_codesigning.d; sourceTree = "<group>"; };
                C26B45C00B8A9C00003C0ACA /* ucspc */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = ucspc; sourceTree = "<group>"; };
+               C28342E40E366E6800E54360 /* csdatabase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = csdatabase.cpp; sourceTree = "<group>"; };
+               C28342E50E366E6800E54360 /* csdatabase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = csdatabase.h; sourceTree = "<group>"; };
+               C28342EB0E36719D00E54360 /* detachedrep.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = detachedrep.cpp; sourceTree = "<group>"; };
+               C28342EC0E36719D00E54360 /* detachedrep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = detachedrep.h; sourceTree = "<group>"; };
+               C2A436130F2133B2007A41A6 /* slcrep.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = slcrep.cpp; sourceTree = "<group>"; };
+               C2A436140F2133B2007A41A6 /* slcrep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = slcrep.h; sourceTree = "<group>"; };
                C2A976A80B8A2E36008B4EA0 /* csutilities.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = csutilities.cpp; sourceTree = "<group>"; };
                C2A976A90B8A2E36008B4EA0 /* csutilities.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = csutilities.h; sourceTree = "<group>"; };
+               C2B9F1D20D51646600CAB713 /* RequirementKeywords.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RequirementKeywords.h; sourceTree = "<group>"; };
                C2BC1F260B580D3A003EC9DC /* libintegrity.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libintegrity.a; sourceTree = BUILT_PRODUCTS_DIR; };
                C2BC1F2F0B580D4B003EC9DC /* libcodehost.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libcodehost.a; sourceTree = BUILT_PRODUCTS_DIR; };
                C2BC1F340B580DA7003EC9DC /* SecCodeHostLib.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SecCodeHostLib.h; sourceTree = "<group>"; };
                C2C3BC5E0BA1D6FE00E869D1 /* cfmdiskrep.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = cfmdiskrep.h; sourceTree = "<group>"; };
                C2C3BCD10BA1E47E00E869D1 /* singlediskrep.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = singlediskrep.cpp; sourceTree = "<group>"; };
                C2C3BCD20BA1E47E00E869D1 /* singlediskrep.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = singlediskrep.h; sourceTree = "<group>"; };
+               C2C4F4EE0E0980C700137848 /* codesigning_dtrace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = codesigning_dtrace.h; sourceTree = "<group>"; };
                C2C931B30AB8BA1200F83950 /* SecCodeHost.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = SecCodeHost.cpp; sourceTree = "<group>"; };
                C2CC30A00B8519CC005FA59D /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = CoreFoundation.framework; sourceTree = "<group>"; };
                C2CC31040B8523AD005FA59D /* SecIntegrityLib.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SecIntegrityLib.h; sourceTree = "<group>"; };
                C2CC310E0B852424005FA59D /* SecIntegrityLib.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = SecIntegrityLib.c; sourceTree = "<group>"; };
                C2CC31130B85254F005FA59D /* antlrplugin.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = antlrplugin.cpp; path = lib/antlrplugin.cpp; sourceTree = "<group>"; };
                C2CC31140B85254F005FA59D /* antlrplugin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = antlrplugin.h; path = lib/antlrplugin.h; sourceTree = "<group>"; };
-               C2CCF02F0A3F523D0085795A /* macho++.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = "macho++.cpp"; sourceTree = "<group>"; };
-               C2CCF0300A3F523D0085795A /* macho++.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "macho++.h"; sourceTree = "<group>"; };
                C2D383120A237F47005C63A2 /* bundlediskrep.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = bundlediskrep.cpp; sourceTree = "<group>"; };
                C2D383130A237F47005C63A2 /* bundlediskrep.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = bundlediskrep.h; sourceTree = "<group>"; };
                C2D383140A237F47005C63A2 /* cdbuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = cdbuilder.cpp; sourceTree = "<group>"; };
                C2D383F10A23A9D3005C63A2 /* RequirementParser.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = RequirementParser.hpp; sourceTree = "<group>"; };
                C2D383F20A23A9D3005C63A2 /* RequirementParserTokenTypes.hpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = RequirementParserTokenTypes.hpp; sourceTree = "<group>"; };
                C2D383F30A23A9D3005C63A2 /* RequirementParserTokenTypes.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = RequirementParserTokenTypes.txt; sourceTree = "<group>"; };
-               C2D8A07D0AE7F6E300F68F79 /* cfmunge.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = cfmunge.cpp; sourceTree = "<group>"; };
-               C2D8A07E0AE7F6E300F68F79 /* cfmunge.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = cfmunge.h; sourceTree = "<group>"; };
+               C2D50CDF0E155A4F0059A195 /* CSCommonPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSCommonPriv.h; sourceTree = "<group>"; };
                C2E2873C0B5D8D80009336A0 /* SecCodeHostLib.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = SecCodeHostLib.c; sourceTree = "<group>"; };
+               C2E8AF240DE25CA7000F6D3B /* SecCodePriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecCodePriv.h; sourceTree = "<group>"; };
+               C2E8AF250DE25CA7000F6D3B /* SecRequirementPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecRequirementPriv.h; sourceTree = "<group>"; };
+               C2E8AF260DE25CA7000F6D3B /* SecStaticCodePriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecStaticCodePriv.h; sourceTree = "<group>"; };
                C2E911E00ADEBE3200275CB2 /* resources.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = resources.cpp; sourceTree = "<group>"; };
                C2E911E10ADEBE3200275CB2 /* resources.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = resources.h; sourceTree = "<group>"; };
                C2EF100E0A49BD89005A44BB /* renum.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = renum.cpp; sourceTree = "<group>"; };
                C2EF100F0A49BD89005A44BB /* renum.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = renum.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>"; };
+               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 */
 
-/* Begin PBXFrameworkTarget section */
-               4C56351D0540A55300DCF0C8 /* security_codesigning */ = {
-                       isa = PBXFrameworkTarget;
-                       buildConfigurationList = C263E67109A2971B000043F1 /* Build configuration list for PBXFrameworkTarget "security_codesigning" */;
-                       buildPhases = (
-                               4C5635180540A55300DCF0C8 /* Headers */,
-                               4CCB00500580097400981D43 /* CopyFiles */,
-                               4CCB00510580097600981D43 /* CopyFiles */,
-                               4CCB00520580097800981D43 /* CopyFiles */,
-                               C26C39D3068368EC00ED5782 /* CopyFiles */,
-                       );
-                       dependencies = (
-                       );
-                       name = security_codesigning;
-                       productInstallPath = "$(LOCAL_LIBRARY_DIR)/Frameworks";
-                       productName = security_codesigning;
-                       productReference = 4C56351E0540A55300DCF0C8 /* security_codesigning.framework */;
-                       productSettingsXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
-<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
-<plist version=\"1.0\">
-<dict/>
-</plist>
-";
-               };
-/* End PBXFrameworkTarget section */
-
 /* Begin PBXFrameworksBuildPhase section */
                4CA1FEBB052A3C8100F22E42 /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                                C2C1DF640A2E45F500D1B02B /* Code Classes */,
                                C2C1DF610A2E459E00D1B02B /* Disk Representations */,
                                C2BC1F370B580DAE003EC9DC /* Static Support */,
+                               C26AC6FF0DAEB2D0005BFB40 /* DTrace */,
                                C2CCF0360A3F524B0085795A /* Local Utilities */,
                                C2CC31160B852554005FA59D /* Security Plugins */,
+                               FEB30C9110DAC6C400557BA2 /* Entitlements */,
                        );
                        path = lib;
                        sourceTree = "<group>";
                        name = "Signing Operations";
                        sourceTree = "<group>";
                };
+               C26AC6FF0DAEB2D0005BFB40 /* DTrace */ = {
+                       isa = PBXGroup;
+                       children = (
+                               C26AC6FD0DAEB2C4005BFB40 /* security_codesigning.d */,
+                               C2F6071B107D575700A83618 /* codesign-watch.d */,
+                       );
+                       name = DTrace;
+                       sourceTree = "<group>";
+               };
                C2A4A43E0B7BABFD004AAC3F /* Pieces */ = {
                        isa = PBXGroup;
                        children = (
                        children = (
                                C2D383180A237F47005C63A2 /* CodeSigning.h */,
                                C2D3831C0A237F47005C63A2 /* CSCommon.h */,
+                               C2D50CDF0E155A4F0059A195 /* CSCommonPriv.h */,
                                C2D3831E0A237F47005C63A2 /* SecCode.h */,
+                               C2E8AF240DE25CA7000F6D3B /* SecCodePriv.h */,
                                C2D3831D0A237F47005C63A2 /* SecCode.cpp */,
                                C2D383220A237F47005C63A2 /* SecStaticCode.h */,
+                               C2E8AF260DE25CA7000F6D3B /* SecStaticCodePriv.h */,
                                C2D383210A237F47005C63A2 /* SecStaticCode.cpp */,
                                C2D383260A237F47005C63A2 /* SecRequirement.h */,
+                               C2E8AF250DE25CA7000F6D3B /* SecRequirementPriv.h */,
                                C2D383250A237F47005C63A2 /* SecRequirement.cpp */,
                                C21EA3DC0AD2F81300E6E31C /* SecCodeSigner.h */,
                                C21EA3DB0AD2F81300E6E31C /* SecCodeSigner.cpp */,
                                C2D3832F0A237F47005C63A2 /* kerneldiskrep.cpp */,
                                C2C3BC5E0BA1D6FE00E869D1 /* cfmdiskrep.h */,
                                C2C3BC5D0BA1D6FE00E869D1 /* cfmdiskrep.cpp */,
-                               C25942430BA7095000877E56 /* foreigndiskrep.h */,
-                               C25942420BA7095000877E56 /* foreigndiskrep.cpp */,
                                C2BD519B0A9392FD000FE43D /* machorep.h */,
                                C2BD519A0A9392FD000FE43D /* machorep.cpp */,
+                               C2A436140F2133B2007A41A6 /* slcrep.h */,
+                               C2A436130F2133B2007A41A6 /* slcrep.cpp */,
                                C2C3BCD20BA1E47E00E869D1 /* singlediskrep.h */,
                                C2C3BCD10BA1E47E00E869D1 /* singlediskrep.cpp */,
+                               C28342EC0E36719D00E54360 /* detachedrep.h */,
+                               C28342EB0E36719D00E54360 /* detachedrep.cpp */,
                        );
                        name = "Disk Representations";
                        sourceTree = "<group>";
                C2CCF0360A3F524B0085795A /* Local Utilities */ = {
                        isa = PBXGroup;
                        children = (
+                               C28342E50E366E6800E54360 /* csdatabase.h */,
+                               C28342E40E366E6800E54360 /* csdatabase.cpp */,
                                C2F6566D0BCBFB250078779E /* cserror.h */,
                                C2F6566C0BCBFB250078779E /* cserror.cpp */,
                                C2E911E10ADEBE3200275CB2 /* resources.h */,
                                C2E911E00ADEBE3200275CB2 /* resources.cpp */,
                                C259DFD50AD6D9BA00C9ACC6 /* sigblob.h */,
                                C259DFD40AD6D9BA00C9ACC6 /* sigblob.cpp */,
-                               C2CCF0300A3F523D0085795A /* macho++.h */,
-                               C2CCF02F0A3F523D0085795A /* macho++.cpp */,
-                               C2D8A07E0AE7F6E300F68F79 /* cfmunge.h */,
-                               C2D8A07D0AE7F6E300F68F79 /* cfmunge.cpp */,
                                C2EF100F0A49BD89005A44BB /* renum.h */,
                                C2EF100E0A49BD89005A44BB /* renum.cpp */,
                                C2A976A90B8A2E36008B4EA0 /* csutilities.h */,
                C2D383F90A23A9D9005C63A2 /* cstemp */ = {
                        isa = PBXGroup;
                        children = (
+                               C2C4F4EE0E0980C700137848 /* codesigning_dtrace.h */,
                                C2D383EF0A23A9D3005C63A2 /* RequirementLexer.hpp */,
                                C2D383EE0A23A9D3005C63A2 /* RequirementLexer.cpp */,
                                C2D383F10A23A9D3005C63A2 /* RequirementParser.hpp */,
                                C2D383F00A23A9D3005C63A2 /* RequirementParser.cpp */,
+                               C2B9F1D20D51646600CAB713 /* RequirementKeywords.h */,
                                C2D383F20A23A9D3005C63A2 /* RequirementParserTokenTypes.hpp */,
                                C2D383F30A23A9D3005C63A2 /* RequirementParserTokenTypes.txt */,
                                C26B45C00B8A9C00003C0ACA /* ucspc */,
                        path = cstemp;
                        sourceTree = BUILT_PRODUCTS_DIR;
                };
+               FEB30C9110DAC6C400557BA2 /* Entitlements */ = {
+                       isa = PBXGroup;
+                       children = (
+                               FEB30C9410DAC8A500557BA2 /* SecTask.h */,
+                               FEB30C9210DAC89D00557BA2 /* SecTask.c */,
+                       );
+                       name = Entitlements;
+                       sourceTree = "<group>";
+               };
 /* End PBXGroup section */
 
 /* Begin PBXHeadersBuildPhase section */
                        isa = PBXHeadersBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               C2A36B4B0D906C08003412BA /* resources.h in Headers */,
+                               FEB30C9E10DAC8FD00557BA2 /* SecTask.h in Headers */,
+                               C2E8AF2A0DE25D11000F6D3B /* SecCodePriv.h in Headers */,
+                               C2E8AF2B0DE25D11000F6D3B /* SecStaticCodePriv.h in Headers */,
+                               C2E8AF2C0DE25D11000F6D3B /* SecRequirementPriv.h in Headers */,
+                               C2D213870D9844F700E76E7D /* resources.h in Headers */,
+                               C2C315D70D9319E800E7AA0C /* csutilities.h in Headers */,
                                C2F656930BCBFFF40078779E /* cserror.h in Headers */,
                                C2A487540B79150C00849490 /* SecIntegrity.h in Headers */,
                                C2A487530B7914F400849490 /* SecCodeHostLib.h in Headers */,
                                C297DF250B014BB300E94EE0 /* SecCodeSigner.h in Headers */,
-                               C2D8A0980AE7F74500F68F79 /* cfmunge.h in Headers */,
                                C2D3836F0A237F47005C63A2 /* cs.h in Headers */,
                                C2D383820A237F47005C63A2 /* Code.h in Headers */,
                                C2D383860A237F47005C63A2 /* StaticCode.h in Headers */,
                                C2D3836C0A237F47005C63A2 /* CodeSigning.h in Headers */,
                                C2D3836D0A237F47005C63A2 /* SecCodeHost.h in Headers */,
                                C2D383700A237F47005C63A2 /* CSCommon.h in Headers */,
+                               C2D50CE20E155AE60059A195 /* CSCommonPriv.h in Headers */,
                                C2D383720A237F47005C63A2 /* SecCode.h in Headers */,
                                C2D383740A237F47005C63A2 /* cskernel.h in Headers */,
                                C2D383760A237F47005C63A2 /* SecStaticCode.h in Headers */,
                                C2093AC80BB0967D00EB8599 /* reqreader.h in Headers */,
                                C2C1DFBE0A2F80EB00D1B02B /* reqinterp.h in Headers */,
                                C2C1DFC60A2F820500D1B02B /* reqmaker.h in Headers */,
-                               C2CCF0340A3F523D0085795A /* macho++.h in Headers */,
                                C2EF10130A49BD89005A44BB /* renum.h in Headers */,
                                C2BD519F0A9392FD000FE43D /* machorep.h in Headers */,
                                C2CC31050B8523AD005FA59D /* SecIntegrityLib.h in Headers */,
+                               C28342E60E366E6800E54360 /* csdatabase.h in Headers */,
+                               C28342ED0E36719D00E54360 /* detachedrep.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        isa = PBXHeadersBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               C2CC31060B8523F8005FA59D /* SecIntegrityLib.h in Headers */,
-                               C2A487550B79152A00849490 /* SecIntegrity.h in Headers */,
-                               C2A487560B79152A00849490 /* SecCodeHostLib.h in Headers */,
-                               C2D3839A0A238132005C63A2 /* CodeSigning.h in Headers */,
-                               C2D383460A237F47005C63A2 /* CSCommon.h in Headers */,
-                               C2D383480A237F47005C63A2 /* SecCode.h in Headers */,
-                               C2D3834C0A237F47005C63A2 /* SecStaticCode.h in Headers */,
-                               C2D383500A237F47005C63A2 /* SecRequirement.h in Headers */,
-                               C2C931B50AB8BA8200F83950 /* SecCodeHost.h in Headers */,
-                               C2C1DFC40A2F820500D1B02B /* reqmaker.h in Headers */,
-                               C2093AA90BB0948000EB8599 /* reqreader.h in Headers */,
-                               C2C1DFBC0A2F80EB00D1B02B /* reqinterp.h in Headers */,
-                               C2EF10110A49BD89005A44BB /* renum.h in Headers */,
-                               C21EA3DE0AD2F81300E6E31C /* SecCodeSigner.h in Headers */,
-                               C236E3D80AD59446000F5140 /* signer.h in Headers */,
-                               C236E3DC0AD595C2000F5140 /* signerutils.h in Headers */,
-                               C259DFD70AD6D9BA00C9ACC6 /* sigblob.h in Headers */,
-                               C2E911E30ADEBE3200275CB2 /* resources.h in Headers */,
-                               C2D8A0800AE7F6E300F68F79 /* cfmunge.h in Headers */,
-                               C2A976AB0B8A2E36008B4EA0 /* csutilities.h in Headers */,
-                               C2C3BC600BA1D6FE00E869D1 /* cfmdiskrep.h in Headers */,
-                               C2C3BCD40BA1E47E00E869D1 /* singlediskrep.h in Headers */,
-                               C25942450BA7095000877E56 /* foreigndiskrep.h in Headers */,
-                               C2F6566F0BCBFB250078779E /* cserror.h in Headers */,
+                               FEB30CA410DAC97400557BA2 /* SecTask.h in Headers */,
+                               C26FF62F0E5B376B00F640A0 /* CodeSigning.h in Headers */,
+                               C26FF6300E5B376B00F640A0 /* CSCommon.h in Headers */,
+                               C26FF6310E5B376B00F640A0 /* CSCommonPriv.h in Headers */,
+                               C26FF6320E5B376B00F640A0 /* SecCode.h in Headers */,
+                               C26FF6330E5B376B00F640A0 /* SecCodePriv.h in Headers */,
+                               C26FF6340E5B376B00F640A0 /* SecStaticCode.h in Headers */,
+                               C26FF6350E5B376B00F640A0 /* SecStaticCodePriv.h in Headers */,
+                               C26FF6360E5B376B00F640A0 /* SecRequirement.h in Headers */,
+                               C26FF6370E5B376B00F640A0 /* SecRequirementPriv.h in Headers */,
+                               C26FF6380E5B376B00F640A0 /* SecCodeSigner.h in Headers */,
+                               C26FF6390E5B376B00F640A0 /* SecCodeHost.h in Headers */,
+                               C26FF63A0E5B376B00F640A0 /* SecIntegrity.h in Headers */,
+                               C26FF62D0E5B375A00F640A0 /* SecIntegrityLib.h in Headers */,
+                               C26FF62E0E5B375A00F640A0 /* SecCodeHostLib.h in Headers */,
+                               C2A436160F2133B2007A41A6 /* slcrep.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                };
 /* End PBXHeadersBuildPhase section */
 
-/* Begin PBXLibraryTarget section */
+/* Begin PBXNativeTarget section */
+               4C56351D0540A55300DCF0C8 /* security_codesigning */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = C263E67109A2971B000043F1 /* Build configuration list for PBXNativeTarget "security_codesigning" */;
+                       buildPhases = (
+                               4C5635180540A55300DCF0C8 /* Headers */,
+                               4CCB00500580097400981D43 /* CopyFiles */,
+                               4CCB00510580097600981D43 /* CopyFiles */,
+                               4CCB00520580097800981D43 /* CopyFiles */,
+                               C26C39D3068368EC00ED5782 /* CopyFiles */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                               C26AC70F0DAEB400005BFB40 /* PBXTargetDependency */,
+                       );
+                       name = security_codesigning;
+                       productInstallPath = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+                       productName = security_codesigning;
+                       productReference = 4C56351E0540A55300DCF0C8 /* security_codesigning.framework */;
+                       productType = "com.apple.product-type.framework";
+               };
                4CA1FEBD052A3C8100F22E42 /* libsecurity_codesigning */ = {
-                       isa = PBXLibraryTarget;
-                       buildConfigurationList = C263E67509A2971B000043F1 /* Build configuration list for PBXLibraryTarget "libsecurity_codesigning" */;
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = C263E67509A2971B000043F1 /* Build configuration list for PBXNativeTarget "libsecurity_codesigning" */;
                        buildPhases = (
                                4CA1FEB9052A3C8100F22E42 /* Headers */,
                                4CA1FEBA052A3C8100F22E42 /* Sources */,
                                4C789C16055AF56700B6FC95 /* ShellScript */,
                                4CD0D468055B0D40001715CB /* ShellScript */,
                        );
+                       buildRules = (
+                       );
                        dependencies = (
                                4C7502910540C69C00056564 /* PBXTargetDependency */,
                                C21E3F8B0A23AE10006558D6 /* PBXTargetDependency */,
                        name = libsecurity_codesigning;
                        productName = libsecurity_codesigning;
                        productReference = 4CA1FEBE052A3C8100F22E42 /* security_codesigning */;
+                       productType = "com.apple.product-type.library.static";
                };
-/* End PBXLibraryTarget section */
-
-/* Begin PBXNativeTarget section */
                C2BC1F250B580D3A003EC9DC /* libintegrity */ = {
                        isa = PBXNativeTarget;
                        buildConfigurationList = C2BC1F270B580D3F003EC9DC /* Build configuration list for PBXNativeTarget "libintegrity" */;
                        isa = PBXProject;
                        buildConfigurationList = C263E67909A2971B000043F1 /* Build configuration list for PBXProject "libsecurity_codesigning" */;
                        compatibilityVersion = "Xcode 2.4";
+                       developmentRegion = English;
                        hasScannedForEncodings = 1;
+                       knownRegions = (
+                               English,
+                               Japanese,
+                               French,
+                               German,
+                       );
                        mainGroup = 4CA1FEA7052A3C3800F22E42;
                        productRefGroup = 4CA1FEBF052A3C8100F22E42 /* Products */;
                        projectDirPath = "";
                                C2D383B80A23A8C4005C63A2 /* Requirements Language */,
                                C2BC1F250B580D3A003EC9DC /* libintegrity */,
                                C2BC1F2E0B580D4B003EC9DC /* libcodehost */,
+                               C26AC7090DAEB3A7005BFB40 /* DTrace */,
                        );
                };
 /* End PBXProject section */
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/sh;
-                       shellScript = "for variant in ${BUILD_VARIANTS}\ndo\n\tpostfix=`echo _${variant} | sed 's/_normal//'`\n\tln -fs \"../../../${PRODUCT_NAME}${postfix}\" ${SYMROOT}/${PRODUCT_NAME}.framework/Versions/A\n\tln -fs \"Versions/Current/${PRODUCT_NAME}${postfix}\" ${SYMROOT}/${PRODUCT_NAME}.framework\ndone";
+                       shellScript = "for variant in ${BUILD_VARIANTS}\ndo\n\tpostfix=`echo _${variant} | sed 's/_normal//'`\n\tditto -V \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}${postfix}\" \"${SYMROOT}/${PRODUCT_NAME}${postfix}\"\n\tln -fs \"../../../${PRODUCT_NAME}${postfix}\" ${SYMROOT}/${PRODUCT_NAME}.framework/Versions/A\n\tln -fs \"Versions/Current/${PRODUCT_NAME}${postfix}\" ${SYMROOT}/${PRODUCT_NAME}.framework\ndone";
                };
                4CD0D468055B0D40001715CB /* ShellScript */ = {
                        isa = PBXShellScriptBuildPhase;
                        shellPath = /bin/sh;
                        shellScript = "for variant in ${BUILD_VARIANTS}\ndo\n\tpostfix=`echo _${variant} | sed 's/_normal//'`\n\tcp -p \"${SYMROOT}/${PRODUCT_NAME}${postfix}\" \"${DSTROOT}/usr/local/SecurityPieces/Components/Security/${PRODUCT_NAME}.framework/Versions/A\"\n\tranlib \"${DSTROOT}/usr/local/SecurityPieces/Components/Security/${PRODUCT_NAME}.framework/Versions/A/${PRODUCT_NAME}${postfix}\"\n\tln -fs \"Versions/Current/${PRODUCT_NAME}${postfix}\" \"${DSTROOT}/usr/local/SecurityPieces/Components/Security/${PRODUCT_NAME}.framework\"\ndone";
                };
+               C26AC7080DAEB3A7005BFB40 /* ShellScript */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       inputPaths = (
+                               "$(SRCROOT)/lib/security_codesigning.d",
+                       );
+                       outputPaths = (
+                               "$(TEMPDIR)/codesigning_dtrace.h",
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+                       shellPath = /bin/sh;
+                       shellScript = "mkdir -p $TEMPDIR\n/usr/sbin/dtrace -h -C -s $SRCROOT/lib/security_codesigning.d -o $TEMPDIR/codesigning_dtrace.h\n";
+                       showEnvVarsInLog = 0;
+               };
                C26B45C30B8A9C1A003C0ACA /* Prepare ucspc */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 2147483647;
                                "$(TEMPDIR)/RequirementLexer.hpp",
                                "$(TEMPDIR)/RequirementLexer.cpp",
                                "$(TEMPDIR)/RequirementParser.hpp",
+                               "$(TEMPDIR)/RequirementKeywords.h",
                                "$(TEMPDIR)/RequirementParser.cpp",
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/bash;
-                       shellScript = "antlr=/usr/local/bin/antlr.jar\nDEBUG=\"\"\nmkdir -p $TEMPDIR\nrm -f $TEMPDIR/Requirement{Parser,Lexer}*\njava -cp \"$antlr\" antlr.Tool -o $TEMPDIR $DEBUG requirements.grammar\n";
+                       shellScript = "antlr=/usr/local/bin/antlr.jar\nDEBUG=\"\"\nmkdir -p $TEMPDIR\nrm -f $TEMPDIR/Requirement{Parser,Lexer}*\njava -cp \"$antlr\" antlr.Tool -o $TEMPDIR $DEBUG requirements.grammar\nsed -n 's/^.*=\\(\".*\"\\)=.*$/        \\1,/p' $TEMPDIR/RequirementParserTokenTypes.txt >$TEMPDIR/RequirementKeywords.h\n";
                };
 /* End PBXShellScriptBuildPhase section */
 
                                C2D3835D0A237F47005C63A2 /* reqparser.cpp in Sources */,
                                C2C1DF140A2E3D7200D1B02B /* requirement.cpp in Sources */,
                                C2D383610A237F47005C63A2 /* Requirements.cpp in Sources */,
-                               C2D383630A237F47005C63A2 /* security_codesigning.exp in Sources */,
                                C21CFC5F0A250D1C006CD5B1 /* reqdumper.cpp in Sources */,
                                C2C1DFBB0A2F80EB00D1B02B /* reqinterp.cpp in Sources */,
                                C2C1DFC30A2F820500D1B02B /* reqmaker.cpp in Sources */,
                                C224635F0B8620F800626F1B /* RequirementParser.cpp in Sources */,
                                C22463600B8620F800626F1B /* RequirementLexer.cpp in Sources */,
                                C22463610B86210100626F1B /* antlrplugin.cpp in Sources */,
-                               C2CCF0310A3F523D0085795A /* macho++.cpp in Sources */,
                                C2EF10100A49BD89005A44BB /* renum.cpp in Sources */,
                                C2BD519C0A9392FD000FE43D /* machorep.cpp in Sources */,
                                C2C931B40AB8BA1200F83950 /* SecCodeHost.cpp in Sources */,
                                C236E3DB0AD595C2000F5140 /* signerutils.cpp in Sources */,
                                C259DFD60AD6D9BA00C9ACC6 /* sigblob.cpp in Sources */,
                                C2E911E20ADEBE3200275CB2 /* resources.cpp in Sources */,
-                               C2D8A07F0AE7F6E300F68F79 /* cfmunge.cpp in Sources */,
                                C2A976AA0B8A2E36008B4EA0 /* csutilities.cpp in Sources */,
                                C2C3BC5F0BA1D6FE00E869D1 /* cfmdiskrep.cpp in Sources */,
                                C2C3BCD30BA1E47E00E869D1 /* singlediskrep.cpp in Sources */,
-                               C25942440BA7095000877E56 /* foreigndiskrep.cpp in Sources */,
                                C2093AA80BB0948000EB8599 /* reqreader.cpp in Sources */,
                                C2F6566E0BCBFB250078779E /* cserror.cpp in Sources */,
+                               C28342E70E366E6800E54360 /* csdatabase.cpp in Sources */,
+                               C28342EE0E36719D00E54360 /* detachedrep.cpp in Sources */,
+                               C2A436150F2133B2007A41A6 /* slcrep.cpp in Sources */,
+                               FEB30C9310DAC89D00557BA2 /* SecTask.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        target = C2BC1F250B580D3A003EC9DC /* libintegrity */;
                        targetProxy = C250F6C40B5EF4E40076098F /* PBXContainerItemProxy */;
                };
+               C26AC70F0DAEB400005BFB40 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = C26AC7090DAEB3A7005BFB40 /* DTrace */;
+                       targetProxy = C26AC70E0DAEB400005BFB40 /* PBXContainerItemProxy */;
+               };
                C2E287410B5D8F97009336A0 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = 4CA1FEBD052A3C8100F22E42 /* libsecurity_codesigning */;
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                BUILD_VARIANTS = debug;
+                               EXECUTABLE_PREFIX = "";
+                               EXECUTABLE_SUFFIX = "";
                                FRAMEWORK_VERSION = A;
                                GCC_DYNAMIC_NO_PIC = NO;
-                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               INFOPLIST_FILE = "Info-security_codesigning.plist";
                                INSTALL_PATH = /usr/local/SecurityPieces/Components/Security;
                                PRODUCT_NAME = security_codesigning;
                                WRAPPER_EXTENSION = framework;
                C263E67309A2971B000043F1 /* Deployment */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               EXECUTABLE_PREFIX = "";
+                               EXECUTABLE_SUFFIX = "";
                                FRAMEWORK_VERSION = A;
-                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
+                               INFOPLIST_FILE = "Info-security_codesigning.plist";
                                INSTALL_PATH = /usr/local/SecurityPieces/Components/Security;
                                PRODUCT_NAME = security_codesigning;
                                WRAPPER_EXTENSION = framework;
                C263E67409A2971B000043F1 /* Default */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               EXECUTABLE_PREFIX = "";
+                               EXECUTABLE_SUFFIX = "";
                                FRAMEWORK_VERSION = A;
+                               INFOPLIST_FILE = "Info-security_codesigning.plist";
                                INSTALL_PATH = /usr/local/SecurityPieces/Components/Security;
                                PRODUCT_NAME = security_codesigning;
                                WRAPPER_EXTENSION = framework;
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                BUILD_VARIANTS = debug;
-                               CURRENT_PROJECT_VERSION = 36924;
+                               CURRENT_PROJECT_VERSION = 55004;
+                               EXECUTABLE_PREFIX = "";
+                               EXECUTABLE_SUFFIX = "";
                                FRAMEWORK_SEARCH_PATHS = (
                                        /usr/local/SecurityPieces/Frameworks,
                                        /usr/local/SecurityPieces/Components/Security,
                                );
                                GCC_DYNAMIC_NO_PIC = NO;
-                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                HEADER_SEARCH_PATHS = (
                                        "$(BUILT_PRODUCTS_DIR)/SecurityPieces/Headers",
                                        "$(BUILT_PRODUCTS_DIR)/SecurityPieces/PrivateHeaders",
+                                       "$(TEMPDIR)",
                                        "$(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/PrivateHeaders",
                                );
                                LIBRARY_STYLE = "\U0001STATIC";
                                OPT_CFLAGS = "-DNDEBUG -Os $(OPT_INLINEFLAGS)";
                                OPT_CPPFLAGS = "$(OPT_CFLAGS)";
-                               OPT_INLINEFLAGS = "-finline-functions";
                                OPT_LDFLAGS = "";
                                OTHER_ASFLAGS_debug = "$(OTHER_CFLAGS)";
                                OTHER_ASFLAGS_normal = "-DNDEBUG $(OTHER_CFLAGS)";
                                OTHER_CPLUSPLUSFLAGS_debug = "$(OTHER_CFLAGS) -O0 -fno-inline";
                                OTHER_CPLUSPLUSFLAGS_normal = "$(OPT_CPPFLAGS) $(OTHER_CFLAGS)";
                                OTHER_CPLUSPLUSFLAGS_profile = "$(OPT_CPPFLAGS) $(OTHER_CFLAGS) -pg";
-                               OTHER_LDFLAGS_debug = "$(OTHER_LDFLAGS)";
+                               OTHER_LDFLAGS_debug = "";
                                OTHER_LDFLAGS_normal = "$(OPT_LDFLAGS) $(OTHER_LDFLAGS)";
                                OTHER_LDFLAGS_profile = "$(OPT_LDFLAGS) $(OTHER_LDFLAGS) -pg";
-                               PRIVATE_HEADER_DIR = "$(DSTROOT)/usr/local/SecurityPieces/PrivateHeaders/Security";
+                               PRIVATE_HEADERS_FOLDER_PATH = /usr/local/SecurityPieces/PrivateHeaders/Security;
                                PRODUCT_NAME = security_codesigning;
-                               PUBLIC_HEADER_DIR = "$(DSTROOT)/usr/local/SecurityPieces/Headers/Security";
+                               PUBLIC_HEADERS_FOLDER_PATH = /usr/local/SecurityPieces/Headers/Security;
                                VERSIONING_SYSTEM = "apple-generic";
                                WARNING_CFLAGS = (
                                        "-Wmost",
                                        normal,
                                        debug,
                                );
-                               CURRENT_PROJECT_VERSION = 36924;
+                               CURRENT_PROJECT_VERSION = 55004;
+                               EXECUTABLE_PREFIX = "";
+                               EXECUTABLE_SUFFIX = "";
                                FRAMEWORK_SEARCH_PATHS = (
                                        /usr/local/SecurityPieces/Frameworks,
                                        /usr/local/SecurityPieces/Components/Security,
                                );
-                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
                                HEADER_SEARCH_PATHS = (
                                        "$(BUILT_PRODUCTS_DIR)/SecurityPieces/Headers",
                                        "$(BUILT_PRODUCTS_DIR)/SecurityPieces/PrivateHeaders",
+                                       "$(TEMPDIR)",
                                        "$(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/PrivateHeaders",
                                );
                                LIBRARY_STYLE = STATIC;
                                OPT_CFLAGS = "-DNDEBUG -Os $(OPT_INLINEFLAGS)";
                                OPT_CPPFLAGS = "$(OPT_CFLAGS)";
-                               OPT_INLINEFLAGS = "-finline-functions";
                                OPT_LDFLAGS = "";
                                OTHER_ASFLAGS_debug = "$(OTHER_CFLAGS)";
                                OTHER_ASFLAGS_normal = "-DNDEBUG $(OTHER_CFLAGS)";
                                OTHER_CPLUSPLUSFLAGS_debug = "$(OTHER_CFLAGS) -O0 -fno-inline";
                                OTHER_CPLUSPLUSFLAGS_normal = "$(OPT_CPPFLAGS) $(OTHER_CFLAGS)";
                                OTHER_CPLUSPLUSFLAGS_profile = "$(OPT_CPPFLAGS) $(OTHER_CFLAGS) -pg";
-                               OTHER_LDFLAGS_debug = "$(OTHER_LDFLAGS)";
+                               OTHER_LDFLAGS_debug = "";
                                OTHER_LDFLAGS_normal = "$(OPT_LDFLAGS) $(OTHER_LDFLAGS)";
                                OTHER_LDFLAGS_profile = "$(OPT_LDFLAGS) $(OTHER_LDFLAGS) -pg";
-                               PRIVATE_HEADER_DIR = "$(DSTROOT)/usr/local/SecurityPieces/PrivateHeaders/Security";
+                               PRIVATE_HEADERS_FOLDER_PATH = /usr/local/SecurityPieces/PrivateHeaders/Security;
                                PRODUCT_NAME = security_codesigning;
-                               PUBLIC_HEADER_DIR = "$(DSTROOT)/usr/local/SecurityPieces/Headers/Security";
+                               PUBLIC_HEADERS_FOLDER_PATH = /usr/local/SecurityPieces/Headers/Security;
                                VERSIONING_SYSTEM = "apple-generic";
                                WARNING_CFLAGS = (
                                        "-Wmost",
                                        normal,
                                        debug,
                                );
-                               CURRENT_PROJECT_VERSION = 36924;
+                               CURRENT_PROJECT_VERSION = 55004;
+                               EXECUTABLE_PREFIX = "";
+                               EXECUTABLE_SUFFIX = "";
                                FRAMEWORK_SEARCH_PATHS = (
                                        /usr/local/SecurityPieces/Frameworks,
                                        /usr/local/SecurityPieces/Components/Security,
                                HEADER_SEARCH_PATHS = (
                                        "$(BUILT_PRODUCTS_DIR)/SecurityPieces/Headers",
                                        "$(BUILT_PRODUCTS_DIR)/SecurityPieces/PrivateHeaders",
+                                       "$(TEMPDIR)",
                                        "$(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/PrivateHeaders",
                                );
                                LIBRARY_STYLE = STATIC;
                                OPT_CFLAGS = "-DNDEBUG -Os $(OPT_INLINEFLAGS)";
                                OPT_CPPFLAGS = "$(OPT_CFLAGS)";
-                               OPT_INLINEFLAGS = "-finline-functions";
                                OPT_LDFLAGS = "";
                                OTHER_ASFLAGS_debug = "$(OTHER_CFLAGS)";
                                OTHER_ASFLAGS_normal = "-DNDEBUG $(OTHER_CFLAGS)";
                                OTHER_CPLUSPLUSFLAGS_debug = "$(OTHER_CFLAGS) -O0 -fno-inline";
                                OTHER_CPLUSPLUSFLAGS_normal = "$(OPT_CPPFLAGS) $(OTHER_CFLAGS)";
                                OTHER_CPLUSPLUSFLAGS_profile = "$(OPT_CPPFLAGS) $(OTHER_CFLAGS) -pg";
-                               OTHER_LDFLAGS_debug = "$(OTHER_LDFLAGS)";
+                               OTHER_LDFLAGS_debug = "";
                                OTHER_LDFLAGS_normal = "$(OPT_LDFLAGS) $(OTHER_LDFLAGS)";
                                OTHER_LDFLAGS_profile = "$(OPT_LDFLAGS) $(OTHER_LDFLAGS) -pg";
-                               PRIVATE_HEADER_DIR = "$(DSTROOT)/usr/local/SecurityPieces/PrivateHeaders/Security";
+                               PRIVATE_HEADERS_FOLDER_PATH = /usr/local/SecurityPieces/PrivateHeaders/Security;
                                PRODUCT_NAME = security_codesigning;
-                               PUBLIC_HEADER_DIR = "$(DSTROOT)/usr/local/SecurityPieces/Headers/Security";
+                               PUBLIC_HEADERS_FOLDER_PATH = /usr/local/SecurityPieces/Headers/Security;
                                VERSIONING_SYSTEM = "apple-generic";
                                WARNING_CFLAGS = (
                                        "-Wmost",
                        buildSettings = {
                                CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)";
                                CONFIGURATION_TEMP_DIR = "$(PROJECT_TEMP_DIR)";
+                               GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
                                HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
                                OTHER_CFLAGS = "$(SEC_DEFINES)";
                                TEMPDIR = "$(BUILT_PRODUCTS_DIR)/cstemp";
                        buildSettings = {
                                CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)";
                                CONFIGURATION_TEMP_DIR = "$(PROJECT_TEMP_DIR)";
+                               GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
                                HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
                                OTHER_CFLAGS = "$(SEC_DEFINES)";
                                TEMPDIR = "$(BUILT_PRODUCTS_DIR)/cstemp";
                        buildSettings = {
                                CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)";
                                CONFIGURATION_TEMP_DIR = "$(PROJECT_TEMP_DIR)";
+                               GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
                                HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
                                OTHER_CFLAGS = "$(SEC_DEFINES)";
                                TEMPDIR = "$(BUILT_PRODUCTS_DIR)/cstemp";
                        };
                        name = Default;
                };
+               C26AC70A0DAEB3A8005BFB40 /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               PRODUCT_NAME = DTrace;
+                       };
+                       name = Development;
+               };
+               C26AC70B0DAEB3A8005BFB40 /* Deployment */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = YES;
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               PRODUCT_NAME = DTrace;
+                               ZERO_LINK = NO;
+                       };
+                       name = Deployment;
+               };
+               C26AC70C0DAEB3A8005BFB40 /* Default */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               PRODUCT_NAME = DTrace;
+                       };
+                       name = Default;
+               };
                C2BC1F280B580D3F003EC9DC /* Development */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                COPY_PHASE_STRIP = NO;
                                FRAMEWORK_SEARCH_PATHS = /usr/local/SecurityPieces/Frameworks;
                                GCC_DYNAMIC_NO_PIC = NO;
-                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
                                GCC_MODEL_TUNING = G5;
                                GCC_OPTIMIZATION_LEVEL = 0;
                                INSTALL_PATH = /usr/local/lib;
                                COPY_PHASE_STRIP = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                FRAMEWORK_SEARCH_PATHS = /usr/local/SecurityPieces/Frameworks;
-                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
                                GCC_MODEL_TUNING = G5;
                                INSTALL_PATH = /usr/local/lib;
                                PREBINDING = NO;
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                FRAMEWORK_SEARCH_PATHS = /usr/local/SecurityPieces/Frameworks;
-                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
                                GCC_MODEL_TUNING = G5;
                                INSTALL_PATH = /usr/local/lib;
                                PREBINDING = NO;
                                COPY_PHASE_STRIP = NO;
                                FRAMEWORK_SEARCH_PATHS = /usr/local/SecurityPieces/Frameworks;
                                GCC_DYNAMIC_NO_PIC = NO;
-                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
                                GCC_MODEL_TUNING = G5;
                                GCC_OPTIMIZATION_LEVEL = 0;
                                INSTALL_PATH = /usr/local/lib;
                                COPY_PHASE_STRIP = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                FRAMEWORK_SEARCH_PATHS = /usr/local/SecurityPieces/Frameworks;
-                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
                                GCC_MODEL_TUNING = G5;
                                INSTALL_PATH = /usr/local/lib;
                                LIBRARY_SEARCH_PATHS = (
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                FRAMEWORK_SEARCH_PATHS = /usr/local/SecurityPieces/Frameworks;
-                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
                                GCC_MODEL_TUNING = G5;
                                INSTALL_PATH = /usr/local/lib;
                                LIBRARY_SEARCH_PATHS = (
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                COPY_PHASE_STRIP = YES;
-                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
                                PRODUCT_NAME = "Requirements Language";
                                ZERO_LINK = NO;
                        buildSettings = {
                                COPY_PHASE_STRIP = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               GCC_ENABLE_FIX_AND_CONTINUE = NO;
                                PRODUCT_NAME = Everything;
                                ZERO_LINK = NO;
                        };
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
-               C263E67109A2971B000043F1 /* Build configuration list for PBXFrameworkTarget "security_codesigning" */ = {
+               C263E67109A2971B000043F1 /* Build configuration list for PBXNativeTarget "security_codesigning" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                                C263E67209A2971B000043F1 /* Development */,
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Default;
                };
-               C263E67509A2971B000043F1 /* Build configuration list for PBXLibraryTarget "libsecurity_codesigning" */ = {
+               C263E67509A2971B000043F1 /* Build configuration list for PBXNativeTarget "libsecurity_codesigning" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                                C263E67609A2971B000043F1 /* Development */,
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Default;
                };
+               C26AC70D0DAEB3C6005BFB40 /* Build configuration list for PBXAggregateTarget "DTrace" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               C26AC70A0DAEB3A8005BFB40 /* Development */,
+                               C26AC70B0DAEB3A8005BFB40 /* Deployment */,
+                               C26AC70C0DAEB3A8005BFB40 /* Default */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Default;
+               };
                C2BC1F270B580D3F003EC9DC /* Build configuration list for PBXNativeTarget "libintegrity" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
diff --git a/req/ppc-host.ireq b/req/ppc-host.ireq
new file mode 100644 (file)
index 0000000..a43b31a
--- /dev/null
@@ -0,0 +1,4 @@
+#
+# Suggested internal host requirement for (only) ppc Mach-O code
+#
+anchor apple and identifier com.apple.translate                // Rosetta
diff --git a/req/ppc.ireqs b/req/ppc.ireqs
deleted file mode 100644 (file)
index 618abaa..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#
-# Suggested internal requirements for ppc (only) Mach-O code
-#
-host => anchor apple and identifier com.apple.translate                // Rosetta
diff --git a/req/workaround.ireqs b/req/workaround.ireqs
deleted file mode 100644 (file)
index 4252ada..0000000
+++ /dev/null
@@ -1 +0,0 @@
-anchor apple and (identifier com.apple.translate or identifier com.apple.LaunchCFMApp)
index 45827a4c457ed1ef8541ba177e57c32b34f1ea9a..f6972e7accbf38e8fe395def575e9de5aeb2d3ed 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2006-2008 Apple Inc. All Rights Reserved.
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -104,16 +104,35 @@ options {
                memcpy(hash, hexString(s).data(), SHA1::digestLength);
        }
        
-       void RequirementParser::certMatchOperation(Maker &maker, int slot, string key)
+       static const char *matchPrefix(const string &key, const char *prefix)
        {
-               if (!key.compare(0, 8, "subject.", 0, 8)) {
+               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 (!key.compare(0, 6, "field.", 0, 6)) {
+               } 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(key.c_str() + 6);
+                       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");
@@ -137,7 +156,7 @@ public:
 private:
        static string hexString(const string &s);
        static void hashString(const string &s, SHA1::Digest hash);
-       void certMatchOperation(Maker &maker, int slot, string key);
+       void certMatchOperation(Maker &maker, int32_t slot, string key);
 }
 
 
@@ -173,6 +192,8 @@ requirementType returns [uint32_t type = kSecInvalidRequirementType]
                        { type = kSecDesignatedRequirementType; }
        |       "library"
                        { type = kSecLibraryRequirementType; }
+       |       "plugin"
+                       { type = kSecPluginRequirementType; }
        |       stype:INTEGER
                        { type = atol(stype->getText().c_str()); }
        ;
@@ -199,12 +220,12 @@ requirementElement returns [Requirement *result = NULL]
 // 
 expr[Maker &maker]
                { Maker::Label label(maker); }
-       :       term[maker] ( "and" { maker.insert<ExprOp>(label) = opAnd; } term[maker] )*
+       :       term[maker] ( "or" { maker.insert<ExprOp>(label) = opOr; } term[maker] )*
        ;
 
 term[Maker &maker]
                { Maker::Label label(maker); }
-       :       primary[maker] ( "or" { maker.insert<ExprOp>(label) = opOr; } primary[maker] )*
+       :       primary[maker] ( "and" { maker.insert<ExprOp>(label) = opAnd; } primary[maker] )*
        ;
 
 primary[Maker &maker]
@@ -221,6 +242,8 @@ primary[Maker &maker]
                        { maker.ident(code); }
        |       "cdhash" { SHA1::Digest digest; } eql hash[digest]
                        { maker.cdhash(digest); }
+       |       LPAREN { string name; } name=identifierString RPAREN
+                       { maker.put(opNamedCode); maker.put(name); }
        ;
 
 
@@ -233,7 +256,7 @@ certspec[Maker &maker]
                        { maker.put(opAppleGenericAnchor); }
        |       ( "certificate" | "cert" | "anchor" ) "trusted"
                        { maker.trustedAnchor(); }
-       |       ( "certificate" | "cert" ) { int slot; } slot=certSlot
+       |       ( "certificate" | "cert" ) { int32_t slot; } slot=certSlot
                ( certslotspec[maker, slot] | "trusted" { maker.trustedAnchor(slot); } )
        |       "anchor" certslotspec[maker, Requirement::anchorCert]
        ;
@@ -243,9 +266,11 @@ appleanchor[Maker &maker]
                        { maker.put(opAppleAnchor); }
        |       "generic"
                        { maker.put(opAppleGenericAnchor); }
+|      |       { string name; } name=identifierString
+                       { maker.put(opNamedAnchor); maker.put(name); }
        ;
 
-certslotspec[Maker &maker, int slot]   { string key; }
+certslotspec[Maker &maker, int32_t slot]       { string key; }
        :       eql { SHA1::Digest digest; } certificateDigest[digest]
             { maker.anchor(slot, digest); }
        |       key=bracketKey
@@ -303,9 +328,9 @@ bracketKey returns [string key]
        ;
 
 //
-// A certSlot identifiers one certificate from the certificate chain
+// A certSlot identifies one certificate from the certificate chain
 //
-certSlot returns [int slot]
+certSlot returns [int32_t slot = 0]
        :       s:INTEGER               // counting from the anchor up
                        { slot = atol(s->getText().c_str()); }
        |       NEG ss:INTEGER  // counting from the leaf down