]> git.saurik.com Git - apple/libsecurity_codesigning.git/commitdiff
libsecurity_codesigning-55032.tar.gz mac-os-x-1073 v55032
authorApple <opensource@apple.com>
Fri, 16 Dec 2011 01:56:44 +0000 (01:56 +0000)
committerApple <opensource@apple.com>
Fri, 16 Dec 2011 01:56:44 +0000 (01:56 +0000)
81 files changed:
APPLE_LICENSE [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
lib/Code.cpp
lib/CodeSigner.cpp
lib/CodeSigner.h
lib/Requirements.cpp
lib/Requirements.h
lib/SecAssessment.cpp [new file with mode: 0644]
lib/SecAssessment.h [new file with mode: 0644]
lib/SecCode.cpp
lib/SecCode.h
lib/SecCodeHost.cpp
lib/SecCodePriv.h
lib/SecCodeSigner.cpp
lib/SecCodeSigner.h
lib/SecRequirement.cpp
lib/SecRequirementPriv.h
lib/SecStaticCode.cpp
lib/SecStaticCode.h
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/codedirectory.cpp
lib/codedirectory.h
lib/cs.h
lib/csdatabase.cpp
lib/csdatabase.h
lib/cserror.cpp
lib/cserror.h
lib/csgeneric.cpp
lib/cskernel.cpp
lib/csutilities.cpp
lib/csutilities.h
lib/diskrep.cpp
lib/diskrep.h
lib/filediskrep.cpp
lib/filediskrep.h
lib/kerneldiskrep.cpp
lib/kerneldiskrep.h
lib/machorep.cpp
lib/machorep.h
lib/policydb.cpp [new file with mode: 0644]
lib/policydb.h [new file with mode: 0644]
lib/policyengine.cpp [new file with mode: 0644]
lib/policyengine.h [new file with mode: 0644]
lib/renum.cpp
lib/reqdumper.cpp
lib/reqinterp.cpp
lib/reqinterp.h
lib/reqparser.cpp
lib/requirement.cpp
lib/requirement.h
lib/resources.cpp
lib/resources.h
lib/security_codesigning.d
lib/security_codesigning.exp
lib/signer.cpp
lib/signer.h
lib/signerutils.cpp
lib/signerutils.h
lib/singlediskrep.cpp
lib/singlediskrep.h
lib/slcrep.cpp
lib/slcrep.h
lib/syspolicy.sql [new file with mode: 0644]
lib/xar++.cpp [new file with mode: 0644]
lib/xar++.h [new file with mode: 0644]
lib/xpcengine.cpp [new file with mode: 0644]
lib/xpcengine.h [new file with mode: 0644]
libsecurity_codesigning.xcodeproj/project.pbxproj
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/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 c4fc3557f2e4100fecff9d88437859bc7b945ad0..4aae1709b703dae3fdb0b5a72f1a1d98f9083b10 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,65 +42,75 @@ 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 */
-       errSecCSHostProtocolInvalidHash,        /* host protocol violation - invalid guest hash */
-       errSecCSStaticCodeChanged,                      /* the program on disk does not match what is running */
-       errSecCSSigDBDenied,                            /* access to signature database denied */
-       errSecCSSigDBAccess,                            /* cannot access signature database */
-       errSecCSHostProtocolInvalidAttribute, /* host returned invalid or inconsistent guest attributes */
+       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 */
+       errSecCSDBDenied =                                      -67033, /* permission to use a database denied */
+       errSecCSDBAccess =                                      -67032, /* cannot access a database */
+       errSecCSSigDBDenied = errSecCSDBDenied,
+       errSecCSSigDBAccess = errSecCSDBAccess,
+       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 */
+       errSecCSBadBundleFormat =                       -67028, /* bundle format unrecognized, invalid, or unsuitable */
 };
 
 
 /*
  * 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 */
+extern const CFStringRef kSecCFErrorPath;                      /* CFURLRef: subcomponent containing the error */
 
 
 /*!
@@ -180,7 +190,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
@@ -195,8 +205,8 @@ 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 flag on all validations of the code.
  */
@@ -207,35 +217,49 @@ 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 operational flags to each running code.
+       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, 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.
+       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.
+       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 properly signed
-       and has not been invalidated since it started. The valid bit can only be cleared.
-       Note that this bit does not make any representations on the static validity of the code.
+       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
+       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 seem random.
+       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 invalid (and live).
+       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 {
@@ -252,10 +276,11 @@ enum {
 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 */
 };
index 084cd882517f486bd66c6f04b0a615437b2aa3c0..e3413624d3696b80fee92a7204b91e0eb2870475 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@
  * 
@@ -89,6 +89,29 @@ enum {
 };
 
 
+/*!
+       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
index 40a1edcd37e46fff855596cb0068a9de6274b584..ab5072aec05ac5726d264e54f4de488ae3d2b2c7 100644 (file)
@@ -49,7 +49,9 @@ SecCode::SecCode(SecCode *host)
 // Clean up a SecCode object
 //
 SecCode::~SecCode() throw()
-{
+try {
+} catch (...) {
+       return;
 }
 
 
@@ -180,7 +182,7 @@ void SecCode::checkValidity(SecCSFlags flags)
 {
        if (this->isRoot()) {
                // the root-of-trust is valid by definition
-               CODESIGN_EVAL_DYNAMIC_ROOT();
+               CODESIGN_EVAL_DYNAMIC_ROOT(this);
                return;
        }
        DTRACK(CODESIGN_EVAL_DYNAMIC, this, (char*)this->staticCode()->mainExecutablePath().c_str());
index f2ff65b48f18f3d59b166fd66de59415f0bf21ab..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@
  * 
@@ -63,7 +63,7 @@ public:
 // Construct a SecCodeSigner
 //
 SecCodeSigner::SecCodeSigner(SecCSFlags flags)
-       : mOpFlags(flags), mRequirements(NULL)
+       : mOpFlags(flags), mRequirements(NULL), mDigestAlgorithm(kSecCodeSignatureDefaultDigestAlgorithm)
 {
 }
 
@@ -72,8 +72,10 @@ SecCodeSigner::SecCodeSigner(SecCSFlags flags)
 // Clean up a SecCodeSigner
 //
 SecCodeSigner::~SecCodeSigner() throw()
-{
+try {
        ::free((Requirements *)mRequirements);
+} catch (...) {
+       return;
 }
 
 
@@ -134,12 +136,31 @@ void SecCodeSigner::returnDetachedSignature(BlobCore *blob, Signer &signer)
                CFDataAppendBytes(CFMutableDataRef(mDetached.get()),
                        (const UInt8 *)blob, blob->length());
        } else if (CFGetTypeID(mDetached) == CFNullGetTypeID()) {
-               signatureDatabase().storeCode(blob, signer.path().c_str());
+               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.
 //
@@ -162,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);
@@ -210,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 ba401ee64e33485f24a43ae3b1c52271ec28b959..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,7 +41,7 @@ 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;
@@ -61,6 +61,10 @@ public:
        
        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
@@ -70,10 +74,12 @@ private:
        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:
diff --git a/lib/SecAssessment.cpp b/lib/SecAssessment.cpp
new file mode 100644 (file)
index 0000000..d5a5a89
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2011 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 "cs.h"
+#include "SecAssessment.h"
+#include "policydb.h"
+#include "policyengine.h"
+#include "xpcengine.h"
+#include "csutilities.h"
+#include <CoreFoundation/CFRuntime.h>
+#include <security_utilities/globalizer.h>
+#include <security_utilities/unix++.h>
+#include <security_utilities/cfmunge.h>
+
+using namespace CodeSigning;
+
+
+//
+// CF Objects
+//
+struct _SecAssessment : private CFRuntimeBase {
+public:
+       _SecAssessment(CFURLRef p, CFDictionaryRef r) : path(p), result(r) { }
+       
+       CFCopyRef<CFURLRef> path;
+       CFRef<CFDictionaryRef> result;
+
+public:
+       static _SecAssessment &ref(SecAssessmentRef r)
+               { return *(_SecAssessment *)r; }
+
+       // CF Boiler-plate
+       void *operator new (size_t size)
+       {
+               return (void *)_CFRuntimeCreateInstance(NULL, SecAssessmentGetTypeID(),
+                       sizeof(_SecAssessment) - sizeof(CFRuntimeBase), NULL);
+       }
+       
+       static void finalize(CFTypeRef obj)
+       { ((_SecAssessment *)obj)->~_SecAssessment(); }
+};
+
+typedef _SecAssessment SecAssessment;
+
+
+static const CFRuntimeClass assessmentClass = {
+       0,                                                              // version
+       "SecAssessment",                                // name
+       NULL,                                                   // init
+       NULL,                                                   // copy
+       SecAssessment::finalize,                // finalize
+       NULL,                                                   // equal
+       NULL,                                                   // hash
+       NULL,                                                   // formatting
+       NULL                                                    // debug string
+};
+
+
+static dispatch_once_t assessmentOnce;
+CFTypeID assessmentType = _kCFRuntimeNotATypeID;
+       
+CFTypeID SecAssessmentGetTypeID()
+{
+       
+       dispatch_once(&assessmentOnce, ^void() {
+               if ((assessmentType = _CFRuntimeRegisterClass(&assessmentClass)) == _kCFRuntimeNotATypeID)
+                       abort();
+       });
+       return assessmentType;
+}
+
+
+//
+// Common dictionary constants
+//
+const CFStringRef kSecAssessmentContextKeyOperation = CFSTR("operation");
+const CFStringRef kSecAssessmentOperationTypeExecute = CFSTR("operation:execute");
+const CFStringRef kSecAssessmentOperationTypeInstall = CFSTR("operation:install");
+const CFStringRef kSecAssessmentOperationTypeOpenDocument = CFSTR("operation:lsopen");
+
+
+//
+// Read-only in-process access to the policy database
+//
+class ReadPolicy : public PolicyDatabase {
+public:
+       ReadPolicy() : PolicyDatabase(defaultDatabase) { }
+};
+ModuleNexus<ReadPolicy> gDatabase;
+
+
+//
+// An on-demand instance of the policy engine
+//
+ModuleNexus<PolicyEngine> gEngine;
+
+
+//
+// Help mapping API-ish CFString keys to more convenient internal enumerations
+//
+typedef struct {
+       CFStringRef cstring;
+       uint enumeration;
+} StringMap;
+
+static uint mapEnum(CFDictionaryRef context, CFStringRef attr, const StringMap *map, uint value = 0)
+{
+       if (context)
+               if (CFTypeRef value = CFDictionaryGetValue(context, attr))
+                       for (const StringMap *mp = map; mp->cstring; ++mp)
+                               if (CFEqual(mp->cstring, value))
+                                       return mp->enumeration;
+       if (value)
+               return value;
+       MacOSError::throwMe(errSecCSInvalidAttributeValues);
+}
+
+static const StringMap mapType[] = {
+       { kSecAssessmentOperationTypeExecute, kAuthorityExecute },
+       { kSecAssessmentOperationTypeInstall, kAuthorityInstall },
+       { kSecAssessmentOperationTypeOpenDocument, kAuthorityOpenDoc },
+       { NULL }
+};
+
+static AuthorityType typeFor(CFDictionaryRef context, AuthorityType type = kAuthorityInvalid)
+{ return mapEnum(context, kSecAssessmentContextKeyOperation, mapType, type); }
+
+
+//
+// Policy evaluation ("assessment") operations
+//
+const CFStringRef kSecAssessmentContextKeyCertificates = CFSTR("context:certificates");
+
+const CFStringRef kSecAssessmentAssessmentVerdict = CFSTR("assessment:verdict");
+const CFStringRef kSecAssessmentAssessmentOriginator = CFSTR("assessment:originator");
+const CFStringRef kSecAssessmentAssessmentAuthority = CFSTR("assessment:authority");
+const CFStringRef kSecAssessmentAssessmentSource = CFSTR("assessment:authority:source");
+const CFStringRef kSecAssessmentAssessmentAuthorityRow = CFSTR("assessment:authority:row");
+const CFStringRef kSecAssessmentAssessmentAuthorityOverride = CFSTR("assessment:authority:override");
+const CFStringRef kSecAssessmentAssessmentFromCache = CFSTR("assessment:authority:cached");
+
+SecAssessmentRef SecAssessmentCreate(CFURLRef path,
+       SecAssessmentFlags flags,
+       CFDictionaryRef context,
+       CFErrorRef *errors)
+{
+       BEGIN_CSAPI
+       SYSPOLICY_ASSESS_API(cfString(path).c_str(), flags);
+       
+       if (flags & kSecAssessmentFlagAsynchronous)
+               MacOSError::throwMe(errSecCSUnimplemented);
+       
+       AuthorityType type = typeFor(context, kAuthorityExecute);
+       CFRef<CFMutableDictionaryRef> result = makeCFMutableDictionary();
+
+       try {
+               // check the object cache first unless caller denied that or we need extended processing
+               if (!(flags & (kSecAssessmentFlagRequestOrigin | kSecAssessmentFlagIgnoreCache))) {
+                       if (gDatabase().checkCache(path, type, result))
+                               return new SecAssessment(path, result.yield());
+               }
+               
+               if (flags & kSecAssessmentFlagDirect) {
+                       // ask the engine right here to do its thing
+                       SYSPOLICY_ASSESS_LOCAL();
+                       gEngine().evaluate(path, type, flags, context, result);
+               } else {
+                       // relay the question to our daemon for consideration
+                       SYSPOLICY_ASSESS_REMOTE();
+                       xpcEngineAssess(path, flags, context, result);
+               }
+       } catch (CommonError &error) {
+               if (!overrideAssessment())
+                       throw;          // let it go as an error
+               cfadd(result, "{%O=#F,'assessment:error'=%d}}", kSecAssessmentAssessmentVerdict, error.osStatus());
+       } catch (...) {
+               if (!overrideAssessment())
+                       throw;          // let it go as an error
+               cfadd(result, "{%O=#F}", kSecAssessmentAssessmentVerdict);
+       }
+       return new SecAssessment(path, result.yield());
+
+       END_CSAPI_ERRORS1(NULL)
+}
+
+
+static void traceResult(SecAssessment &assessment, CFDictionaryRef result)
+{
+       if (CFDictionaryGetValue(result, CFSTR("assessment:remote")))
+               return;         // just traced in syspolicyd
+
+       CFRef<CFURLRef> url = CFURLCopyAbsoluteURL(assessment.path);
+       string sanitized = cfString(url);
+       string::size_type rslash = sanitized.rfind('/');
+       if (rslash != string::npos)
+               sanitized = sanitized.substr(rslash+1);
+       string::size_type dot = sanitized.rfind('.');
+       if (dot != string::npos)
+               sanitized = sanitized.substr(dot+1);
+       else
+               sanitized = "(none)";
+
+       string identifier = "UNBUNDLED";
+       if (CFRef<CFBundleRef> bundle = CFBundleCreate(NULL, assessment.path))
+               if (CFStringRef ident = CFBundleGetIdentifier(bundle))
+                       identifier = cfString(ident);
+       
+       string authority = "UNSPECIFIED";
+       bool overridden = false;
+       if (CFDictionaryRef authdict = CFDictionaryRef(CFDictionaryGetValue(result, kSecAssessmentAssessmentAuthority))) {
+               if (CFStringRef auth = CFStringRef(CFDictionaryGetValue(authdict, kSecAssessmentAssessmentSource)))
+                       authority = cfString(auth);
+               else
+                       authority = "no authority";
+               if (CFDictionaryGetValue(authdict, kSecAssessmentAssessmentAuthorityOverride))
+                       overridden = true;
+       }
+       
+       MessageTrace trace("com.apple.security.assessment.outcome", NULL);
+       trace.add("signature2", "bundle:%s", identifier.c_str());
+       if (CFDictionaryGetValue(result, kSecAssessmentAssessmentVerdict) == kCFBooleanFalse) {
+               trace.add("signature", "denied:%s", authority.c_str());
+               trace.add("signature3", sanitized.c_str());
+               trace.send("assessment denied for %s", sanitized.c_str());
+       } else if (overridden) {
+               trace.add("signature", "override:%s", authority.c_str());
+               trace.add("signature3", sanitized.c_str());
+               trace.send("assessment denied for %s but overridden", sanitized.c_str());
+       } else {
+               trace.add("signature", "granted:%s", authority.c_str());
+               trace.add("signature3", sanitized.c_str());
+               trace.send("assessment granted for %s by %s", sanitized.c_str(), authority.c_str());
+       }
+}
+
+
+//
+// At present, CopyResult simply retrieves the result already formed by Create.
+// In the future, this will be more lazy.
+//
+CFDictionaryRef SecAssessmentCopyResult(SecAssessmentRef assessmentRef,
+       SecAssessmentFlags flags,
+       CFErrorRef *errors)
+{
+       BEGIN_CSAPI
+
+       SecAssessment &assessment = SecAssessment::ref(assessmentRef);
+       CFCopyRef<CFDictionaryRef> result = assessment.result;
+       if (!(flags & kSecAssessmentFlagEnforce) && overrideAssessment()) {
+               // turn rejections into approvals, but note that we did that
+               if (CFDictionaryGetValue(result, kSecAssessmentAssessmentVerdict) == kCFBooleanFalse) {
+                       CFRef<CFMutableDictionaryRef> adulterated = makeCFMutableDictionary(result.get());
+                       CFDictionarySetValue(adulterated, kSecAssessmentAssessmentVerdict, kCFBooleanTrue);
+                       if (CFDictionaryRef authority = CFDictionaryRef(CFDictionaryGetValue(adulterated, kSecAssessmentAssessmentAuthority))) {
+                               CFRef<CFMutableDictionaryRef> authority2 = makeCFMutableDictionary(authority);
+                               CFDictionarySetValue(authority2, kSecAssessmentAssessmentAuthorityOverride, CFSTR("security disabled"));
+                               CFDictionarySetValue(adulterated, kSecAssessmentAssessmentAuthority, authority2);
+                       } else {
+                               cfadd(adulterated, "{%O={%O='security disabled'}}",
+                                       kSecAssessmentAssessmentAuthority, kSecAssessmentAssessmentAuthorityOverride);
+                       }
+                       result = adulterated.get();
+               }
+       }
+       traceResult(assessment, result);
+       return result.yield();
+
+       END_CSAPI_ERRORS1(NULL)
+}
+
+
+//
+// Policy editing operations
+//
+const CFStringRef kSecAssessmentContextKeyUpdate = CFSTR("update");
+const CFStringRef kSecAssessmentUpdateOperationAddFile = CFSTR("update:addfile");
+const CFStringRef kSecAssessmentUpdateOperationRemoveFile = CFSTR("update:removefile");
+
+const CFStringRef kSecAssessmentUpdateKeyPriority = CFSTR("update:priority");
+const CFStringRef kSecAssessmentUpdateKeyLabel = CFSTR("update:label");
+
+Boolean SecAssessmentUpdate(CFURLRef path,
+       SecAssessmentFlags flags,
+       CFDictionaryRef context,
+       CFErrorRef *errors)
+{
+       BEGIN_CSAPI
+
+       CFDictionary ctx(context, errSecCSInvalidAttributeValues);
+       CFStringRef edit = ctx.get<CFStringRef>(kSecAssessmentContextKeyUpdate);
+
+       AuthorityType type = typeFor(context);
+       if (edit == kSecAssessmentUpdateOperationAddFile)
+               return gEngine().add(path, type, flags, context);
+       else if (edit == kSecAssessmentUpdateOperationRemoveFile)
+               MacOSError::throwMe(errSecCSUnimplemented);
+       else
+               MacOSError::throwMe(errSecCSInvalidAttributeValues);
+
+       END_CSAPI_ERRORS1(false)
+}
+
+
+//
+// The fcntl of System Policies.
+// For those very special requests.
+//
+Boolean SecAssessmentControl(CFStringRef control, void *arguments, CFErrorRef *errors)
+{
+       BEGIN_CSAPI
+       
+       if (CFEqual(control, CFSTR("ui-enable"))) {
+               UnixPlusPlus::AutoFileDesc flagFile(visibleSecurityFlagFile, O_CREAT | O_WRONLY, 0644);
+               MessageTrace trace("com.apple.security.assessment.state", "enable");
+               trace.send("enable assessment outcomes");
+               return true;
+       } else if (CFEqual(control, CFSTR("ui-disable"))) {
+               if (::remove(visibleSecurityFlagFile) == 0 || errno == ENOENT) {
+                       MessageTrace trace("com.apple.security.assessment.state", "disable");
+                       trace.send("disable assessment outcomes");
+                       return true;
+               }
+               UnixError::throwMe();
+       } else if (CFEqual(control, CFSTR("ui-status"))) {
+               CFBooleanRef &result = *(CFBooleanRef*)(arguments);
+               if (overrideAssessment())
+                       result = kCFBooleanFalse;
+               else
+                       result = kCFBooleanTrue;
+               return true;
+       } else
+               MacOSError::throwMe(errSecCSInvalidAttributeValues);
+
+       END_CSAPI_ERRORS1(false)
+}
diff --git a/lib/SecAssessment.h b/lib/SecAssessment.h
new file mode 100644 (file)
index 0000000..546b139
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2011 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 _H_SECASSESSMENT
+#define _H_SECASSESSMENT
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*!
+ * @type SecAccessmentRef An assessment being performed.
+ */
+typedef struct _SecAssessment *SecAssessmentRef;
+
+
+/*!
+ * CF-standard type function
+ */
+CFTypeID SecAssessmentGetTypeID();
+
+
+/*!
+ * Primary operation codes. These are operations the system policy can express
+ * opinions on. They are not operations *on* the system configuration itself.
+ * (For those, see SecAssessmentUpdate below.)
+ *
+ * @constant kSecAssessmentContextKeyOperation Context key describing the type of operation
+ *     being contemplated.
+ * @constant kSecAssessmentOperationTypeInstall Value denoting the operation of installing
+ *     software into the system.
+ * @constant kSecAssessmentOperationTypeExecute Value denoting the operation of running or executing
+ *     code on the system.
+ */
+extern const CFStringRef kSecAssessmentContextKeyOperation;    // proposed operation
+extern const CFStringRef kSecAssessmentOperationTypeExecute;   // .. execute code
+extern const CFStringRef kSecAssessmentOperationTypeInstall;   // .. install software
+extern const CFStringRef kSecAssessmentOperationTypeOpenDocument; // .. LaunchServices-level document open
+
+
+/*!
+       Operational flags for SecAssessment calls
+       
+       @type SecAssessmentFlags A mask of flag bits passed to SecAssessment calls to influence their
+               operation.
+       
+       @constant kSecAssessmentDefaultFlags Pass this to indicate that default behavior is desired.
+       @constant kSecAssessmentFlagIgnoreCache Do not use cached information; always perform a full
+               evaluation of system policy. This may be substantially slower.
+       @constant kSecAssessmentFlagNoCache Do not save any evaluation outcome in the system caches.
+               Any content already there is left undisturbed. Independent of kSecAssessmentFlagIgnoreCache.
+       
+       Flags common to multiple calls are assigned from high-bit down. Flags for particular calls
+       are assigned low-bit up, and are documented with that call.
+ */
+typedef uint64_t SecAssessmentFlags;
+enum {
+       kSecAssessmentDefaultFlags = 0,                                 // default behavior
+
+       kSecAssessmentFlagDirect = 1 << 30,                             // in-process evaluation
+       kSecAssessmentFlagAsynchronous = 1 << 29,               // request asynchronous operation
+       kSecAssessmentFlagIgnoreCache = 1 << 28,                // do not search cache
+       kSecAssessmentFlagNoCache = 1 << 27,                    // do not populate cache
+       kSecAssessmentFlagEnforce = 1 << 26,                    // force on (disable bypass switches)
+};
+
+
+/*!
+       @function SecAssessmentCreate
+       Ask the system for its assessment of a proposed operation.
+       
+       @param path CFURL describing the file central to the operation - the program
+               to be executed, archive to be installed, plugin to be loaded, etc.
+       @param flags Operation flags and options. Pass kSecAssessmentDefaultFlags for default
+               behavior.
+       @param context Optional CFDictionaryRef containing additional information bearing
+               on the requested assessment.
+       @param errors Standard CFError argument for reporting errors. Note that declining to permit
+               the proposed operation is not an error. Inability to form a judgment is.
+       @result On success, a SecAssessment object that can be queried for its outcome.
+               On error, NULL (with *errors set).
+       
+       Option flags:
+       
+       @constant kSecAssessmentFlagRequestOrigin Request additional work to produce information on
+               the originator (signer) of the object being discussed.
+
+       Context keys:
+
+       @constant kSecAssessmentContextKeyOperation Type of operation (see overview above). This defaults
+               to the kSecAssessmentOperationTypeExecute.
+       @constant kSecAssessmentContextKeyEdit A CFArray of SecCertificateRefs describing the
+               certificate chain of a CMS-type signature as pulled from 'path' by the caller.
+               The first certificate is the signing certificate. The certificates provided must be
+               sufficient to construct a valid certificate chain.
+ */
+extern const CFStringRef kSecAssessmentContextKeyCertificates; // certificate chain as provided by caller
+
+extern const CFStringRef kSecAssessmentAssessmentVerdict;              // CFBooleanRef: master result - allow or deny
+extern const CFStringRef kSecAssessmentAssessmentOriginator;   // CFStringRef: describing the signature originator
+extern const CFStringRef kSecAssessmentAssessmentAuthority;    // CFDictionaryRef: authority used to arrive at result
+extern const CFStringRef kSecAssessmentAssessmentSource;               // CFStringRef: primary source of authority
+extern const CFStringRef kSecAssessmentAssessmentFromCache;    // present if result is from cache
+extern const CFStringRef kSecAssessmentAssessmentAuthorityRow; // (internal)
+extern const CFStringRef kSecAssessmentAssessmentAuthorityOverride; // (internal)
+
+enum {
+       kSecAssessmentFlagRequestOrigin = 1 << 0,               // request origin information (slower)
+};
+
+SecAssessmentRef SecAssessmentCreate(CFURLRef path,
+       SecAssessmentFlags flags,
+       CFDictionaryRef context,
+       CFErrorRef *errors);
+
+
+/*!
+       @function SecAssessmentCopyResult
+
+       Extract results from a completed assessment and return them as a CFDictionary.
+
+       Assessment result keys (dictionary keys returned on success):
+
+       @param assessment A SecAssessmentRef created with SecAssessmentCreate.
+       @param flags Operation flags and options. Pass kSecAssessmentDefaultFlags for default
+               behavior.
+       @errors Standard CFError argument for reporting errors. Note that declining to permit
+               the proposed operation is not an error. Inability to form a judgment is.
+       @result On success, a CFDictionary describing the outcome and various corroborating
+               data as requested by flags. The caller owns this dictionary and should release it
+               when done with it. On error, NULL (with *errors set).
+
+       @constant kSecAssessmentAssessmentVerdict A CFBoolean value indicating whether the system policy
+               allows (kCFBooleanTrue) or denies (kCFBooleanFalse) the proposed operation.
+       @constant kSecAssessmentAssessmentAuthority A CFDictionary describing what sources of authority
+               were used to arrive at this result.
+       @constant kSecAssessmentAssessmentOriginator A human-readable CFString describing the originator
+               of the signature securing the subject of the verdict. Requires kSecAssessmentFlagRequireOrigin.
+               May be missing anyway if no reliable source of origin can be determined.
+ */
+CFDictionaryRef SecAssessmentCopyResult(SecAssessmentRef assessment,
+       SecAssessmentFlags flags,
+       CFErrorRef *errors);
+
+
+/*!
+       @function SecAssessmentUpdate
+       Make changes to the system policy configuration.
+       
+       @param path CFURL describing the file central to an operation - the program
+               to be executed, archive to be installed, plugin to be loaded, etc.
+               Pass NULL if the requested operation has no file subject.
+       @param flags Operation flags and options. Pass kSecAssessmentDefaultFlags for default
+               behavior.
+       @param context Required CFDictionaryRef containing information bearing
+               on the requested assessment. Must at least contain the kSecAssessmentContextKeyEdit key.
+       @param errors Standard CFError argument for reporting errors. Note that declining to permit
+               the proposed operation is not an error. Inability to form a judgment is.
+       @result Returns True on success. Returns False on failure (and sets *error).
+       
+       Context keys and values:
+
+       @constant kSecAssessmentContextKeyEdit Required context key describing the kind of change
+               requested to the system policy configuration. Currently understood values:
+       @constant kSecAssessmentUpdateOperationAddFile Request to add rules governing operations on the 'path'
+               argument.
+       @constant kSecAssessmentUpdateOperationRemoveFile Request to remove rules governing operations on the
+               'path' argument.
+ */
+extern const CFStringRef kSecAssessmentContextKeyUpdate;               // proposed operation
+extern const CFStringRef kSecAssessmentUpdateOperationAddFile; // add to policy database
+extern const CFStringRef kSecAssessmentUpdateOperationRemoveFile; // remove from policy database
+
+extern const CFStringRef kSecAssessmentUpdateKeyPriority;              // rule priority
+extern const CFStringRef kSecAssessmentUpdateKeyLabel;                 // rule label
+
+Boolean SecAssessmentUpdate(CFURLRef path,
+       SecAssessmentFlags flags,
+       CFDictionaryRef context,
+       CFErrorRef *errors);
+
+
+/*!
+       @function SecAssessmentControl
+       Miscellaneous system policy operations
+       
+ */
+Boolean SecAssessmentControl(CFStringRef control, void *arguments, CFErrorRef *errors);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_H_SECASSESSMENT
index d9524052a28dacd43b1cb2e5b42ce09d8460792d..fc64df445038f682626fb3c69ebbf177ee124932 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@
  * 
@@ -39,14 +39,17 @@ 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");
+const CFStringRef kSecCFErrorResourceAdded =           CFSTR("SecCSResourceAdded");
 const CFStringRef kSecCFErrorResourceAltered = CFSTR("SecCSResourceAltered");
 const CFStringRef kSecCFErrorResourceMissing = CFSTR("SecCSResourceMissing");
-const CFStringRef kSecCFErrorInfoPlist =               CFSTR("SecCSInfoPlist");
+const CFStringRef kSecCFErrorInfoPlist =                       CFSTR("SecCSInfoPlist");
 const CFStringRef kSecCFErrorGuestAttributes = CFSTR("SecCSGuestAttributes");
 const CFStringRef kSecCFErrorRequirementSyntax = CFSTR("SecRequirementSyntax");
+const CFStringRef kSecCFErrorPath =                            CFSTR("SecComponentPath");
+
 
 //
 // CF-standard type code functions
@@ -69,7 +72,7 @@ OSStatus SecCodeCopySelf(SecCSFlags flags, SecCodeRef *selfRef)
        checkFlags(flags);
        CFRef<CFMutableDictionaryRef> attributes = makeCFMutableDictionary(1,
                kSecGuestAttributePid, CFTempNumber(getpid()).get());
-       Required(selfRef) = SecCode::autoLocateGuest(attributes, flags)->handle(false);
+       CodeSigning::Required(selfRef) = SecCode::autoLocateGuest(attributes, flags)->handle(false);
        
        END_CSAPI
 }
@@ -83,7 +86,7 @@ OSStatus SecCodeGetStatus(SecCodeRef codeRef, SecCSFlags flags, SecCodeStatus *s
        BEGIN_CSAPI
        
        checkFlags(flags);
-       Required(status) = SecCode::required(codeRef)->status();
+       CodeSigning::Required(status) = SecCode::required(codeRef)->status();
        
        END_CSAPI
 }
@@ -113,7 +116,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
 }
@@ -128,7 +131,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
 }
@@ -152,11 +155,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
 }
@@ -171,7 +174,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;
        
@@ -198,7 +201,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
 }
@@ -218,6 +221,7 @@ const CFStringRef kSecCodeInfoCMS =                         CFSTR("cms");
 const CFStringRef kSecCodeInfoDesignatedRequirement = CFSTR("designated-requirement");
 const CFStringRef kSecCodeInfoEntitlements =   CFSTR("entitlements");
 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");
@@ -255,7 +259,7 @@ OSStatus SecCodeCopySigningInformation(SecStaticCodeRef codeRef, SecCSFlags flag
                        info = cfmake<CFDictionaryRef>("{+%O,%O=%u}", info.get(),
                                kSecCodeInfoStatus, dcode->status());
        
-       Required(infoRef) = info.yield();
+       CodeSigning::Required(infoRef) = info.yield();
        
        END_CSAPI
 }
index 2d9dcb1e6a8d7b1c72ef081f8318c8975d851087..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@
  * 
@@ -74,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.
@@ -106,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
@@ -132,6 +143,8 @@ OSStatus SecCodeCopyHost(SecCodeRef guest, SecCSFlags flags, SecCodeRef *host);
        may return sub-guests in this call. In other words, do not assume that
        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(s) specified.
@@ -307,6 +320,8 @@ OSStatus SecCodeCopyDesignatedRequirement(SecStaticCodeRef code, SecCSFlags flag
                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
@@ -365,6 +380,7 @@ extern const CFStringRef kSecCodeInfoCMS;                   /* 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 */
index 749b61fa30653bc0a95d78e64b1fdfc916b7a550..f6989f2990629882aa79c591bb5e2c0272df3414 100644 (file)
@@ -57,7 +57,7 @@ OSStatus SecHostCreateGuest(SecGuestRef host,
        BEGIN_CSAPI
        
        checkFlags(flags, kSecCSDedicatedHost | kSecCSGenerateGuestHash);
-       Required(newGuest) = SecurityServer::ClientSession().createGuest(host,
+       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 0f78c1aa5eac4fa6f20edf6b11fdbb502cdecbcc..54759b8250e645d9f4f58a32b1ae583eebb34c23 100644 (file)
@@ -130,7 +130,7 @@ OSStatus SecCodeCopyInternalRequirement(SecStaticCodeRef code, SecRequirementTyp
        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 an obsolescent convenience function.
+       This is a deprecated convenience function.
        Call SecCodeCopyGuestWithAttributes instead.
        
        @param pid A process id for an existing UNIX process on the system.
@@ -150,8 +150,9 @@ OSStatus SecCodeCreateWithPID(pid_t pid, SecCSFlags flags, SecCodeRef *process)
        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.
+       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.
@@ -168,6 +169,9 @@ OSStatus SecCodeCreateWithPID(pid_t pid, SecCSFlags flags, SecCodeRef *process)
                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,
index 5dca9299653ce065e967fb7725ac82d7f343357b..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");
 
 
@@ -74,7 +76,7 @@ OSStatus SecCodeSignerCreate(CFDictionaryRef parameters, SecCSFlags flags,
        checkFlags(flags, kSecCSRemoveSignature);
        SecPointer<SecCodeSigner> signer = new SecCodeSigner(flags);
        signer->parameters(parameters);
-       Required(signerRef) = signer->handle();
+       CodeSigning::Required(signerRef) = signer->handle();
 
     END_CSAPI
 }
index 2e081d199eea09761d6a60f0946c4c7f361ad1e9..184dc663bec89e09b47ce20afbce14bcd240a13e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006-2007 Apple Computer, Inc. All Rights Reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -100,6 +100,9 @@ CFTypeID SecCodeSignerGetTypeID(void);
        @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.
@@ -109,6 +112,7 @@ CFTypeID SecCodeSignerGetTypeID(void);
  */
 extern const CFStringRef kSecCodeSignerApplicationData;
 extern const CFStringRef kSecCodeSignerDetached;
+extern const CFStringRef kSecCodeSignerDigestAlgorithm;
 extern const CFStringRef kSecCodeSignerDryRun;
 extern const CFStringRef kSecCodeSignerEntitlements;
 extern const CFStringRef kSecCodeSignerFlags;
@@ -118,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;
 
 
index 903daf778ff020b0284715e7d9d5b5f3115bcf45..cee83106df7f26a773ee5e4baa5ec1ee33c606b9 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,7 +119,7 @@ OSStatus SecRequirementCreateGroup(CFStringRef groupName, SecCertificateRef anch
        } else {
                maker.anchor();                 // canonical Apple anchor
        }
-       Required(requirementRef) = (new SecRequirement(maker.make(), true))->handle();
+       CodeSigning::Required(requirementRef) = (new SecRequirement(maker.make(), true))->handle();
 
        END_CSAPI
 }
@@ -135,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
@@ -152,13 +152,38 @@ 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
 }
 
 
+//
+CFStringRef kSecRequirementKeyInfoPlist = CFSTR("requirement:eval:info");
+CFStringRef kSecRequirementKeyEntitlements = CFSTR("requirement:eval:entitlements");
+
+OSStatus SecRequirementEvaluate(SecRequirementRef requirementRef,
+       CFArrayRef certificateChain, CFDictionaryRef context,
+       SecCSFlags flags)
+{
+       BEGIN_CSAPI
+
+       const Requirement *req = SecRequirement::required(requirementRef)->requirement();
+       checkFlags(flags);
+       CodeSigning::Required(certificateChain);
+       
+       Requirement::Context ctx(certificateChain,              // mandatory
+               context ? CFDictionaryRef(CFDictionaryGetValue(context, kSecRequirementKeyInfoPlist)) : NULL,
+               context ? CFDictionaryRef(CFDictionaryGetValue(context, kSecRequirementKeyEntitlements)) : NULL,
+               NULL    // can't specify a CodeDirectory here
+       );
+       req->validate(ctx);
+       
+       END_CSAPI
+}
+
+
 //
 // Assemble a requirement set (as a CFData) from a dictionary of requirement objects.
 // An empty set is allowed.
@@ -181,7 +206,7 @@ OSStatus SecRequirementsCreateFromRequirements(CFDictionaryRef requirements, Sec
                maker.add(cfNumber<Requirements::Type>(keys[n]), req->clone());
        }
        Requirements *reqset = maker.make();                                    // malloc'ed
-       Required(requirementSet) = makeCFDataMalloc(*reqset);   // takes ownership of reqs
+       CodeSigning::Required(requirementSet) = makeCFDataMalloc(*reqset);      // takes ownership of reqs
 
        END_CSAPI
 }
@@ -206,7 +231,7 @@ OSStatus SecRequirementsCopyRequirements(CFDataRef requirementSet, SecCSFlags fl
                CFRef<SecRequirementRef> req = (new SecRequirement(reqs->blob<Requirement>(n)))->handle();
                CFDictionaryAddValue(dict, CFTempNumber(reqs->type(n)), req);
        }
-       Required(requirements) = dict.yield();
+       CodeSigning::Required(requirements) = dict.yield();
 
        END_CSAPI
 }
@@ -271,7 +296,7 @@ OSStatus SecRequirementsCopyString(CFTypeRef input, SecCSFlags flags, CFStringRe
                const Requirements *reqs = (const Requirements *)CFDataGetBytePtr(CFDataRef(input));
                if (!reqs->validateBlob(CFDataGetLength(CFDataRef(input))))
                        return errSecCSReqInvalid;
-               Required(text) = makeCFString(Dumper::dump(reqs, false));
+               CodeSigning::Required(text) = makeCFString(Dumper::dump(reqs, false));
        } else
                return errSecCSInvalidObjectRef;
 
index 249eba47a192a7055a5963e3d1e7bee7332f1801..b7e6062ee269ea089009c94bd99f8e1d222e5465 100644 (file)
@@ -158,6 +158,36 @@ OSStatus SecRequirementCreateGroup(CFStringRef groupName, SecCertificateRef anch
        SecCSFlags flags, SecRequirementRef *requirement);
 
 
+       
+/*!
+       @function SecRequirementEvaluate
+       Explicitly evaluate a SecRequirementRef against context provided in the call.
+       This allows evaluation of a code requirement outside the context of a code signature.
+
+       @param requirement A valid SecRequirement object.
+       @param certificateChain A CFArray of SecCertificate objects describing the certificate
+       chain of the object being validated. This must be a full chain terminating in an anchor
+       certificate that is cryptographically valid.
+       @param context An optional CFDictionary containing additional context made available
+       to the requirement program's evaluation. NULL is equivalent to an empty dictionary.
+       @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
+       @result Upon success, noErr. Failure to pass the check returns errSecCSReqFailed.
+       All other returns indicate errors as documented in CSCommon.h or certain other
+       Security framework headers.
+       
+       @constant kSecRequirementKeyInfoPlist A context key providing an CFDictionary denoting
+       an Info.plist. If this key is missing, all references to Info.plist contents will fail.
+       @constant kSecRequirementKeyEntitlements A context key providing an CFDictionary describing
+       an entitlement dictionary. If this key is missing, all references to entitlements will fail.
+*/
+extern CFStringRef kSecRequirementKeyInfoPlist;
+extern CFStringRef kSecRequirementKeyEntitlements;
+
+OSStatus SecRequirementEvaluate(SecRequirementRef requirement,
+       CFArrayRef certificateChain, CFDictionaryRef context,
+       SecCSFlags flags);
+
+
 #ifdef __cplusplus
 }
 #endif
index a099dfbda5b0fea684fa1e368a288edd909c2e95..3669928ecbf9364056f626be540395d5a0e1dd62 100644 (file)
@@ -26,7 +26,9 @@
 //
 #include "cs.h"
 #include "StaticCode.h"
+#include <security_utilities/cfmunge.h>
 #include <fcntl.h>
+#include <dirent.h>
 
 using namespace CodeSigning;
 
@@ -50,7 +52,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 +92,85 @@ OSStatus SecStaticCodeCreateWithPath(CFURLRef path, SecCSFlags flags, SecStaticC
 //
 // Check static validity of a StaticCode
 //
+static void validate(SecStaticCode *code, const SecRequirement *req, SecCSFlags flags);
+static void validateNested(string location, const SecRequirement *req, SecCSFlags flags, string exclude = "/");
+
+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);
+               if (flags & kSecCSCheckNestedCode)
+                       if (CFURLRef baseUrl = code->resourceBase()) {
+                               // CFBundle has no orderly enumerator of these things, so this is somewhat ad-hoc.
+                               // (It should be augmented by information in ResourceDirectory.)
+                               string base = cfString(baseUrl) + "/";
+                               validateNested(base + "Frameworks", req, flags);
+                               validateNested(base + "SharedFrameworks", req, flags);
+                               validateNested(base + "PlugIns", req, flags);
+                               validateNested(base + "Plug-ins", req, flags);
+                               validateNested(base + "XPCServices", req, flags);
+                               validateNested(base + "MacOS", req, flags, code->mainExecutablePath()); // helpers
+                       }
+       } 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;
+       }
+}
+
+static void validateNested(string location, const SecRequirement *req, SecCSFlags flags, string exclude)
+{
+       DIR *dir = opendir(location.c_str());
+       if (dir == 0) {
+               if (errno == ENOENT)    // nothing there (okay)
+                       return;
+               UnixError::throwMe();
+       }
+       while (struct dirent *dp = readdir(dir)) {
+               switch (dp->d_type) {
+               case DT_REG:
+               case DT_LNK:
+               case DT_DIR:
+                       break;
+               default:
+                       continue;
+               }
+               if (dp->d_name[0] == '.')
+                       continue;
+               string path = location + "/" + dp->d_name;
+               if (path == exclude)    // main executable; skip
+                       continue;
+               try {
+                       SecPointer<SecStaticCode> code = new SecStaticCode(DiskRep::bestGuess(path));
+                       validate(code, req, flags);
+               } catch (CSError &err) {
+                       err.augment(kSecCFErrorPath, CFTempURL(path));
+                       throw;
+               }
+       }
+       closedir(dir);
+}
+
+
 OSStatus SecStaticCodeCheckValidity(SecStaticCodeRef staticCodeRef, SecCSFlags flags,
        SecRequirementRef requirementRef)
 {
@@ -74,17 +186,18 @@ OSStatus SecStaticCodeCheckValidityWithErrors(SecStaticCodeRef staticCodeRef, Se
                  kSecCSCheckAllArchitectures
                | kSecCSDoNotValidateExecutable
                | kSecCSDoNotValidateResources
-               | kSecCSConsiderExpiration);
+               | kSecCSConsiderExpiration
+               | kSecCSCheckNestedCode);
 
        SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(staticCodeRef);
+       const SecRequirement *req = SecRequirement::optional(requirementRef);
        DTRACK(CODESIGN_EVAL_STATIC, code, (char*)code->mainExecutablePath().c_str());
-       code->validateDirectory();
-       if (!(flags & kSecCSDoNotValidateExecutable))
-               code->validateExecutable();
-       if (!(flags & kSecCSDoNotValidateResources))
-               code->validateResources();
-       if (const SecRequirement *req = SecRequirement::optional(requirementRef))
-               code->validateRequirements(req->requirement(), errSecCSReqFailed);
+       if (flags & kSecCSCheckAllArchitectures) {
+               SecStaticCode::AllArchitectures archs(code);
+               while (SecPointer<SecStaticCode> scode = archs())
+                       validate(scode, req, flags);
+       } else
+               validate(code, req, flags);
 
        END_CSAPI_ERRORS
 }
@@ -108,7 +221,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
 }
@@ -125,7 +238,7 @@ 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
 }
@@ -142,7 +255,7 @@ OSStatus SecCodeCopyInternalRequirement(SecStaticCodeRef staticCodeRef, SecRequi
        checkFlags(flags);
        const Requirement *req =
                SecStaticCode::requiredStatic(staticCodeRef)->internalRequirement(type);
-       Required(requirementRef) = req ? (new SecRequirement(req))->handle() : NULL;
+       CodeSigning::Required(requirementRef) = req ? (new SecRequirement(req))->handle() : NULL;
 
        END_CSAPI
 }
index 6aca41102f85de26440a91b909e1b34f5caa53d8..8d0f68a94793e66549f471d59a82f674f24d97ce 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" (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
@@ -62,14 +66,35 @@ CFTypeID SecStaticCodeGetTypeID(void);
        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
@@ -95,6 +120,9 @@ OSStatus SecStaticCodeCreateWithPath(CFURLRef path, SecCSFlags flags, SecStaticC
        @constant kSecCSNoNotValidateResources
        Do not validate the presence and contents of all bundle resources (if any).
        By default, a mismatch in any bundle resource causes validation to fail.
+       @constant kSecCSCheckNestedCode
+       For code in bundle form, locate and recursively check embedded code. Only code
+       in standard locations is considered.
        
        @param requirement On optional code requirement specifying additional conditions
        the staticCode object must satisfy to be considered valid. If NULL, no additional
@@ -110,7 +138,8 @@ enum {
        kSecCSCheckAllArchitectures = 1 << 0,
        kSecCSDoNotValidateExecutable = 1 << 1,
        kSecCSDoNotValidateResources = 1 << 2,
-       kSecCSBasicValidateOnly = kSecCSDoNotValidateExecutable | kSecCSDoNotValidateResources
+       kSecCSBasicValidateOnly = kSecCSDoNotValidateExecutable | kSecCSDoNotValidateResources,
+       kSecCSCheckNestedCode = 1 << 3,
 };
 
 OSStatus SecStaticCodeCheckValidity(SecStaticCodeRef staticCode, SecCSFlags flags,
diff --git a/lib/SecTask.c b/lib/SecTask.c
new file mode 100644 (file)
index 0000000..b7bb9ea
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * 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;
+       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 ca15a5f54c8a63134d6a5224a0a455f67a87fcf6..cec0b2b58d5e416ef9c2645288bb19f4b9ad1daf 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@
  * 
@@ -70,8 +70,10 @@ SecStaticCode::SecStaticCode(DiskRep *rep)
 // Clean up a SecStaticCode object
 //
 SecStaticCode::~SecStaticCode() throw()
-{
+try {
        ::free(const_cast<Requirement *>(mDesignatedReq));
+} catch (...) {
+       return;
 }
 
 
@@ -209,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);
        
@@ -219,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
                }
        }
@@ -300,7 +302,7 @@ void SecStaticCode::validateDirectory()
                        // perform validation (or die trying)
                        CODESIGN_EVAL_STATIC_DIRECTORY(this);
                        mValidationExpired = verifySignature();
-                       component(cdInfoSlot);          // force load of Info Dictionary (if any)
+                       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
@@ -429,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)) {
+                               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;
+                                       actionData.ActionFlags |= CSSM_TP_ACTION_ALLOW_EXPIRED; // (this also allows postdated certs)
                                        continue;               // retry validation
                                }
                                MacOSError::throwMe(result);
@@ -460,17 +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);
        }
 }
 
@@ -543,7 +546,7 @@ void SecStaticCode::validateResources()
 
        // 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;
@@ -583,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;
@@ -610,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());
@@ -642,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
@@ -681,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
@@ -717,9 +720,9 @@ void SecStaticCode::validateResource(string path, ValidationContext &ctx)
                        CFRef<CFURLRef> fullpath = makeCFURL(path, false, resourceBase());
                        AutoFileDesc fd(cfString(fullpath), O_RDONLY, FileDesc::modeMissingOk); // open optional filee
                        if (fd) {
-                               SHA1 hasher;
-                               hashFileData(fd, hasher);
-                               if (hasher.verify(seal.hash()))
+                               MakeHash<CodeDirectory> hasher(this->codeDirectory());
+                               hashFileData(fd, hasher.get());
+                               if (hasher->verify(seal.hash()))
                                        return;                 // verify good
                                else
                                        ctx.reportProblem(errSecCSBadResource, kSecCFErrorResourceAltered, fullpath); // altered
@@ -832,9 +835,14 @@ const Requirement *SecStaticCode::defaultDesignatedRequirement()
        return maker();
 }
 
-static const uint8_t adcSdkMarker[] = { APPLE_EXTENSION_OID, 2, 1 };
+static const uint8_t adcSdkMarker[] = { APPLE_EXTENSION_OID, 2, 1 };           // iOS intermediate marker
 static const CSSM_DATA adcSdkMarkerOID = { sizeof(adcSdkMarker), (uint8_t *)adcSdkMarker };
 
+static const uint8_t caspianSdkMarker[] = { APPLE_EXTENSION_OID, 2, 6 }; // Caspian intermediate marker
+static const CSSM_DATA caspianSdkMarkerOID = { sizeof(caspianSdkMarker), (uint8_t *)caspianSdkMarker };
+static const uint8_t caspianLeafMarker[] = { APPLE_EXTENSION_OID, 1, 13 }; // Caspian leaf certificate marker
+static const CSSM_DATA caspianLeafMarkerOID = { sizeof(caspianLeafMarker), (uint8_t *)caspianLeafMarker };
+
 void SecStaticCode::defaultDesignatedAppleAnchor(Requirement::Maker &maker)
 {
        if (isAppleSDKSignature()) {
@@ -860,8 +868,41 @@ void SecStaticCode::defaultDesignatedAppleAnchor(Requirement::Maker &maker)
                maker.put(matchExists);                 // exists
                return;
        }
+       
+       if (isAppleCaspianSignature()) {
+               // get the Organizational Unit DN element for the leaf (it contains the TEAMID)
+               CFRef<CFStringRef> teamID;
+               MacOSError::check(SecCertificateCopySubjectComponent(cert(Requirement::leafCert),
+                       &CSSMOID_OrganizationalUnitName, &teamID.aref()));
 
-       // otherwise, claim this program for Apple
+               // apple anchor generic and ...
+               maker.put(opAnd);
+               maker.anchorGeneric();                  // apple generic anchor and...
+               
+               // ... certificate 1[intermediate marker oid] exists and ...
+               maker.put(opAnd);
+               maker.put(opCertGeneric);               // certificate
+               maker.put(1);                                   // 1
+               maker.putData(caspianSdkMarker, sizeof(caspianSdkMarker));
+               maker.put(matchExists);                 // exists
+               
+               // ... certificate leaf[Caspian cert oid] exists and ...
+               maker.put(opAnd);
+               maker.put(opCertGeneric);               // certificate
+               maker.put(0);                                   // leaf
+               maker.putData(caspianLeafMarker, sizeof(caspianLeafMarker));
+               maker.put(matchExists);                 // exists
+
+               // ... leaf[subject.OU] = <leaf's subject>
+               maker.put(opCertField);                 // certificate
+               maker.put(0);                                   // leaf
+               maker.put("subject.OU");                // [subject.OU]
+               maker.put(matchEqual);                  // =
+               maker.putData(teamID);                  // TEAMID
+               return;
+       }
+
+       // otherwise, claim this program for Apple Proper
        maker.anchor();
 }
 
@@ -875,6 +916,16 @@ bool SecStaticCode::isAppleSDKSignature()
        return false;
 }
 
+bool SecStaticCode::isAppleCaspianSignature()
+{
+       if (CFArrayRef certChain = certificates())              // got cert chain
+               if (CFArrayGetCount(certChain) == 3)            // leaf, one intermediate, anchor
+                       if (SecCertificateRef intermediate = cert(1)) // get intermediate
+                               if (certificateHasField(intermediate, CssmOid::overlay(caspianSdkMarkerOID)))
+                                       return true;
+       return false;
+}
+
 void SecStaticCode::defaultDesignatedNonAppleAnchor(Requirement::Maker &maker)
 {
        // get the Organization DN element for the leaf
@@ -911,7 +962,7 @@ void SecStaticCode::validateRequirements(SecRequirementType type, SecStaticCode
 {
        DTRACK(CODESIGN_EVAL_STATIC_INTREQ, this, type, target, nullError);
        if (const Requirement *req = internalRequirement(type))
-               target->validateRequirements(req, nullError ? nullError : errSecCSReqFailed);
+               target->validateRequirement(req, nullError ? nullError : errSecCSReqFailed);
        else if (nullError)
                MacOSError::throwMe(nullError);
        else
@@ -922,11 +973,17 @@ void SecStaticCode::validateRequirements(SecRequirementType type, SecStaticCode
 //
 // 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);
 }
 
 
@@ -989,6 +1046,7 @@ CFDictionaryRef SecStaticCode::signingInformation(SecCSFlags flags)
        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
@@ -1095,5 +1153,57 @@ void SecStaticCode::CollectingContext::throwMe()
 }
 
 
+//
+// 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.
+//
+SecStaticCode::AllArchitectures::AllArchitectures(SecStaticCode *code)
+       : mBase(code)
+{
+       if (Universal *fat = code->diskRep()->mainExecutableImage()) {
+               fat->architectures(mArchitectures);
+               mCurrent = mArchitectures.begin();
+               mState = fatBinary;
+       } else {
+               mState = firstNonFat;
+       }
+}
+
+SecStaticCode *SecStaticCode::AllArchitectures::operator () ()
+{
+       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;
+       }
+}
+
+
 } // end namespace CodeSigning
 } // end namespace Security
index de6417dfc8b8e4ef2c045ff79e35ae28b088e990..da616c82b797b6daf0e7d1c69e43c8b2ca65c75a 100644 (file)
@@ -49,7 +49,14 @@ 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)
@@ -111,7 +118,7 @@ public:
        std::string identifier() { return codeDirectory()->identifier(); }
        std::string format() const { return mRep->format(); }
        std::string signatureSource();
-       CFDataRef component(CodeDirectory::SpecialSlot slot);
+       CFDataRef component(CodeDirectory::SpecialSlot slot, OSStatus fail = errSecCSSignatureFailed);
        CFDictionaryRef infoDictionary();
        CFDictionaryRef entitlements();
 
@@ -119,18 +126,18 @@ public:
        CFURLRef resourceBase();
        CFDataRef resource(std::string path);
        CFDataRef resource(std::string path, ValidationContext &ctx);
-       void validateResource(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();
        
@@ -140,22 +147,28 @@ public:
        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();
 
        void defaultDesignatedAppleAnchor(Requirement::Maker &maker);
        void defaultDesignatedNonAppleAnchor(Requirement::Maker &maker);
        bool isAppleSDKSignature();
+       bool isAppleCaspianSignature();
 
        static void checkOptionalResource(CFTypeRef key, CFTypeRef value, void *context);
 
@@ -197,6 +210,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 d8785d1335811c693488f51f968354a97b79db9e..757bbbc25d32237ec4a4f1bc72b425ef6776d173 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2006-2011 Apple Inc. All Rights Reserved.
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -21,6 +21,7 @@
  * @APPLE_LICENSE_HEADER_END@
  */
 #include "bundlediskrep.h"
+#include "filediskrep.h"
 #include <CoreFoundation/CFURLAccess.h>
 #include <CoreFoundation/CFBundlePriv.h>
 #include <security_utilities/cfmunge.h>
@@ -37,21 +38,80 @@ using namespace UnixPlusPlus;
 // We make a CFBundleRef immediately, but everything else is lazy
 //
 BundleDiskRep::BundleDiskRep(const char *path, const Context *ctx)
-       : mBundle(_CFBundleCreateIfMightBeBundle(NULL, CFTempURL(path)))
+       : mBundle(CFBundleCreate(NULL, CFTempURL(path)))
 {
        if (!mBundle)
-               MacOSError::throwMe(errSecCSBadObjectFormat);
-       mExecRep = DiskRep::bestFileGuess(this->mainExecutablePath(), ctx);
+               MacOSError::throwMe(errSecCSBadBundleFormat);
+       setup(ctx);
        CODESIGN_DISKREP_CREATE_BUNDLE_PATH(this, (char*)path, (void*)ctx, mExecRep);
 }
 
 BundleDiskRep::BundleDiskRep(CFBundleRef ref, const Context *ctx)
 {
        mBundle = ref;          // retains
-       mExecRep = DiskRep::bestFileGuess(this->mainExecutablePath(), ctx);
+       setup(ctx);
        CODESIGN_DISKREP_CREATE_BUNDLE_REF(this, ref, (void*)ctx, mExecRep);
 }
 
+// common construction code
+void BundleDiskRep::setup(const Context *ctx)
+{
+       // deal with versioned bundles (aka Frameworks)
+       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);
+       }
+       
+       // conventional executable bundle: CFBundle identifies an executable for us
+       if (mMainExecutableURL.take(CFBundleCopyExecutableURL(mBundle))) {
+               // conventional executable bundle
+               mExecRep = DiskRep::bestFileGuess(this->mainExecutablePath(), ctx);
+               mFormat = string("bundle with ") + mExecRep->format();
+               return;
+       }
+       
+       CFDictionaryRef infoDict = CFBundleGetInfoDictionary(mBundle);
+       assert(infoDict);       // CFBundle will always make one up for us
+       
+       if (CFTypeRef main = CFDictionaryGetValue(infoDict, CFSTR("MainHTML"))) {
+               // widget
+               if (CFGetTypeID(main) != CFStringGetTypeID())
+                       MacOSError::throwMe(errSecCSBadBundleFormat);
+               mMainExecutableURL = makeCFURL(cfString(CFStringRef(main)), false, CFRef<CFURLRef>(CFBundleCopySupportFilesDirectoryURL(mBundle)));
+               if (!mMainExecutableURL)
+                       MacOSError::throwMe(errSecCSBadBundleFormat);
+               mExecRep = new FileDiskRep(this->mainExecutablePath().c_str());
+               mFormat = "widget bundle";
+               return;
+       }
+       
+       // generic bundle case - impose our own "minimal signable bundle" standard
+
+       // we MUST have an actual Info.plist in here
+       CFRef<CFURLRef> infoURL = _CFBundleCopyInfoPlistURL(mBundle);
+       if (!infoURL)
+               MacOSError::throwMe(errSecCSBadBundleFormat);
+
+       // focus on the Info.plist (which we know exists) as the nominal "main executable" file
+       if ((mMainExecutableURL = _CFBundleCopyInfoPlistURL(mBundle))) {
+               mExecRep = new FileDiskRep(this->mainExecutablePath().c_str());
+               mFormat = "bundle";
+               return;
+       }
+       
+       // this bundle cannot be signed
+       MacOSError::throwMe(errSecCSBadBundleFormat);
+}
+
 
 //
 // Create a path to a bundle signing resource, by name.
@@ -141,31 +201,9 @@ CFURLRef BundleDiskRep::canonicalPath()
        return CFBundleCopyBundleURL(mBundle);
 }
 
-string BundleDiskRep::recommendedIdentifier()
-{
-       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);
-}
-
 string BundleDiskRep::mainExecutablePath()
 {
-       if (CFURLRef exec = CFBundleCopyExecutableURL(mBundle))
-               return cfString(exec, true);
-       else
-               MacOSError::throwMe(errSecCSBadObjectFormat);
+       return cfString(mMainExecutableURL);
 }
 
 string BundleDiskRep::resourcesRootPath()
@@ -173,20 +211,13 @@ 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
        builder.addExclusion("^" BUNDLEDISKREP_DIRECTORY "/");
+
+       // exclude the store manifest directory
+       builder.addExclusion("^" STORE_RECEIPT_DIRECTORY "/");
        
        // exclude the main executable file
        string resources = resourcesRootPath();
@@ -197,22 +228,12 @@ void BundleDiskRep::adjustResources(ResourceBuilder &builder)
 }
 
 
-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();
@@ -225,7 +246,7 @@ size_t BundleDiskRep::signingLimit()
 
 string BundleDiskRep::format()
 {
-       return string("bundle with ") + mExecRep->format();
+       return mFormat;
 }
 
 CFArrayRef BundleDiskRep::modifiedFiles()
@@ -260,6 +281,58 @@ 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 &)
+{
+       // consider the bundle's structure
+       string rbase = this->resourcesRootPath();
+       if (rbase.substr(rbase.length()-2, 2) == "/.")  // produced by versioned bundle implicit "Current" case
+               rbase = rbase.substr(0, rbase.length()-2);      // ... so take it off for this
+       string resources = cfString(CFBundleCopyResourcesDirectoryURL(mBundle), true);
+       if (resources == rbase)
+               resources = "";
+       else if (resources.compare(0, rbase.length(), rbase, 0, rbase.length()) != 0)   // Resources not in resource root
+               MacOSError::throwMe(errSecCSBadBundleFormat);
+       else
+               resources = resources.substr(rbase.length() + 1) + "/"; // differential path segment
+       
+       return cfmake<CFDictionaryRef>("{rules={"
+               "'^version.plist$' = #T"
+               "%s = #T"
+               "%s = {optional=#T, weight=1000}"
+               "%s = {omit=#T, weight=1100}"
+               "}}",
+               (string("^") + resources).c_str(),
+               (string("^") + resources + ".*\\.lproj/").c_str(),
+               (string("^") + resources + ".*\\.lproj/locversion.plist$").c_str()
+       );
+}
+
+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
 //
@@ -294,16 +367,8 @@ 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;
-# if FORCE_REPLACE_SYMLINK             /* replace any existing file with legacy symlink */
-                               ::unlink(legacy.c_str());               // force-replace
-#endif
-                               ::symlink((string(BUNDLEDISKREP_DIRECTORY "/") + name).c_str(), legacy.c_str());
-                       }
                } else
-                       MacOSError::throwMe(errSecCSBadObjectFormat);
+                       MacOSError::throwMe(errSecCSBadBundleFormat);
        }
 }
 
index b4e201ef3afeaafdac8c4b0f0aafe788c4d58994..e96199326a51aac9c03867c57398a8a75809cad3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2006-2011 Apple Inc. All Rights Reserved.
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -35,6 +35,7 @@ namespace CodeSigning {
 
 
 #define BUNDLEDISKREP_DIRECTORY                "_CodeSignature"
+#define STORE_RECEIPT_DIRECTORY                "_MASReceipt"
 
 
 //
@@ -42,7 +43,7 @@ namespace CodeSigning {
 // The bundle is expected to have an Info.plist, and a "main executable file"
 // of some sort (as indicated therein).
 // The BundleDiskRep stores the necessary components in the main executable
-// if it is in Mach-O format, or in Contents files if not.
+// if it is in Mach-O format, or in files in a _CodeSignature directory if not.
 // This DiskRep supports resource sealing.
 //
 class BundleDiskRep : public DiskRep {
@@ -54,19 +55,20 @@ public:
        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; }
        
@@ -81,12 +83,15 @@ 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:
        CFRef<CFBundleRef> mBundle;
        std::string mMetaPath;                                  // path to directory containing signing files
        bool mMetaExists;                                               // separate meta-file directory exists
+       CFRef<CFURLRef> mMainExecutableURL;     // chosen main executable URL
+       string mFormat;                                                 // format description string
        RefPointer<DiskRep> mExecRep;                   // DiskRep for main executable file
 };
 
index 6d63525d7decdc5536cd36444cc6564a5250ef28..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,14 +39,22 @@ namespace CodeSigning {
 //
 // Create an (empty) builder
 //
-CodeDirectory::Builder::Builder()
-       : mFlags(0), mSpecialSlots(0), mCodeSlots(0), mScatter(NULL), mScatterSize(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);
 }
 
@@ -77,12 +85,12 @@ 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;
 }
@@ -120,7 +128,7 @@ 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;
 }
 
@@ -155,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
@@ -181,21 +189,22 @@ CodeDirectory *CodeDirectory::Builder::build()
 
        // (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 f12d387bfc2a78485415e700a4bc1c4c1feab0a3..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,20 +36,20 @@ 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; }
        
@@ -58,14 +58,24 @@ public:
        
        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
index 49edf08d012079e802a83d935226af512dc9fdd4..41607e12a425b67ee3d0d47c94542ba5a8a21da4 100644 (file)
@@ -88,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.
@@ -148,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.
 //
index 23d3a8ad0a2b51ad2ec9cbcd6cb92b3e01043247..3ea17ab8488ba25e85e55e6a6eb938f9da09c9c9 100644 (file)
@@ -55,12 +55,13 @@ public:
        ~CFMDiskRep();
        
        CFDataRef component(CodeDirectory::SpecialSlot slot);
-       const Requirements *defaultRequirements(const Architecture *arch);
-       size_t pageSize();
        size_t signingLimit();
        std::string format();
        void flush();
        
+       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:
index 9423f8eff421792aefd47d5688536ae82595a1b5..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@
  * 
@@ -156,9 +156,10 @@ void CodeDirectory::checkIntegrity() 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;
 }
 
 
@@ -168,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;
 }
 
 
@@ -182,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
        }
@@ -191,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.
@@ -198,11 +221,10 @@ 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)
 {
-       SHA1 hasher;
        size_t size = hashFileData(fd, hasher, limit);
-       hasher.finish(digest);
+       hasher->finish(digest);
        return size;
 }
 
@@ -210,11 +232,10 @@ size_t CodeDirectory::hash(FileDesc fd, Hash::Byte *digest, size_t limit)
 //
 // 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;
 }
 
index 0f99dd116c2b5a687b9138716fefe5a63f0a703f..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,8 +70,8 @@ enum {
 // indices. This enumeration is also used widely in various internal APIs, and as
 // type values in embedded SuperBlobs.
 //
-// How to add a slot code:
-//     1. Add the new name into the primary or virtual slot array at the end (below).
+// 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.
@@ -85,7 +83,7 @@ enum {
        // 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
@@ -99,12 +97,12 @@ enum {
        
        //
        // Virtual slot numbers.
-       // These values are NOT used in the CodeDirectory hash array. The are used as
+       // 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
@@ -130,12 +128,14 @@ 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. Two constants control
@@ -143,7 +143,8 @@ enum {
 //     * 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 checkValidity().
+// 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
@@ -164,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
@@ -174,12 +174,12 @@ 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
+       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 = 0x20100;         // "version 2.1"
@@ -190,12 +190,14 @@ public:
        
        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));
@@ -208,11 +210,19 @@ public:
                return at<unsigned char>(hashOffset) + hashSize * slot;
        }
        
+       //
+       // 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;  // offset in target
-               Endian<uint64_t> spare;                 // reserved
+               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; }
@@ -220,19 +230,25 @@ public:
                { return (version >= supportsScatter && scatterOffset) ? at<const Scatter>(scatterOffset) : NULL; }
        
 public:
-       bool validateSlot(const void *data, size_t size, Slot slot) const;
-       bool validateSlot(UnixPlusPlus::FileDesc fd, size_t size, Slot slot) const;
+       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);
index 8a6e244ba82b6abfbbc24a6a827d1111aa5bc457..1cd9306b5a81007b906081d8945bc5b2308ea0dc 100644 (file)
--- a/lib/cs.h
+++ b/lib/cs.h
@@ -114,10 +114,26 @@ OSStatus dbError(const SQLite3::Error &err);
        return noErr;
        
 #define END_CSAPI1(bad)    } catch (...) { return bad; }
+
        
+#define END_CSAPI_ERRORS1(bad) \
+       } \
+       catch (const CSError &err) { err.cfError(errors); } \
+       catch (const UnixError &err) { \
+               switch (err.error) { \
+               case ENOEXEC: CSError::cfError(errors, errSecCSBadObjectFormat); \
+               default: CSError::cfError(errors, err.osStatus()); \
+               }} \
+    catch (const MacOSError &err) { CSError::cfError(errors, err.osStatus()); } \
+    catch (const SQLite3::Error &err) { CSError::cfError(errors, dbError(err)); } \
+    catch (const CommonError &err) { CSError::cfError(errors, SecKeychainErrFromOSStatus(err.osStatus())); } \
+    catch (const std::bad_alloc &) { CSError::cfError(errors, memFullErr); } \
+    catch (...) { CSError::cfError(errors, errSecCSInternalError); } \
+       return bad;
+
 
 //
-// A version of Required
+// A version of CodeSigning::Required
 //
 template <class T>
 static inline T &Required(T *ptr)
index 76912ced78be0186c76063e9500cd569d3e3339a..5772ee6e30adfbef0340cafc04b9b935f179cfe2 100644 (file)
@@ -38,6 +38,7 @@ using namespace SQLite;
 // It auto-adapts to readonly vs. writable use.
 //
 ModuleNexus<SignatureDatabase> signatureDatabase;
+ModuleNexus<SignatureDatabaseWriter> signatureDatabaseWriter;
 
 
 //
@@ -112,7 +113,7 @@ FilterRep *SignatureDatabase::findCode(DiskRep *rep)
 // This writes exactly one Global record, plus one Code record per architecture
 // (where non-architectural code is treated as single-architecture).
 //
-void SignatureDatabase::storeCode(const BlobCore *sig, const char *location)
+void SignatureDatabaseWriter::storeCode(const BlobCore *sig, const char *location)
 {
        Transaction xa(*this, Transaction::exclusive);  // lock out everyone
        if (this->empty())
@@ -136,7 +137,7 @@ void SignatureDatabase::storeCode(const BlobCore *sig, const char *location)
 
 }
 
-int64 SignatureDatabase::insertGlobal(const char *location, const BlobCore *blob)
+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;
@@ -146,7 +147,7 @@ int64 SignatureDatabase::insertGlobal(const char *location, const BlobCore *blob
        return lastInsert();
 }
 
-void SignatureDatabase::insertCode(int64 globid, int arch, const EmbeddedSignatureBlob *sig)
+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));
index 94ff92020faefd4ba8a8ea851689b8e06ff033a1..95f8e1b104ee468d2616824cfd68317e8552a5dc 100644 (file)
@@ -44,22 +44,32 @@ namespace SQLite = SQLite3;
 class SignatureDatabase : public SQLite::Database {
 public:
        SignatureDatabase(const char *path = defaultPath,
-               int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
+               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);
-
-public:
-       static const char defaultPath[];
 };
 
 
 extern ModuleNexus<SignatureDatabase> signatureDatabase;
+extern ModuleNexus<SignatureDatabaseWriter> signatureDatabaseWriter;
 
 
 } // end namespace CodeSigning
index 940c8d0a1b1637167e453e25f46adc59fdf488b9..1673205685855f2f094a36d8a424ae78b14a446b 100644 (file)
@@ -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 7ff1a98e59a129d4083a70ee1c45eb35fc0bfd8c..c67d9467bddb6c97e42b5a3f8e3b93651d79cb37 100644 (file)
@@ -160,7 +160,7 @@ SecCodeStatus GenericCode::getGuestStatus(SecCode *guest)
 //
 void GenericCode::changeGuestStatus(SecCode *iguest, SecCodeStatusOperation operation, CFDictionaryRef arguments)
 {
-       if (GenericCode *guest = dynamic_cast<GenericCode *>(iguest))
+       if (/* GenericCode *guest = */dynamic_cast<GenericCode *>(iguest))
                switch (operation) {
                case kSecCodeOperationNull:
                        break;
@@ -170,7 +170,7 @@ void GenericCode::changeGuestStatus(SecCode *iguest, SecCodeStatusOperation oper
                        MacOSError::throwMe(errSecCSUnimplemented);
                        break;
                default:
-                       MacOSError::throwMe(errSecCSInvalidOperation);
+                       MacOSError::throwMe(errSecCSUnimplemented);
                }
        else
                MacOSError::throwMe(errSecCSNoSuchCode);
index ebdd6ee8f0fd9ed830da1debf386890eea6e34fd..9821465db9645e6482c38e0ce331cc31ee0001ad 100644 (file)
@@ -157,7 +157,7 @@ void KernelCode::changeGuestStatus(SecCode *iguest, SecCodeStatusOperation opera
                        csops(guest, CS_OPS_MARKKILL);
                        break;
                default:
-                       MacOSError::throwMe(errSecCSInvalidOperation);
+                       MacOSError::throwMe(errSecCSUnimplemented);
                }
        else
                MacOSError::throwMe(errSecCSNoSuchCode);
index b33266d738e69ee23310bf17e216918b737a2425..ed5a0a88ca4541f9763dfb03d4393edf03c24a8b 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@
  * 
@@ -57,38 +57,6 @@ 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.
-//
-size_t hashFileData(const char *path, SHA1 &hasher)
-{
-       UnixPlusPlus::AutoFileDesc fd(path);
-       return hashFileData(fd, hasher);
-}
-
-size_t hashFileData(UnixPlusPlus::FileDesc fd, SHA1 &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(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.
@@ -101,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
@@ -123,6 +91,35 @@ 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;
+}
 
 
 //
@@ -156,5 +153,36 @@ void Copyfile::check(int rc)
 }
 
 
+//
+// MessageTracer support
+//
+MessageTrace::MessageTrace(const char *domain, const char *signature)
+{
+       mAsl = asl_new(ASL_TYPE_MSG);
+       if (domain)
+               asl_set(mAsl, "com.apple.message.domain", domain);
+       if (signature)
+               asl_set(mAsl, "com.apple.message.signature", signature);
+}
+
+void MessageTrace::add(const char *key, const char *format, ...)
+{
+       va_list args;
+       va_start(args, format);
+       char value[200];
+       vsnprintf(value, sizeof(value), format, args);
+       va_end(args);
+       asl_set(mAsl, (string("com.apple.message.") + key).c_str(), value);
+}
+       
+void MessageTrace::send(const char *format, ...)
+{
+       va_list args;
+       va_start(args, format);
+       asl_vlog(NULL, mAsl, ASL_LEVEL_NOTICE, format, args);
+       va_end(args);
+}
+
+
 } // end namespace CodeSigning
 } // end namespace Security
index 3aade71e39cb672d11314c03583c1282706a1a8a..456511316899038b8363e9b02ea1e8cd996f3e2f 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@
  * 
@@ -35,6 +35,8 @@
 #include <security_utilities/unix++.h>
 #include <security_cdsa_utilities/cssmdata.h>
 #include <copyfile.h>
+#include <asl.h>
+#include <cstdarg>
 
 namespace Security {
 namespace CodeSigning {
@@ -54,8 +56,32 @@ void hashOfCertificate(SecCertificateRef cert, SHA1::Digest digest);
 // Extends to end of file, or (if limit > 0) at most limit bytes.
 // Returns number of bytes digested.
 //
-size_t hashFileData(const char *path, SHA1 &hasher);
-size_t hashFileData(UnixPlusPlus::FileDesc fd, SHA1 &hasher, size_t limit = 0);
+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;
+}
 
 
 //
@@ -63,6 +89,7 @@ size_t hashFileData(UnixPlusPlus::FileDesc fd, SHA1 &hasher, size_t limit = 0);
 // 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);
 
 
 //
@@ -89,6 +116,20 @@ private:
 };
 
 
+//
+// MessageTracer support
+//
+class MessageTrace {
+public:
+       MessageTrace(const char *domain, const char *signature);
+       void add(const char *key, const char *format, ...);
+       void send(const char *format, ...);
+
+private:
+       aslmsg mAsl;
+};
+
+
 //
 // A reliable uid set/reset bracket
 //
index 8db305c24dee29b905ee8b5340231390960205a4..395402c65f8650f3ac5fa9427e880ac24af3f25d 100644 (file)
@@ -68,7 +68,7 @@ DiskRep *DiskRep::base()
 //
 DiskRep::Writer *DiskRep::writer()
 {
-       MacOSError::throwMe(errSecCSBadObjectFormat);
+       MacOSError::throwMe(errSecCSUnimplemented);
 }
 
 
@@ -177,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)
@@ -220,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
 //
index b7746ae8f5098d8f6164a4a3401e29fac8777774..5d9c2d302769b2f535e2fe5da4f10d09e1c2baa3 100644 (file)
@@ -48,6 +48,9 @@ namespace CodeSigning {
 // the details of the storage locations or formats.
 //
 class DiskRep : public RefCount {
+public:
+       class SigningContext;
+       
 public:
        DiskRep();
        virtual ~DiskRep();
@@ -56,19 +59,22 @@ public:
        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; }
        
@@ -78,24 +84,43 @@ public:
 
 public:
        class Writer;
-       virtual Writer *writer();
+       virtual Writer *writer();                                                               // Writer factory
 
 public:
+       // optional information that might be used to create a suitable DiskRep. All optional
        struct Context {
-               Context() : arch(Architecture::none), offset(0), fileOnly(false) { }
-               Architecture arch;                      // explicit architecture
+               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
+               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
@@ -110,6 +135,15 @@ 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);
@@ -159,15 +193,18 @@ public:
        CFDataRef identification()                              { return mOriginal->identification(); }
        std::string mainExecutablePath()                { return mOriginal->mainExecutablePath(); }
        CFURLRef canonicalPath()                                { return mOriginal->canonicalPath(); }
-       std::string recommendedIdentifier()             { return mOriginal->recommendedIdentifier(); }
        std::string resourcesRootPath()                 { return mOriginal->resourcesRootPath(); }
-       CFDictionaryRef defaultResourceRules()  { return mOriginal->defaultResourceRules(); }
        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
index dbb8820c8f19ee894d49b53577a89ba1b032b2ef..7a098c22a4577c5409923df269096732bff590d5 100644 (file)
@@ -98,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];
@@ -108,15 +108,17 @@ 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());
index 70f4281eabf3bf07cb50127bbf8f970b0c137d27..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;
index 9557abd952a062b51a1c6c3351de45dc895c7fda..f39cc511f0bf4dc6703a1dc5a4fa93877a63ae98 100644 (file)
@@ -21,6 +21,7 @@
  * @APPLE_LICENSE_HEADER_END@
  */
 #include "kerneldiskrep.h"
+#include <sys/utsname.h>
 
 namespace Security {
 namespace CodeSigning {
@@ -58,9 +59,11 @@ 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 050dd4f3e12fe1b99fa0b0ad1c75fc3b5ea8e222..997462f657051789fadca6062f61af218a5a06ee 100644 (file)
@@ -50,10 +50,11 @@ public:
        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);
 };
 
 
index 1aaa608c4c72549e5f0b05a5340d70489745c723..8753ca609bfa2cc9db04201b0b3de66ea6598d28 100644 (file)
@@ -86,92 +86,16 @@ bool MachORep::candidate(FileDesc &fd)
 }
 
 
-//
-// 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)
-{
-       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))
-               maker.add(kSecLibraryRequirementType, libreq);  // takes ownership
-
-       // that's all
-       return maker.make();
-}
-
-Requirement *MachORep::libraryRequirements(const Architecture *arch)
-{
-       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 {
-                                               secdebug("machorep", "examining DYLIB %s", name);
-                                               // find path on disk, get designated requirement (if signed)
-                                               if (RefPointer<DiskRep> rep = DiskRep::bestFileGuess(name))
-                                                       if (SecPointer<SecStaticCode> code = new SecStaticCode(rep))
-                                                               if (const Requirement *req = code->designatedRequirement()) {
-                                                                       secdebug("machorep", "adding library requirement for %s", name);
-                                                                       chain.add();
-                                                                       chain.maker.copy(req);
-                                                               }
-                                       } catch (...) {
-                                               secdebug("machorep", "exception getting library requirement (ignored)");
-                                       }
-                               else
-                                       secdebug("machorep", "no string for DYLIB command (ignored)");
-                       }
-               }
-       }
-       if (chain.empty())
-               return NULL;
-       else
-               return maker.make();
-}
-
-
 
 //
-// 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
-//
-size_t MachORep::pageSize()
-{
-       return segmentedPageSize;
-}
-
-
 //
 // Signing base is the start of the Mach-O architecture we're using
 //
@@ -291,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
 //
@@ -350,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;
 }
 
 
index 69542d23f61d2b8ea7c9e037f0a28d63dd04c590..2486139533924d034e005e8839ffaf4a0a0b21c6 100644 (file)
@@ -37,8 +37,8 @@ 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
@@ -52,13 +52,14 @@ public:
        
        CFDataRef component(CodeDirectory::SpecialSlot slot);
        CFDataRef identification();
-       std::string recommendedIdentifier();
-       const Requirements *defaultRequirements(const Architecture *arch);
        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 candidate(UnixPlusPlus::FileDesc &fd);
@@ -74,7 +75,7 @@ public:
 protected:
        CFDataRef embeddedComponent(CodeDirectory::SpecialSlot slot);
        CFDataRef infoPlist();
-       Requirement *libraryRequirements(const Architecture *arch);
+       Requirement *libraryRequirements(const Architecture *arch, const SigningContext &ctx);
 
 private:
        Universal *mExecutable; // cached Mach-O/Universal reference to mainExecutablePath()
@@ -83,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;
diff --git a/lib/policydb.cpp b/lib/policydb.cpp
new file mode 100644 (file)
index 0000000..72018c3
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2011 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 "cs.h"
+#include "policydb.h"
+#include "policyengine.h"
+#include <Security/CodeSigning.h>
+#include <security_utilities/cfutilities.h>
+#include <security_utilities/cfmunge.h>
+
+namespace Security {
+namespace CodeSigning {
+
+
+using namespace SQLite;
+
+
+//
+// The one and only PolicyDatabase object.
+// It auto-adapts to readonly vs. writable use.
+//
+ModuleNexus<PolicyDatabase> PolicyDatabase;
+
+
+//
+// Determine the database path
+//
+static const char *dbPath()
+{
+       if (const char *s = getenv("SYSPOLICYDATABASE"))
+               return s;
+       return defaultDatabase;
+}
+
+
+//
+// Open the database (creating it if necessary and possible).
+// Note that this isn't creating the schema; we do that on first write.
+//
+PolicyDatabase::PolicyDatabase(const char *path, int flags)
+       : SQLite::Database(path ? path : dbPath(), flags)
+{
+}
+
+PolicyDatabase::~PolicyDatabase()
+{ /* virtual */ }
+
+
+//
+// Quick-check the cache for a match.
+// Return true on a cache hit, false on failure to confirm a hit for any reason.
+//
+bool PolicyDatabase::checkCache(CFURLRef path, AuthorityType type, CFMutableDictionaryRef result)
+{
+       // we currently don't use the cache for anything but execution rules
+       if (type != kAuthorityExecute)
+               return false;
+       
+       SecCSFlags validationFlags = kSecCSDefaultFlags;
+       if (overrideAssessment())       // we'll force the verdict to 'pass' at the end, so don't sweat validating code
+               validationFlags = kSecCSBasicValidateOnly;
+
+       CFRef<SecStaticCodeRef> code;
+       MacOSError::check(SecStaticCodeCreateWithPath(path, kSecCSDefaultFlags, &code.aref()));
+       if (SecStaticCodeCheckValidity(code, validationFlags, NULL) != noErr)
+               return false;   // quick pass - any error is a cache miss
+       CFRef<CFDictionaryRef> info;
+       MacOSError::check(SecCodeCopySigningInformation(code, kSecCSDefaultFlags, &info.aref()));
+       CFDataRef cdHash = CFDataRef(CFDictionaryGetValue(info, kSecCodeInfoUnique));
+       
+       // check the cache table for a fast match
+       SQLite::Statement cached(*this, "SELECT allow, expires, label, authority FROM object WHERE type = ?1 and hash = ?2;");
+       cached.bind(1).integer(type);
+       cached.bind(2) = cdHash;
+       if (cached.nextRow()) {
+               bool allow = int(cached[0]);
+               const char *label = cached[2];
+               SQLite::int64 auth = cached[3];
+               bool valid = true;
+               if (SQLite3::int64 expires = cached[1])
+                       valid = time(NULL) <= expires;
+               if (valid) {
+                       SYSPOLICY_ASSESS_CACHE_HIT();
+                       cfadd(result, "{%O=%B}", kSecAssessmentAssessmentVerdict, allow);
+                       PolicyEngine::addAuthority(result, label, auth, kCFBooleanTrue);
+                       return true;
+               }
+       }
+       return false;
+}
+
+
+//
+// Purge the object cache of all expired entries
+//
+void PolicyDatabase::purge(const char *table)
+{
+       SQLite::Statement cleaner(*this,
+               "DELETE FROM ?1 WHERE expires < DATE_TIME('now');");
+       cleaner.bind(1) = table;
+       cleaner.execute();
+}
+
+
+//
+// Check the override-enable master flag
+//
+bool overrideAssessment()
+{
+       if (::access(visibleSecurityFlagFile, F_OK) == 0) {
+               return false;
+       } else if (errno == ENOENT) {
+               return true;
+       } else
+               UnixError::throwMe();
+}
+
+
+} // end namespace CodeSigning
+} // end namespace Security
diff --git a/lib/policydb.h b/lib/policydb.h
new file mode 100644 (file)
index 0000000..1b06b4a
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2011 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 _H_POLICYDB
+#define _H_POLICYDB
+
+#include <security_utilities/globalizer.h>
+#include <security_utilities/hashing.h>
+#include <security_utilities/sqlite++.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+namespace Security {
+namespace CodeSigning {
+
+
+namespace SQLite = SQLite3;
+
+
+static const char defaultDatabase[] = "/var/db/SystemPolicy";
+static const char visibleSecurityFlagFile[] = "/var/db/.sp_visible";
+
+
+typedef SHA1::SDigest ObjectHash;
+
+
+typedef uint AuthorityType;
+enum {
+       kAuthorityInvalid = 0,                          // not a valid authority type
+       kAuthorityExecute = 1,                          // authorizes launch and execution
+       kAuthorityInstall = 2,                          // authorizes installation
+       kAuthorityOpenDoc = 3,                          // authorizes opening of documents
+};
+
+
+//
+// An open policy database.
+// Usually read-only, but can be opened for write by privileged callers.
+// This is a translucent wrapper around SQLite::Database; the caller
+// is expected to work with statement rows.
+//
+class PolicyDatabase : public SQLite::Database {
+public:
+       PolicyDatabase(const char *path = NULL, int flags = SQLITE_OPEN_READONLY);
+       virtual ~PolicyDatabase();
+       
+public:
+       bool checkCache(CFURLRef path, AuthorityType type, CFMutableDictionaryRef result);
+
+public:
+       void purge(const char *table);
+};
+
+
+//
+// Check the system-wide overriding flag file
+//
+bool overrideAssessment();
+
+
+} // end namespace CodeSigning
+} // end namespace Security
+
+#endif //_H_POLICYDB
diff --git a/lib/policyengine.cpp b/lib/policyengine.cpp
new file mode 100644 (file)
index 0000000..99e087b
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 2011 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 "policyengine.h"
+#include "xar++.h"
+#include <security_utilities/cfmunge.h>
+#include <Security/Security.h>
+#include <Security/SecRequirementPriv.h>
+#include <Security/SecPolicyPriv.h>
+
+#include <CoreServices/CoreServicesPriv.h>
+#undef check // Macro! Yech.
+
+namespace Security {
+namespace CodeSigning {
+
+static const time_t NEGATIVE_HOLD = 60;        // seconds for negative cache entries
+
+
+//
+// Core structure
+//
+PolicyEngine::PolicyEngine()
+       : PolicyDatabase(NULL, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE)
+{
+}
+
+PolicyEngine::~PolicyEngine()
+{ }
+
+
+//
+// Top-level evaluation driver
+//
+void PolicyEngine::evaluate(CFURLRef path, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result)
+{
+       switch (type) {
+       case kAuthorityExecute:
+               evaluateCode(path, flags, context, result);
+               break;
+       case kAuthorityInstall:
+               evaluateInstall(path, flags, context, result);
+               break;
+       case kAuthorityOpenDoc:
+               evaluateDocOpen(path, flags, context, result);
+               break;
+       default:
+               MacOSError::throwMe(errSecCSInvalidAttributeValues);
+               break;
+       }
+}
+
+
+//
+// Executable code.
+// Read from disk, evaluate properly, cache as indicated. The whole thing, so far.
+//
+void PolicyEngine::evaluateCode(CFURLRef path, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result)
+{
+       const AuthorityType type = kAuthorityExecute;
+       
+       CFRef<SecStaticCodeRef> code;
+       MacOSError::check(SecStaticCodeCreateWithPath(path, kSecCSDefaultFlags, &code.aref()));
+       
+       if (flags & kSecAssessmentFlagRequestOrigin) {
+               CFRef<CFDictionaryRef> info;
+               MacOSError::check(SecCodeCopySigningInformation(code, kSecCSSigningInformation, &info.aref()));
+               if (CFArrayRef chain = CFArrayRef(CFDictionaryGetValue(info, kSecCodeInfoCertificates)))
+                       setOrigin(chain, result);
+       }
+       
+       SecCSFlags validationFlags = kSecCSDefaultFlags;
+       if (overrideAssessment())       // we'll force the verdict to 'pass' at the end, so don't sweat validating code
+               validationFlags = kSecCSBasicValidateOnly;
+
+       SQLite::Statement query(*this,
+               "SELECT allow, requirement, inhibit_cache, expires, id, label FROM authority WHERE type = ?1 ORDER BY priority DESC;");
+       query.bind(1).integer(type);
+       while (query.nextRow()) {
+               bool allow = int(query[0]);
+               const char *reqString = query[1];
+               bool inhibit_cache = query[2];
+               time_t expires = SQLite::int64(query[3]);
+               SQLite3::int64 id = query[4];
+               const char *label = query[5];
+               
+               if (expires && expires < time(NULL))    // no longer active
+                       continue;
+               
+               CFRef<SecRequirementRef> requirement;
+               MacOSError::check(SecRequirementCreateWithString(CFTempString(reqString), kSecCSDefaultFlags, &requirement.aref()));
+               switch (OSStatus rc = SecStaticCodeCheckValidity(code, validationFlags, requirement)) {
+               case noErr: // success
+                       break;
+               case errSecCSUnsigned:
+                       cfadd(result, "{%O=#F}", kSecAssessmentAssessmentVerdict);
+                       addAuthority(result, "no usable signature");
+                       return;
+               case errSecCSSignatureFailed:
+               case errSecCSSignatureInvalid:
+               case errSecCSSignatureUnsupported:
+               case errSecCSSignatureNotVerifiable:
+                       cfadd(result, "{%O=#F}", kSecAssessmentAssessmentVerdict);
+                       addAuthority(result, "invalid signature");
+                       return;
+               case errSecCSReqFailed: // requirement missed, but otherwise okay
+                       continue;
+               default: // broken in some way; all tests will fail like this so bail out
+                       MacOSError::throwMe(rc);
+               }
+               if (!inhibit_cache && !(flags & kSecAssessmentFlagNoCache))     // cache inhibit
+                               this->recordOutcome(code, allow, type, expires, id, label);
+               cfadd(result, "{%O=%B}", kSecAssessmentAssessmentVerdict, allow);
+               addAuthority(result, label, id);
+               return;
+       }
+       
+       // no applicable authority. Deny by default
+       if (!(flags & kSecAssessmentFlagNoCache))
+               this->recordOutcome(code, false, type, time(NULL) + NEGATIVE_HOLD, 0, NULL);
+       cfadd(result, "{%O=%B}", kSecAssessmentAssessmentVerdict, false);
+       addAuthority(result, NULL);
+}
+
+
+//
+// Installer archive.
+// Certs passed from caller (untrusted), no policy engine yet, no caching (since untrusted).
+// The current "policy" is to trust any proper signature.
+//
+void PolicyEngine::evaluateInstall(CFURLRef path, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result)
+{
+       const AuthorityType type = kAuthorityInstall;
+       
+       Xar xar(cfString(path).c_str());
+       if (xar) {
+               if (!xar.isSigned()) {
+                       // unsigned xar
+                       cfadd(result, "{%O=%B}", kSecAssessmentAssessmentVerdict, false);
+                       addAuthority(result, "no usable signature");
+                       return;
+               }
+               if (CFRef<CFArrayRef> certs = xar.copyCertChain()) {
+                       CFRef<SecPolicyRef> policy = SecPolicyCreateBasicX509();
+                       CFRef<SecTrustRef> trust;
+                       MacOSError::check(SecTrustCreateWithCertificates(certs, policy, &trust.aref()));
+//                     MacOSError::check(SecTrustSetAnchorCertificates(trust, cfEmptyArray())); // no anchors
+                       MacOSError::check(SecTrustSetOptions(trust, kSecTrustOptionImplicitAnchors));
+
+                       SecTrustResultType trustResult;
+                       MacOSError::check(SecTrustEvaluate(trust, &trustResult));
+                       CFRef<CFArrayRef> chain;
+                       CSSM_TP_APPLE_EVIDENCE_INFO *info;
+                       MacOSError::check(SecTrustGetResult(trust, &trustResult, &chain.aref(), &info));
+                       
+                       if (flags & kSecAssessmentFlagRequestOrigin)
+                               setOrigin(chain, result);
+                       
+                       switch (trustResult) {
+                       case kSecTrustResultProceed:
+                       case kSecTrustResultConfirm:
+                       case kSecTrustResultUnspecified:
+                               break;
+                       default:
+                               {
+                                       OSStatus rc;
+                                       MacOSError::check(SecTrustGetCssmResultCode(trust, &rc));
+                                       MacOSError::throwMe(rc);
+                               }
+                       }
+
+                       SQLite::Statement query(*this,
+                               "SELECT allow, requirement, inhibit_cache, expires, id, label FROM authority WHERE type = ?1 ORDER BY priority DESC;");
+                       query.bind(1).integer(type);
+                       while (query.nextRow()) {
+                               bool allow = int(query[0]);
+                               const char *reqString = query[1];
+                               bool inhibit_cache = query[2];
+                               time_t expires = SQLite::int64(query[3]);
+                               SQLite3::int64 id = query[4];
+                               const char *label = query[5];
+                               
+                               if (expires && expires < time(NULL))    // no longer active
+                                       continue;
+               
+                               CFRef<SecRequirementRef> requirement;
+                               MacOSError::check(SecRequirementCreateWithString(CFTempString(reqString), kSecCSDefaultFlags, &requirement.aref()));
+                               switch (OSStatus rc = SecRequirementEvaluate(requirement, chain, NULL, kSecCSDefaultFlags)) {
+                               case noErr: // success
+                                       break;
+                               case errSecCSReqFailed: // requirement missed, but otherwise okay
+                                       continue;
+                               default: // broken in some way; all tests will fail like this so bail out
+                                       MacOSError::throwMe(rc);
+                               }
+                               // not adding to the object cache - we could, but it's not likely to be worth it
+                               cfadd(result, "{%O=%B}", kSecAssessmentAssessmentVerdict, allow);
+                               addAuthority(result, label, id);
+                               return;
+                       }
+               }
+       }
+       
+       // no applicable authority. Deny by default
+       cfadd(result, "{%O=#F}", kSecAssessmentAssessmentVerdict);
+       addAuthority(result, NULL);
+}
+
+
+//
+// LaunchServices-layer document open.
+// We don't cache those at present. If we ever do, we need to authenticate CoreServicesUIAgent as the source of its risk assessment.
+//
+void PolicyEngine::evaluateDocOpen(CFURLRef path, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result)
+{
+       if (context) {
+               if (CFStringRef riskCategory = CFStringRef(CFDictionaryGetValue(context, kLSDownloadRiskCategoryKey))) {
+                       if (CFEqual(riskCategory, kLSRiskCategorySafe)
+                               || CFEqual(riskCategory, kLSRiskCategoryNeutral)
+                               || CFEqual(riskCategory, kLSRiskCategoryUnknown)
+                               || CFEqual(riskCategory, kLSRiskCategoryMayContainUnsafeExecutable)) {
+                               cfadd(result, "{%O=#T}", kSecAssessmentAssessmentVerdict);
+                       } else {
+                               cfadd(result, "{%O=#F}", kSecAssessmentAssessmentVerdict);
+                       }
+                       addAuthority(result, "_XProtect");
+                       addToAuthority(result, kLSDownloadRiskCategoryKey, riskCategory);
+                       return;
+               }
+       }
+       // insufficient information from LS - deny by default
+       cfadd(result, "{%O=%F}", kSecAssessmentAssessmentVerdict);
+       addAuthority(result, NULL);
+}
+
+
+void PolicyEngine::addAuthority(CFMutableDictionaryRef parent, const char *label, SQLite::int64 row, CFTypeRef cacheInfo)
+{
+       CFRef<CFMutableDictionaryRef> auth = makeCFMutableDictionary();
+       if (label)
+               cfadd(auth, "{%O=%s}", kSecAssessmentAssessmentSource, label);
+       if (row)
+               CFDictionaryAddValue(auth, kSecAssessmentAssessmentAuthorityRow, CFTempNumber(row));
+       if (cacheInfo)
+               CFDictionaryAddValue(auth, kSecAssessmentAssessmentFromCache, cacheInfo);
+       CFDictionaryAddValue(parent, kSecAssessmentAssessmentAuthority, auth);
+}
+
+void PolicyEngine::addToAuthority(CFMutableDictionaryRef parent, CFStringRef key, CFTypeRef value)
+{
+       CFMutableDictionaryRef authority = CFMutableDictionaryRef(CFDictionaryGetValue(parent, kSecAssessmentAssessmentAuthority));
+       assert(authority);
+       CFDictionaryAddValue(authority, key, value);
+}
+
+
+//
+// Add a rule to the policy database
+//
+bool PolicyEngine::add(CFURLRef path, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context)
+{
+       if (type != kAuthorityExecute)
+               MacOSError::throwMe(errSecCSUnimplemented);
+
+       double priority = 0;
+       string label;
+       if (context) {
+               if (CFTypeRef pri = CFDictionaryGetValue(context, kSecAssessmentUpdateKeyPriority)) {
+                       if (CFGetTypeID(pri) != CFNumberGetTypeID())
+                               MacOSError::throwMe(errSecCSBadDictionaryFormat);
+                       CFNumberGetValue(CFNumberRef(pri), kCFNumberDoubleType, &priority);
+               }
+               if (CFTypeRef lab = CFDictionaryGetValue(context, kSecAssessmentUpdateKeyLabel)) {
+                       if (CFGetTypeID(lab) != CFStringGetTypeID())
+                               MacOSError::throwMe(errSecCSBadDictionaryFormat);
+                       label = cfString(CFStringRef(lab));
+               }
+       }
+
+       CFRef<SecStaticCodeRef> code;
+       MacOSError::check(SecStaticCodeCreateWithPath(path, kSecCSDefaultFlags, &code.aref()));
+       CFRef<CFDictionaryRef> info;
+       MacOSError::check(SecCodeCopySigningInformation(code, kSecCSDefaultFlags, &info.aref()));
+       CFRef<SecRequirementRef> dr;
+       MacOSError::check(SecCodeCopyDesignatedRequirement(code, kSecCSDefaultFlags, &dr.aref()));
+
+       CFRef<CFStringRef> requirementText;
+       MacOSError::check(SecRequirementCopyString(dr, kSecCSDefaultFlags, &requirementText.aref()));
+       SQLite::Statement insert(*this,
+               "INSERT INTO authority (type, allow, requirement, priority, label) VALUES (?1, ?2, ?3, ?4, ?5);");
+       insert.bind(1).integer(type);
+       insert.bind(2).integer(true);
+       insert.bind(3) = requirementText.get();
+       insert.bind(4) = priority;
+       insert.bind(5) = label.c_str();
+       insert.execute();
+       return true;
+}
+
+
+//
+// Fill in extra information about the originator of cryptographic credentials found - if any
+//
+void PolicyEngine::setOrigin(CFArrayRef chain, CFMutableDictionaryRef result)
+{
+       if (chain)
+               if (CFArrayGetCount(chain) > 0)
+                       if (SecCertificateRef leaf = SecCertificateRef(CFArrayGetValueAtIndex(chain, 0)))
+                               if (CFStringRef summary = SecCertificateCopyLongDescription(NULL, leaf, NULL))
+                                       CFDictionarySetValue(result, kSecAssessmentAssessmentOriginator, summary);
+}
+
+
+//
+// Take an assessment outcome and record it in the object cache
+//
+void PolicyEngine::recordOutcome(SecStaticCodeRef code, bool allow, AuthorityType type, time_t expires, int authority, const char *label)
+{
+       CFRef<CFDictionaryRef> info;
+       MacOSError::check(SecCodeCopySigningInformation(code, kSecCSDefaultFlags, &info.aref()));
+       CFDataRef cdHash = CFDataRef(CFDictionaryGetValue(info, kSecCodeInfoUnique));
+       CFRef<CFURLRef> path;
+       MacOSError::check(SecCodeCopyPath(code, kSecCSDefaultFlags, &path.aref()));
+       //@@@ should really be OR REPLACE IF EXPIRED... does it matter? @@@
+       SQLite::Transaction xact(*this, SQLite3::Transaction::deferred, "caching");
+       SQLite::Statement insert(*this,
+               "INSERT OR REPLACE INTO object (type, allow, hash, expires, authority, label, path) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)");
+       insert.bind(1).integer(type);
+       insert.bind(2).integer(allow);
+       insert.bind(3) = cdHash;
+       if (expires)
+               insert.bind(4).integer(expires);
+       insert.bind(5).integer(authority);
+       if (label)
+               insert.bind(6) = label;
+       insert.bind(7) = cfString(path).c_str();
+       insert.execute();
+       xact.commit();
+}
+
+
+} // end namespace CodeSigning
+} // end namespace Security
diff --git a/lib/policyengine.h b/lib/policyengine.h
new file mode 100644 (file)
index 0000000..73b993a
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2011 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 _H_POLICYENGINE
+#define _H_POLICYENGINE
+
+#include "SecAssessment.h"
+#include "policydb.h"
+#include <security_utilities/globalizer.h>
+#include <security_utilities/cfutilities.h>
+#include <security_utilities/hashing.h>
+#include <security_utilities/sqlite++.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <Security/CodeSigning.h>
+
+namespace Security {
+namespace CodeSigning {
+
+
+typedef uint EngineOperation;
+enum {
+       opInvalid = 0,
+       opEvaluate,
+       opAddAuthority,
+       opRemoveAuthority,
+};
+
+
+class PolicyEngine : public PolicyDatabase {
+public:
+       PolicyEngine();
+       virtual ~PolicyEngine();
+
+public:
+       void evaluate(CFURLRef path, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result);
+       bool add(CFURLRef path, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context);
+
+       static void addAuthority(CFMutableDictionaryRef parent, const char *label, SQLite::int64 row = 0, CFTypeRef cacheInfo = NULL);
+       static void addToAuthority(CFMutableDictionaryRef parent, CFStringRef key, CFTypeRef value);
+
+private:
+       void evaluateCode(CFURLRef path, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result);
+       void evaluateInstall(CFURLRef path, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result);
+       void evaluateDocOpen(CFURLRef path, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result);
+
+       void setOrigin(CFArrayRef chain, CFMutableDictionaryRef result);
+
+       void recordOutcome(SecStaticCodeRef code, bool allow, AuthorityType type, time_t expires, int authority, const char *label);
+};
+
+
+} // end namespace CodeSigning
+} // end namespace Security
+
+#endif //_H_POLICYENGINE
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 491b9625b270e34d8f2d904c0b53fcee4a1b2339..ec6cd64390f37071d5b5e0e316460c51d2700588 100644 (file)
@@ -208,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);
index 207efd88fdc26ade29f88a3786188f5085f4f9af..5e1567d58961fdcda7646f4a6094f907e198a644 100644 (file)
 #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.");
 
 
 //
@@ -64,7 +93,7 @@ bool Requirement::Interpreter::evaluate()
        case opTrue:
                return true;
        case opIdent:
-               return getString() == mContext->directory->identifier();
+               return mContext->directory && getString() == mContext->directory->identifier();
        case opAppleAnchor:
                return appleSigned();
        case opAppleGenericAnchor:
@@ -84,11 +113,12 @@ bool Requirement::Interpreter::evaluate()
        case opOr:
                return evaluate() | evaluate();
        case opCDHash:
-               {
+               if (mContext->directory) {
                        SHA1 hash;
                        hash(mContext->directory, mContext->directory->length());
                        return hash.verify(getHash());
-               }
+               } else
+                       return false;
        case opNot:
                return !evaluate();
        case opInfoKeyField:
@@ -117,10 +147,21 @@ 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)) {
@@ -180,10 +221,16 @@ bool Requirement::Interpreter::certFieldValue(const string &key, const Match &ma
                { "subject.CN", &CSSMOID_CommonName },
                { "subject.D", &CSSMOID_Description },
                { "subject.L", &CSSMOID_LocalityName },
+//             { "subject.C-L", &CSSMOID_CollectiveLocalityName },     // missing from Security.framework headers
                { "subject.O", &CSSMOID_OrganizationName },
+               { "subject.C-O", &CSSMOID_CollectiveOrganizationName },
                { "subject.OU", &CSSMOID_OrganizationalUnitName },
+               { "subject.C-OU", &CSSMOID_CollectiveOrganizationalUnitName },
                { "subject.ST", &CSSMOID_StateProvinceName },
+               { "subject.C-ST", &CSSMOID_CollectiveStateProvinceName },
                { "subject.STREET", &CSSMOID_StreetAddress },
+               { "subject.C-STREET", &CSSMOID_CollectiveStreetAddress },
+               { "subject.UID", &CSSMOID_UserID },
                { NULL, NULL }
        };
        
@@ -192,7 +239,7 @@ bool Requirement::Interpreter::certFieldValue(const string &key, const Match &ma
                if (cf->name == key) {
                        CFRef<CFStringRef> value;
                        if (OSStatus rc = SecCertificateCopySubjectComponent(cert, cf->oid, &value.aref())) {
-                               secdebug("csinterp", "cert %p lookup for DN.%s failed rc=%ld", cert, key.c_str(), rc);
+                               secdebug("csinterp", "cert %p lookup for DN.%s failed rc=%d", cert, key.c_str(), rc);
                                return false;
                        }
                        return match(value);
@@ -202,7 +249,7 @@ bool Requirement::Interpreter::certFieldValue(const string &key, const Match &ma
        if (key == "email") {
                CFRef<CFArrayRef> value;
                if (OSStatus rc = SecCertificateCopyEmailAddresses(cert, &value.aref())) {
-                       secdebug("csinterp", "cert %p lookup for email failed rc=%ld", cert, rc);
+                       secdebug("csinterp", "cert %p lookup for email failed rc=%d", cert, rc);
                        return false;
                }
                return match(value);
@@ -213,7 +260,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
@@ -226,6 +273,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
@@ -381,7 +440,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.
@@ -466,5 +525,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 4d940c3fbd25298d0def4b9c24be1abea588491c..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();
        
@@ -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 354bfb18fd2ea56d2abec6bb275a04ec565968af..5a8e94e1057589bcae4dc208f6a8fb14065e2cfc 100644 (file)
@@ -51,7 +51,7 @@ ModuleNexus<PluginHost> plugin;
 PluginHost::PluginHost()
 {
        if (CFBundleRef securityFramework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security")))
-               if (CFURLRef plugins = CFBundleCopyBuiltInPlugInsURL(securityFramework))
+               if (CFRef<CFURLRef> plugins = CFBundleCopyBuiltInPlugInsURL(securityFramework))
                        if (CFRef<CFURLRef> pluginURL = makeCFURL("csparser.bundle", true, plugins)) {
                                plugin = new LoadableBundle(cfString(pluginURL).c_str());
                                plugin->load();
index b1e136e198406ae4a45bf2a9c8d04f8a082f7018..714e6c57ef831c4ea0421293b8840ff46c5922ad 100644 (file)
@@ -57,7 +57,8 @@ const char *const Requirement::typeNames[] = {
        "host",
        "guest",
        "designated",
-       "library"
+       "library",
+       "plugin",
 };
 
 
@@ -65,19 +66,25 @@ const char *const Requirement::typeNames[] = {
 // validate a requirement against a code context
 //
 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()) {
-                       CODESIGN_EVAL_REQINT_END(0);
-                       return;
+                       CODESIGN_EVAL_REQINT_END(this, 0);
+                       return true;
                } else {
-                       CODESIGN_EVAL_REQINT_END(failure);
-                       MacOSError::throwMe(failure);
+                       CODESIGN_EVAL_REQINT_END(this, failure);
+                       return false;
                }
        default:
-               CODESIGN_EVAL_REQINT_END(errSecCSReqUnsupported);
+               CODESIGN_EVAL_REQINT_END(this, errSecCSReqUnsupported);
                MacOSError::throwMe(errSecCSReqUnsupported);
        }
 }
index cf5bf35f7f0f7ce8caa96743b12001e131216073..4588a0249825363d0532fdd46f857962fe1f81f9 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)
@@ -97,14 +98,15 @@ private:
 //
 // An interpretation context
 //
-struct Requirement::Context {
+class Requirement::Context {
+public:
        Context(CFArrayRef certChain, CFDictionaryRef infoDict, CFDictionaryRef entitlementDict, const CodeDirectory *dir)
                : certs(certChain), info(infoDict), entitlements(entitlementDict), directory(dir) { }
        
-       const CFArrayRef certs;
-       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
@@ -150,6 +152,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)
 };
 
@@ -188,18 +193,34 @@ private:
 };
 
 
-}      // CodeSigning
-
-
 //
-// 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 f5b20c3233adb903e4b1714803365ec097311fa7..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@
  * 
@@ -37,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);
@@ -142,10 +142,11 @@ CFDictionaryRef ResourceBuilder::build()
 CFDataRef ResourceBuilder::hashFile(const char *path)
 {
        UnixPlusPlus::AutoFileDesc fd(path);
-       SHA1 hasher;
-       hashFileData(fd, hasher);
-       SHA1::Digest digest;
-       hasher.finish(digest);
+       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));
 }
 
@@ -205,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 7c6ca1c70f779751fcedfde8f9a1787b340aca47..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();
@@ -81,11 +82,13 @@ public:
 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;
 };
 
 
index 2fb8a95b8b0597e8d892ba7561ad2a43ed339fd8..4dbcb67279889866dcf0486d350c6c4378e46dc3 100644 (file)
@@ -29,7 +29,7 @@ provider codesign {
 
        probe eval__dynamic__start(void *me, const char *path);
        probe eval__dynamic__end(void *me);
-       probe eval__dynamic__root();
+       probe eval__dynamic__root(void *me);
        
        probe eval__static__start(void *me, const char *path);
        probe eval__static__end(void *me);
@@ -52,10 +52,12 @@ provider codesign {
        probe eval__static__signature__end(void *me);
 
        probe eval__reqint__start(const void *reqdata, uint32_t reqlength);
-       probe eval__reqint__end(uint32_t result);
+       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);
@@ -68,6 +70,17 @@ provider codesign {
        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();
 };
+
+
+provider syspolicy {
+       probe assess_api(const char *path, uint32_t flags);
+       probe assess_cache_hit();
+       probe assess_local();
+       probe assess_remote();
+};
\ No newline at end of file
index 7a135c9ab399fc54bcbddc73151b86da544c9035..8558455da7d7001a7ad9ea23515a19c5b4dbc01d 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@
 #
@@ -36,8 +36,12 @@ _SecCodeCopyDesignatedRequirement
 _SecCodeCopySigningInformation
 _SecCodeMapMemory
 _SecCodeSetDetachedSignature
+_kSecCodeAttributeArchitecture
+_kSecCodeAttributeBundleVersion
+_kSecCodeAttributeSubarchitecture
 _SecStaticCodeGetTypeID
 _SecStaticCodeCreateWithPath
+_SecStaticCodeCreateWithPathAndAttributes
 _SecStaticCodeCheckValidity
 _SecStaticCodeCheckValidityWithErrors
 _SecRequirementGetTypeID
@@ -48,6 +52,7 @@ _SecRequirementCreateWithStringAndErrors
 _SecRequirementCreateGroup
 _SecRequirementCopyData
 _SecRequirementCopyString
+_SecRequirementEvaluate
 _SecRequirementsCreateFromRequirements
 _SecRequirementsCopyRequirements
 _SecRequirementsCreateWithString
@@ -65,6 +70,7 @@ _SecHostSetHostingPort
 _kSecCodeDirectoryFlagTable
 _kSecCodeSignerApplicationData
 _kSecCodeSignerDetached
+_kSecCodeSignerDigestAlgorithm
 _kSecCodeSignerDryRun
 _kSecCodeSignerEntitlements
 _kSecCodeSignerFlags
@@ -74,6 +80,7 @@ _kSecCodeSignerIdentity
 _kSecCodeSignerPageSize
 _kSecCodeSignerRequirements
 _kSecCodeSignerResourceRules
+_kSecCodeSignerSDKRoot
 _kSecCodeSignerSigningTime
 _kSecCodeInfoCertificates
 _kSecCodeInfoChangedFiles
@@ -82,6 +89,7 @@ _kSecCodeInfoTime
 _kSecCodeInfoDesignatedRequirement
 _kSecCodeInfoEntitlements
 _kSecCodeInfoFormat
+_kSecCodeInfoDigestAlgorithm
 _kSecCodeInfoIdentifier
 _kSecCodeInfoImplicitDesignatedRequirement
 _kSecCodeInfoMainExecutable
@@ -99,6 +107,9 @@ _kSecGuestAttributeCanonical
 _kSecGuestAttributeHash
 _kSecGuestAttributeMachPort
 _kSecGuestAttributePid
+_kSecRequirementKeyInfoPlist
+_kSecRequirementKeyEntitlements
+_kSecCFErrorArchitecture
 _kSecCFErrorPattern
 _kSecCFErrorResourceSeal
 _kSecCFErrorResourceAdded
@@ -107,3 +118,33 @@ _kSecCFErrorResourceMissing
 _kSecCFErrorInfoPlist
 _kSecCFErrorGuestAttributes
 _kSecCFErrorRequirementSyntax
+_kSecCFErrorPath
+
+# Entitlements
+_SecTaskGetTypeID
+_SecTaskCreateWithAuditToken
+_SecTaskCopyValueForEntitlement
+_SecTaskCopyValuesForEntitlements
+
+# Assessments
+_SecAssessmentCreate
+_SecAssessmentCopyResult
+_SecAssessmentUpdate
+_SecAssessmentControl
+_kSecAssessmentContextKeyOperation
+_kSecAssessmentOperationTypeExecute
+_kSecAssessmentOperationTypeInstall
+_kSecAssessmentOperationTypeOpenDocument
+_kSecAssessmentContextKeyUpdate
+_kSecAssessmentUpdateOperationAddFile
+_kSecAssessmentUpdateOperationRemoveFile
+_kSecAssessmentUpdateKeyPriority
+_kSecAssessmentUpdateKeyLabel
+_kSecAssessmentAssessmentAuthority
+_kSecAssessmentAssessmentAuthorityRow
+_kSecAssessmentAssessmentFromCache
+_kSecAssessmentAssessmentOriginator
+_kSecAssessmentAssessmentAuthorityOverride
+_kSecAssessmentAssessmentSource
+_kSecAssessmentAssessmentVerdict
+_kSecAssessmentContextKeyCertificates
index 68537d92d53b74240490df944ec5911ba98aadea..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@
  * 
@@ -35,6 +35,7 @@
 #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_utilities/cfmunge.h>
@@ -70,7 +71,7 @@ void SecCodeSigner::Signer::remove(SecCSFlags flags)
        rep = code->diskRep();
        if (Universal *fat = state.mNoMachO ? NULL : rep->mainExecutableImage()) {
                // architecture-sensitive removal
-               MachOEditor editor(rep->writer(), *fat, rep->mainExecutablePath());
+               MachOEditor editor(rep->writer(), *fat, kSecCodeSignatureNoHash, rep->mainExecutablePath());
                editor.allocate();              // create copy
                editor.commit();                // commit change
        } else {
@@ -95,9 +96,11 @@ void SecCodeSigner::Signer::prepare(SecCSFlags flags)
        // work out the canonical identifier
        identifier = state.mIdentifier;
        if (identifier.empty()) {
-               identifier = rep->recommendedIdentifier();
+               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());
@@ -141,10 +144,10 @@ void SecCodeSigner::Signer::prepare(SecCSFlags flags)
 
                // 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"));
+               ResourceBuilder resources(rpath, cfget<CFDictionaryRef>(resourceRules, "rules"), digestAlgorithm());
                rep->adjustResources(resources);        // DiskRep-specific adjustments
                CFRef<CFDictionaryRef> rdir = resources.build();
                resourceDirectory.take(CFPropertyListCreateXMLData(NULL, rdir));
@@ -163,7 +166,7 @@ void SecCodeSigner::Signer::prepare(SecCSFlags flags)
                signingTime = time;
        }
        
-       pagesize = state.mPageSize ? cfNumber<size_t>(state.mPageSize) : rep->pageSize();
+       pagesize = state.mPageSize ? cfNumber<size_t>(state.mPageSize) : rep->pageSize(state);
 }
 
 
@@ -178,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);
@@ -187,7 +190,7 @@ 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,
@@ -241,9 +244,9 @@ 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());
        
@@ -289,21 +292,21 @@ void SecCodeSigner::Signer::populate(CodeDirectory::Builder &builder, DiskRep::W
        builder.identifier(identifier);
        
        if (CFDataRef data = rep->component(cdInfoSlot))
-               builder.special(cdInfoSlot, data);
+               builder.specialSlot(cdInfoSlot, data);
        if (ireqs) {
                CFRef<CFDataRef> data = makeCFData(*ireqs);
                writer.component(cdRequirementsSlot, data);
-               builder.special(cdRequirementsSlot, data);
+               builder.specialSlot(cdRequirementsSlot, data);
        }
        if (resourceDirectory)
-               builder.special(cdResourceDirSlot, resourceDirectory);
+               builder.specialSlot(cdResourceDirSlot, resourceDirectory);
 #if NOT_YET
        if (state.mApplicationData)
-               builder.special(cdApplicationSlot, state.mApplicationData);
+               builder.specialSlot(cdApplicationSlot, state.mApplicationData);
 #endif
        if (state.mEntitlementData) {
                writer.component(cdEntitlementSlot, state.mEntitlementData);
-               builder.special(cdEntitlementSlot, state.mEntitlementData);
+               builder.specialSlot(cdEntitlementSlot, state.mEntitlementData);
        }
        
        writer.addDiscretionary(builder);
@@ -366,5 +369,30 @@ uint32_t SecCodeSigner::Signer::cdTextFlags(std::string text)
 }
 
 
+//
+// 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 d521354fe13ac43aaf44c13739cc34732faab16c..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@
  * 
@@ -52,6 +52,8 @@ public:
        SecCodeSigner &state;
        SecStaticCode * const code;
        
+       CodeDirectory::HashAlgorithm digestAlgorithm() const { return state.mDigestAlgorithm; }
+       
        std::string path() const { return cfString(rep->canonicalPath()); }
        
 protected:
@@ -65,6 +67,7 @@ protected:
        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 a7e925ae216ae66b5a7c9842b61bc6f19404fba0..f1264f5db344764fb15e40b80b22c19708799a17 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@
  * 
@@ -75,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);
 }
 
 
@@ -96,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);
@@ -124,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;
@@ -190,7 +199,7 @@ void MachOEditor::parentAction()
                code->validateDirectory();
                code->validateExecutable();
                code->validateResources();
-               code->validateRequirements((const Requirement *)appleReq, errSecCSReqFailed);
+               code->validateRequirement((const Requirement *)appleReq, errSecCSReqFailed);
        }
 }
 
@@ -206,7 +215,7 @@ void MachOEditor::childAction()
        for (Iterator it = architecture.begin(); it != architecture.end(); ++it) {
                size_t size = LowLevelMemoryUtilities::alignUp(it->second->blobSize, csAlign);
                char *ssize;                    // we'll leak this (execv is coming soon)
-               asprintf(&ssize, "%d", size);
+               asprintf(&ssize, "%zd", size);
 
                if (const char *arch = it->first.name()) {
                        CODESIGN_ALLOCATE_ARCH((char*)arch, size);
@@ -281,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()));
index 8a13733702644b788a56a24c91430f1cd09222a5..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@
  * 
@@ -66,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:
@@ -82,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) { }
        };
 
        //
@@ -112,7 +113,7 @@ protected:
 //
 class BlobEditor : public ArchEditor {
 public:
-       BlobEditor(Universal &fat, SecCodeSigner::Signer &s) : ArchEditor(fat), signer(s) { }
+       BlobEditor(Universal &fat, SecCodeSigner::Signer &s);
        
        SecCodeSigner::Signer &signer;
        
@@ -130,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;
@@ -147,13 +150,16 @@ 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;
 };
index ab3064d01a5b9f88b15db3de9084d187f161bedb..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@
  * 
@@ -51,7 +51,7 @@ CFDataRef SingleDiskRep::identification()
 {
        SHA1 hash;
        this->fd().seek(0);
-       hashFileData(this->fd(), hash);
+       hashFileData(this->fd(), &hash);
        SHA1::Digest digest;
        hash.finish(digest);
        return makeCFData(digest, sizeof(digest));
@@ -72,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.
@@ -116,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 dc4e77cda354f8c6d88d25fb772e94c68a73f712..2ff73e10787a298e530e2e991dc887597c114050 100644 (file)
@@ -49,11 +49,12 @@ public:
        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;
        
index 1ba4c49f3dd69ec704afcf5583186a5d1cf0cf38..254d651e501a205975a6092b5a63af8fdc2d93e3 100644 (file)
@@ -77,7 +77,7 @@ bool DYLDCacheRep::candidate(FileDesc &fd)
 //
 // Default to system page size for segmented (paged) signatures
 //
-size_t DYLDCacheRep::pageSize()
+size_t DYLDCacheRep::pageSize(const SigningContext &)
 {
        return segmentedPageSize;
 }
index 70b88fa5df00cb412c27ac09a3fe3656a8b3d72b..4e044ae3c344ee201c1a4c1aab1b53411bb1b248 100644 (file)
@@ -48,7 +48,7 @@ public:
        DYLDCacheRep(const char *path);
        
        CFDataRef component(CodeDirectory::SpecialSlot slot);
-       size_t pageSize();
+       size_t pageSize(const SigningContext &ctx);
        std::string format();
        
        static bool candidate(UnixPlusPlus::FileDesc &fd);
diff --git a/lib/syspolicy.sql b/lib/syspolicy.sql
new file mode 100644 (file)
index 0000000..4e2eb86
--- /dev/null
@@ -0,0 +1,87 @@
+--
+-- Copyright (c) 2011 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@
+--
+--
+-- System Policy master database - file format and initial contents
+--
+-- This is currently for sqlite3
+--
+PRAGMA foreign_keys = true;
+
+
+
+--
+-- The primary authority. This table is conceptually scanned
+-- in priority order, with the highest-priority matching record
+-- determining the outcome.
+-- 
+CREATE TABLE authority (
+       id INTEGER PRIMARY KEY,
+       type INTEGER NOT NULL,
+       requirement TEXT NOT NULL,
+       allow INTEGER NOT NULL,
+       expires INTEGER NULL,
+       priority REAL NOT NULL DEFAULT (0),
+       label TEXT NULL,
+       inhibit_cache INTEGER NULL,
+       flags INTEGER NOT NULL DEFAULT (0),
+       -- following fields are for documentation only
+       remarks TEXT NULL
+);
+
+-- any Apple-signed installers of any kind
+insert into authority (type, allow, priority, label, requirement)
+       values (2, 1, -1, 'Apple Installer', 'anchor apple generic');
+
+-- Apple code signing
+insert into authority (type, allow, label, requirement)
+       values (1, 1, 'Apple', 'anchor apple');
+
+-- Mac App Store signing
+insert into authority (type, allow, label, requirement)
+       values (1, 1, 'Mac App Store', 'anchor apple generic and certificate leaf[field.1.2.840.113635.100.6.1.9] exists');
+
+insert into authority (type, allow, label, requirement)
+       values (1, 1, 'Developer Seed', 'anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] exists and certificate leaf[field.1.2.840.113635.100.6.1.13] exists');
+insert into authority (type, allow, label, requirement)
+       values (2, 1, 'Developer Seed', 'anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] exists and certificate leaf[field.1.2.840.113635.100.6.1.14] exists');
+
+
+--
+-- The cache table lists previously determined outcomes
+-- for individual objects (by object hash). Entries come from
+-- full evaluations of authority records, or by explicitly inserting
+-- override rules that preempt the normal authority.
+--
+CREATE TABLE object (
+       id INTEGER PRIMARY KEY,
+       type INTEGER NOT NULL,
+       hash CDHASH NOT NULL UNIQUE,
+       allow INTEGER NOT NULL,
+       expires INTEGER NULL,
+       label TEXT NULL,
+       authority INTEGER NULL REFERENCES authority(id),
+       -- following fields are for documentation only
+       path TEXT NULL,
+       created INTEGER NOT NULL default (strftime('%s','now')),
+       remarks TEXT NULL
+);
diff --git a/lib/xar++.cpp b/lib/xar++.cpp
new file mode 100644 (file)
index 0000000..42b49a4
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2011 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@
+ */
+
+//
+// xar++ - interface to XAR-format archive files
+//
+#include "xar++.h"
+#include <security_utilities/cfutilities.h>
+#include <Security/Security.h>
+
+
+namespace Security {
+namespace CodeSigning {
+
+
+Xar::Xar(const char *path)
+{
+       mXar = 0;
+       mSig = 0;
+       if (path)
+               open(path);
+}
+
+void Xar::open(const char *path)
+{
+       if ((mXar = ::xar_open(path, READ)))
+               mSig = xar_signature_first(mXar);
+}
+
+Xar::~Xar()
+{
+       if (mXar)
+               ::xar_close(mXar);
+}
+
+
+CFArrayRef Xar::copyCertChain()
+{
+       if (!mSig)
+               return NULL;
+       unsigned count = xar_signature_get_x509certificate_count(mSig);
+       CFRef<CFMutableArrayRef> certs = makeCFMutableArray(0);
+       for (unsigned ix = 0; ix < count; ix++) {
+               const uint8_t *data;
+               uint32_t length;
+               if (xar_signature_get_x509certificate_data(mSig, ix, &data, &length) == 0) {
+                       CFTempData cdata(data, length);
+                       CFRef<SecCertificateRef> cert = SecCertificateCreateWithData(NULL, cdata);
+                       CFArrayAppendValue(certs, cert.get());
+               }
+       }
+       return certs.yield();
+}
+
+
+} // end namespace CodeSigning
+} // end namespace Security
diff --git a/lib/xar++.h b/lib/xar++.h
new file mode 100644 (file)
index 0000000..fa28777
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2011 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@
+ */
+
+//
+// xar++ - interface to XAR-format archive files
+//
+#ifndef _H_XARPLUSPLUS
+#define _H_XARPLUSPLUS
+
+#include <security_utilities/utilities.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+extern "C" {
+#include <xar/xar.h>
+}
+
+namespace Security {
+namespace CodeSigning {
+
+
+//
+// A XAR-format file on disk
+//
+class Xar {
+public:        
+       Xar(const char *path = NULL);
+       virtual ~Xar();
+       void open(const char *path);
+       
+       operator bool() const { return mXar != 0; }
+       bool isSigned() const { return mSig != 0; }
+       
+       CFArrayRef copyCertChain();
+
+private:
+       xar_t mXar;
+       xar_signature_t mSig;
+};
+
+
+
+} // end namespace CodeSigning
+} // end namespace Security
+
+#endif // !_H_XARPLUSPLUS
diff --git a/lib/xpcengine.cpp b/lib/xpcengine.cpp
new file mode 100644 (file)
index 0000000..b9ace0f
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2011 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 "xpcengine.h"
+#include <xpc/connection.h>
+#include <syslog.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <security_utilities/cfutilities.h>
+
+
+namespace Security {
+namespace CodeSigning {
+
+static const char serviceName[] = "com.apple.security.syspolicy";
+
+
+static dispatch_once_t dispatchInit;           // one-time init marker
+static xpc_connection_t service;                       // connection to spd
+static dispatch_queue_t queue;                         // dispatch queue for service
+
+static void init()
+{
+       dispatch_once(&dispatchInit, ^void(void) {
+               const char *name = serviceName;
+               if (const char *env = getenv("SYSPOLICYNAME"))
+                       name = env;
+               queue = dispatch_queue_create("spd-client", 0);
+               service = xpc_connection_create_mach_service(name, queue, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
+               xpc_connection_set_event_handler(service, ^(xpc_object_t ev) {
+               });
+               xpc_connection_resume(service);
+       });
+}
+
+
+//
+// Your standard XPC client-side machinery
+//
+class Message {
+public:
+       xpc_object_t obj;
+       
+       Message(const char *function)
+       {
+               init();
+               obj = xpc_dictionary_create(NULL, NULL, 0);
+               xpc_dictionary_set_string(obj, "function", function);
+       }
+       ~Message()
+       {
+               if (obj)
+                       xpc_release(obj);
+       }
+       operator xpc_object_t () { return obj; }
+
+       void send()
+       {
+               xpc_object_t reply = xpc_connection_send_message_with_reply_sync(service, obj);
+               xpc_release(obj);
+               obj = NULL;
+               xpc_type_t type = xpc_get_type(reply);
+               if (type == XPC_TYPE_DICTIONARY) {
+                       obj = reply;
+                       if (int64_t error = xpc_dictionary_get_int64(obj, "error"))
+                               MacOSError::throwMe(error);
+               } else if (type == XPC_TYPE_ERROR) {
+                       const char *s = xpc_copy_description(reply);
+                       printf("Error returned: %s\n", s);
+                       free((char*)s);
+                       MacOSError::throwMe(errSecCSInternalError);
+               } else {
+                       const char *s = xpc_copy_description(reply);
+                       printf("Unexpected type of return object: %s\n", s);
+                       free((char*)s);
+               }
+       }
+};
+
+
+
+static void copyCFDictionary(const void *key, const void *value, void *ctx)
+{
+       CFMutableDictionaryRef target = CFMutableDictionaryRef(ctx);
+       if (CFEqual(key, kSecAssessmentContextKeyCertificates))         // legacy; drop it
+               return;
+       if (CFGetTypeID(value) == CFURLGetTypeID()) {
+               CFRef<CFStringRef> path = CFURLCopyFileSystemPath(CFURLRef(value), kCFURLPOSIXPathStyle);
+               CFDictionaryAddValue(target, key, path);
+       } else {
+               CFDictionaryAddValue(target, key, value);
+       }
+}
+
+void xpcEngineAssess(CFURLRef path, uint flags, CFDictionaryRef context, CFMutableDictionaryRef result)
+{
+       Message msg("assess");
+       xpc_dictionary_set_string(msg, "path", cfString(path).c_str());
+       xpc_dictionary_set_int64(msg, "flags", flags);
+       CFRef<CFMutableDictionaryRef> ctx = makeCFMutableDictionary();
+       if (context)
+               CFDictionaryApplyFunction(context, copyCFDictionary, ctx);
+       CFRef<CFDataRef> contextData = makeCFData(CFDictionaryRef(ctx));
+       xpc_dictionary_set_data(msg, "context", CFDataGetBytePtr(contextData), CFDataGetLength(contextData));
+       msg.send();
+       size_t resultLength;
+       const void *resultData = xpc_dictionary_get_data(msg, "result", &resultLength);
+       CFRef<CFDictionaryRef> resultDict = makeCFDictionaryFrom(resultData, resultLength);
+       CFDictionaryApplyFunction(resultDict, copyCFDictionary, result);
+       CFDictionaryAddValue(result, CFSTR("assessment:remote"), kCFBooleanTrue);
+}
+
+
+bool xpcEngineControl(const char *control)
+{
+       Message msg("control");
+       xpc_dictionary_set_string(msg, "control", control);
+       msg.send();
+       return true;
+}
+
+
+} // end namespace CodeSigning
+} // end namespace Security
diff --git a/lib/xpcengine.h b/lib/xpcengine.h
new file mode 100644 (file)
index 0000000..92a6030
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2011 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 _H_XPCENGINE
+#define _H_XPCENGINE
+
+#include "SecAssessment.h"
+#include "policydb.h"
+#include <xpc/private.h>
+#include <Security/Security.h>
+
+namespace Security {
+namespace CodeSigning {
+
+
+void xpcEngineAssess(CFURLRef path, uint flags, CFDictionaryRef context, CFMutableDictionaryRef result);
+bool xpcEngineControl(const char *name);
+
+
+
+} // end namespace CodeSigning
+} // end namespace Security
+
+#endif //_H_XPCENGINE
index 951bd003eb157d9712f4dd01882a4493819fe3d6..111f93a3a7c59d5059dae925809a798ac0434c8f 100644 (file)
@@ -3,10 +3,22 @@
        archiveVersion = 1;
        classes = {
        };
-       objectVersion = 42;
+       objectVersion = 46;
        objects = {
 
 /* Begin PBXAggregateTarget section */
+               C26AC0EB143BCF01001C98CE /* SystemPolicy */ = {
+                       isa = PBXAggregateTarget;
+                       buildConfigurationList = C26AC0EC143BCF01001C98CE /* Build configuration list for PBXAggregateTarget "SystemPolicy" */;
+                       buildPhases = (
+                               C26AC0F0143BCF18001C98CE /* ShellScript */,
+                               C26AC0F4143BD1C4001C98CE /* CopyFiles */,
+                       );
+                       dependencies = (
+                       );
+                       name = SystemPolicy;
+                       productName = SystemPolicy;
+               };
                C26AC7090DAEB3A7005BFB40 /* DTrace */ = {
                        isa = PBXAggregateTarget;
                        buildConfigurationList = C26AC70D0DAEB3C6005BFB40 /* Build configuration list for PBXAggregateTarget "DTrace" */;
@@ -38,6 +50,7 @@
                                C2E287410B5D8F97009336A0 /* PBXTargetDependency */,
                                C250F6C50B5EF4E40076098F /* PBXTargetDependency */,
                                C2E287430B5D8F9A009336A0 /* PBXTargetDependency */,
+                               C26AC0F2143BD02B001C98CE /* PBXTargetDependency */,
                        );
                        name = Everything;
                        productName = Everything;
                C22463610B86210100626F1B /* antlrplugin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2CC31130B85254F005FA59D /* antlrplugin.cpp */; };
                C236E3D70AD59446000F5140 /* signer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C236E3D50AD59446000F5140 /* signer.cpp */; };
                C236E3DB0AD595C2000F5140 /* signerutils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C236E3D90AD595C2000F5140 /* signerutils.cpp */; };
+               C24EABAB1421432800C16AA9 /* policydb.h in Headers */ = {isa = PBXBuildFile; fileRef = C24EABAA1421432800C16AA9 /* policydb.h */; };
+               C24EABAD1421433700C16AA9 /* policydb.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C24EABAC1421433700C16AA9 /* policydb.cpp */; };
                C250F6C30B5EF1910076098F /* SecIntegrity.h in Headers */ = {isa = PBXBuildFile; fileRef = C250F6C20B5EF1910076098F /* SecIntegrity.h */; };
                C259DFD60AD6D9BA00C9ACC6 /* sigblob.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C259DFD40AD6D9BA00C9ACC6 /* sigblob.cpp */; };
+               C26AC0F5143BD1C8001C98CE /* SystemPolicy in CopyFiles */ = {isa = PBXBuildFile; fileRef = C26AC0F3143BD1B3001C98CE /* SystemPolicy */; };
                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, ); }; };
                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, ); }; };
+               C273601E1432A60B00A9A5FF /* policyengine.h in Headers */ = {isa = PBXBuildFile; fileRef = C273601D1432A60B00A9A5FF /* policyengine.h */; };
+               C273606E1433F09000A9A5FF /* SecAssessment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C273606C1433F09000A9A5FF /* SecAssessment.cpp */; };
+               C273606F1433F09000A9A5FF /* SecAssessment.h in Headers */ = {isa = PBXBuildFile; fileRef = C273606D1433F09000A9A5FF /* SecAssessment.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               C27360701433F09000A9A5FF /* SecAssessment.h in Headers */ = {isa = PBXBuildFile; fileRef = C273606D1433F09000A9A5FF /* SecAssessment.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               C27360711433F0E600A9A5FF /* SecAssessment.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C273606D1433F09000A9A5FF /* SecAssessment.h */; };
+               C27360D51436866D00A9A5FF /* xpcengine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C27360D41436866C00A9A5FF /* xpcengine.cpp */; };
                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, ); }; };
                C2D3839B0A238150005C63A2 /* CodeSigning.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = C2D383180A237F47005C63A2 /* CodeSigning.h */; };
                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, ); }; };
+               C2DC2DCA145F594000AD2A3A /* xar++.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2353410145F1B110073F964 /* xar++.cpp */; };
+               C2DC2DCB145F5CD000AD2A3A /* policyengine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C27360201432A61900A9A5FF /* policyengine.cpp */; };
                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, ); }; };
                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 */; };
                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;
                };
+               C26AC0F1143BD02B001C98CE /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 4CA1FEAB052A3C3800F22E42 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = C26AC0EB143BCF01001C98CE;
+                       remoteInfo = SystemPolicy;
+               };
                C26AC70E0DAEB400005BFB40 /* 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 */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               C26AC0F4143BD1C4001C98CE /* CopyFiles */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = private/var/db;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               C26AC0F5143BD1C8001C98CE /* SystemPolicy in CopyFiles */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
                C26C39D3068368EC00ED5782 /* CopyFiles */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 2147483647;
                                C21EA3E00AD2F81300E6E31C /* SecCodeSigner.h in CopyFiles */,
                                C2A752B70B80EAFB004CF655 /* SecIntegrity.h in CopyFiles */,
                                C2A752B80B80EAFB004CF655 /* SecCodeHostLib.h in CopyFiles */,
+                               C27360711433F0E600A9A5FF /* SecAssessment.h in CopyFiles */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                C21EA3DC0AD2F81300E6E31C /* SecCodeSigner.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SecCodeSigner.h; sourceTree = "<group>"; };
                C21EA3E10AD2FA0900E6E31C /* CodeSigner.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CodeSigner.cpp; sourceTree = "<group>"; };
                C21EA3E20AD2FA0900E6E31C /* CodeSigner.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CodeSigner.h; sourceTree = "<group>"; };
+               C235340E145F1B050073F964 /* xar++.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "xar++.h"; sourceTree = "<group>"; };
+               C2353410145F1B110073F964 /* xar++.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "xar++.cpp"; sourceTree = "<group>"; };
                C236E3D50AD59446000F5140 /* signer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = signer.cpp; sourceTree = "<group>"; };
                C236E3D60AD59446000F5140 /* signer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = signer.h; sourceTree = "<group>"; };
                C236E3D90AD595C2000F5140 /* signerutils.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = signerutils.cpp; sourceTree = "<group>"; };
                C236E3DA0AD595C2000F5140 /* signerutils.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = signerutils.h; sourceTree = "<group>"; };
+               C24EABAA1421432800C16AA9 /* policydb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = policydb.h; sourceTree = "<group>"; };
+               C24EABAC1421433700C16AA9 /* policydb.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = policydb.cpp; sourceTree = "<group>"; };
                C250F6C20B5EF1910076098F /* SecIntegrity.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SecIntegrity.h; sourceTree = "<group>"; };
                C250F6C60B5EF5B50076098F /* SecIntegrity.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = SecIntegrity.cpp; 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>"; };
+               C26AC0F3143BD1B3001C98CE /* SystemPolicy */ = {isa = PBXFileReference; lastKnownFileType = text; path = SystemPolicy; 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>"; };
+               C27249D2143237CD0058B552 /* syspolicy.sql */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = syspolicy.sql; sourceTree = "<group>"; };
+               C273601D1432A60B00A9A5FF /* policyengine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = policyengine.h; sourceTree = "<group>"; };
+               C27360201432A61900A9A5FF /* policyengine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = policyengine.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
+               C273606C1433F09000A9A5FF /* SecAssessment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = SecAssessment.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
+               C273606D1433F09000A9A5FF /* SecAssessment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = SecAssessment.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
+               C27360D41436866C00A9A5FF /* xpcengine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = xpcengine.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
+               C27360D71436868600A9A5FF /* xpcengine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xpcengine.h; 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>"; };
                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 PBXFrameworksBuildPhase section */
                                C26AC6FF0DAEB2D0005BFB40 /* DTrace */,
                                C2CCF0360A3F524B0085795A /* Local Utilities */,
                                C2CC31160B852554005FA59D /* Security Plugins */,
+                               FEB30C9110DAC6C400557BA2 /* Entitlements */,
+                               C24EABA914213FAF00C16AA9 /* System Policy */,
                        );
                        path = lib;
                        sourceTree = "<group>";
                        name = "Signing Operations";
                        sourceTree = "<group>";
                };
+               C24EABA914213FAF00C16AA9 /* System Policy */ = {
+                       isa = PBXGroup;
+                       children = (
+                               C273606D1433F09000A9A5FF /* SecAssessment.h */,
+                               C273606C1433F09000A9A5FF /* SecAssessment.cpp */,
+                               C24EABAA1421432800C16AA9 /* policydb.h */,
+                               C24EABAC1421433700C16AA9 /* policydb.cpp */,
+                               C273601D1432A60B00A9A5FF /* policyengine.h */,
+                               C27360201432A61900A9A5FF /* policyengine.cpp */,
+                               C27360D71436868600A9A5FF /* xpcengine.h */,
+                               C27360D41436866C00A9A5FF /* xpcengine.cpp */,
+                               C27249D2143237CD0058B552 /* syspolicy.sql */,
+                       );
+                       name = "System Policy";
+                       sourceTree = "<group>";
+               };
                C26AC6FF0DAEB2D0005BFB40 /* DTrace */ = {
                        isa = PBXGroup;
                        children = (
                                C26AC6FD0DAEB2C4005BFB40 /* security_codesigning.d */,
+                               C2F6071B107D575700A83618 /* codesign-watch.d */,
                        );
                        name = DTrace;
                        sourceTree = "<group>";
                                C2EF100E0A49BD89005A44BB /* renum.cpp */,
                                C2A976A90B8A2E36008B4EA0 /* csutilities.h */,
                                C2A976A80B8A2E36008B4EA0 /* csutilities.cpp */,
+                               C235340E145F1B050073F964 /* xar++.h */,
+                               C2353410145F1B110073F964 /* xar++.cpp */,
                        );
                        name = "Local Utilities";
                        sourceTree = "<group>";
                                C2B9F1D20D51646600CAB713 /* RequirementKeywords.h */,
                                C2D383F20A23A9D3005C63A2 /* RequirementParserTokenTypes.hpp */,
                                C2D383F30A23A9D3005C63A2 /* RequirementParserTokenTypes.txt */,
+                               C26AC0F3143BD1B3001C98CE /* SystemPolicy */,
                                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 = (
+                               FEB30C9E10DAC8FD00557BA2 /* SecTask.h in Headers */,
                                C2E8AF2A0DE25D11000F6D3B /* SecCodePriv.h in Headers */,
                                C2E8AF2B0DE25D11000F6D3B /* SecStaticCodePriv.h in Headers */,
                                C2E8AF2C0DE25D11000F6D3B /* SecRequirementPriv.h in Headers */,
                                C2BD519F0A9392FD000FE43D /* machorep.h in Headers */,
                                C2CC31050B8523AD005FA59D /* SecIntegrityLib.h in Headers */,
                                C28342E60E366E6800E54360 /* csdatabase.h in Headers */,
+                               C27360701433F09000A9A5FF /* SecAssessment.h in Headers */,
                                C28342ED0E36719D00E54360 /* detachedrep.h in Headers */,
+                               C273601E1432A60B00A9A5FF /* policyengine.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        isa = PBXHeadersBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               FEB30CA410DAC97400557BA2 /* SecTask.h in Headers */,
                                C26FF62F0E5B376B00F640A0 /* CodeSigning.h in Headers */,
                                C26FF6300E5B376B00F640A0 /* CSCommon.h in Headers */,
                                C26FF6310E5B376B00F640A0 /* CSCommonPriv.h in Headers */,
                                C26FF63A0E5B376B00F640A0 /* SecIntegrity.h in Headers */,
                                C26FF62D0E5B375A00F640A0 /* SecIntegrityLib.h in Headers */,
                                C26FF62E0E5B375A00F640A0 /* SecCodeHostLib.h in Headers */,
+                               C273606F1433F09000A9A5FF /* SecAssessment.h in Headers */,
                                C2A436160F2133B2007A41A6 /* slcrep.h in Headers */,
+                               C24EABAB1421432800C16AA9 /* policydb.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
 /* Begin PBXProject section */
                4CA1FEAB052A3C3800F22E42 /* Project object */ = {
                        isa = PBXProject;
+                       attributes = {
+                               LastUpgradeCheck = 0420;
+                       };
                        buildConfigurationList = C263E67909A2971B000043F1 /* Build configuration list for PBXProject "libsecurity_codesigning" */;
-                       compatibilityVersion = "Xcode 2.4";
+                       compatibilityVersion = "Xcode 3.2";
+                       developmentRegion = English;
                        hasScannedForEncodings = 1;
+                       knownRegions = (
+                               English,
+                               Japanese,
+                               French,
+                               German,
+                       );
                        mainGroup = 4CA1FEA7052A3C3800F22E42;
                        productRefGroup = 4CA1FEBF052A3C8100F22E42 /* Products */;
                        projectDirPath = "";
                                C2BC1F250B580D3A003EC9DC /* libintegrity */,
                                C2BC1F2E0B580D4B003EC9DC /* libcodehost */,
                                C26AC7090DAEB3A7005BFB40 /* DTrace */,
+                               C26AC0EB143BCF01001C98CE /* SystemPolicy */,
                        );
                };
 /* End PBXProject section */
                        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";
                };
+               C26AC0F0143BCF18001C98CE /* ShellScript */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 8;
+                       files = (
+                       );
+                       inputPaths = (
+                               "$(SRCROOT)/lib/syspolicy.sql",
+                       );
+                       outputPaths = (
+                               "$(TEMPDIR)/SystemPolicy",
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+                       shellPath = /bin/sh;
+                       shellScript = "mkdir -p \"$(dirname \"$SCRIPT_OUTPUT_FILE_0\")\"\nsqlite3 \"$SCRIPT_OUTPUT_FILE_0\" <<END\n.read \"$SCRIPT_INPUT_FILE_0\"\nEND\n";
+                       showEnvVarsInLog = 0;
+               };
                C26AC7080DAEB3A7005BFB40 /* ShellScript */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 2147483647;
                                C28342E70E366E6800E54360 /* csdatabase.cpp in Sources */,
                                C28342EE0E36719D00E54360 /* detachedrep.cpp in Sources */,
                                C2A436150F2133B2007A41A6 /* slcrep.cpp in Sources */,
+                               FEB30C9310DAC89D00557BA2 /* SecTask.c in Sources */,
+                               C24EABAD1421433700C16AA9 /* policydb.cpp in Sources */,
+                               C273606E1433F09000A9A5FF /* SecAssessment.cpp in Sources */,
+                               C27360D51436866D00A9A5FF /* xpcengine.cpp in Sources */,
+                               C2DC2DCA145F594000AD2A3A /* xar++.cpp in Sources */,
+                               C2DC2DCB145F5CD000AD2A3A /* policyengine.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        target = C2BC1F250B580D3A003EC9DC /* libintegrity */;
                        targetProxy = C250F6C40B5EF4E40076098F /* PBXContainerItemProxy */;
                };
+               C26AC0F2143BD02B001C98CE /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = C26AC0EB143BCF01001C98CE /* SystemPolicy */;
+                       targetProxy = C26AC0F1143BD02B001C98CE /* PBXContainerItemProxy */;
+               };
                C26AC70F0DAEB400005BFB40 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = C26AC7090DAEB3A7005BFB40 /* DTrace */;
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                BUILD_VARIANTS = debug;
-                               CURRENT_PROJECT_VERSION = 55005;
+                               CURRENT_PROJECT_VERSION = 55032;
                                EXECUTABLE_PREFIX = "";
                                EXECUTABLE_SUFFIX = "";
                                FRAMEWORK_SEARCH_PATHS = (
+                                       /System/Library/PrivateFrameworks,
                                        /usr/local/SecurityPieces/Frameworks,
                                        /usr/local/SecurityPieces/Components/Security,
                                );
                                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)";
                                PRIVATE_HEADERS_FOLDER_PATH = /usr/local/SecurityPieces/PrivateHeaders/Security;
                                PRODUCT_NAME = security_codesigning;
                                PUBLIC_HEADERS_FOLDER_PATH = /usr/local/SecurityPieces/Headers/Security;
+                               SKIP_INSTALL = YES;
                                VERSIONING_SYSTEM = "apple-generic";
                                WARNING_CFLAGS = (
                                        "-Wmost",
                                        normal,
                                        debug,
                                );
-                               CURRENT_PROJECT_VERSION = 55005;
+                               CURRENT_PROJECT_VERSION = 55032;
                                EXECUTABLE_PREFIX = "";
                                EXECUTABLE_SUFFIX = "";
                                FRAMEWORK_SEARCH_PATHS = (
+                                       /System/Library/PrivateFrameworks,
                                        /usr/local/SecurityPieces/Frameworks,
                                        /usr/local/SecurityPieces/Components/Security,
                                );
                                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)";
                                PRIVATE_HEADERS_FOLDER_PATH = /usr/local/SecurityPieces/PrivateHeaders/Security;
                                PRODUCT_NAME = security_codesigning;
                                PUBLIC_HEADERS_FOLDER_PATH = /usr/local/SecurityPieces/Headers/Security;
+                               SKIP_INSTALL = YES;
                                VERSIONING_SYSTEM = "apple-generic";
                                WARNING_CFLAGS = (
                                        "-Wmost",
                                        normal,
                                        debug,
                                );
-                               CURRENT_PROJECT_VERSION = 55005;
+                               CURRENT_PROJECT_VERSION = 55032;
                                EXECUTABLE_PREFIX = "";
                                EXECUTABLE_SUFFIX = "";
                                FRAMEWORK_SEARCH_PATHS = (
+                                       /System/Library/PrivateFrameworks,
                                        /usr/local/SecurityPieces/Frameworks,
                                        /usr/local/SecurityPieces/Components/Security,
                                );
                                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)";
                                PRIVATE_HEADERS_FOLDER_PATH = /usr/local/SecurityPieces/PrivateHeaders/Security;
                                PRODUCT_NAME = security_codesigning;
                                PUBLIC_HEADERS_FOLDER_PATH = /usr/local/SecurityPieces/Headers/Security;
+                               SKIP_INSTALL = YES;
                                VERSIONING_SYSTEM = "apple-generic";
                                WARNING_CFLAGS = (
                                        "-Wmost",
                        buildSettings = {
                                CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)";
                                CONFIGURATION_TEMP_DIR = "$(PROJECT_TEMP_DIR)";
+                               FRAMEWORK_SEARCH_PATHS = "";
+                               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)";
+                               FRAMEWORK_SEARCH_PATHS = "";
+                               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)";
+                               FRAMEWORK_SEARCH_PATHS = "";
+                               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;
                };
+               C26AC0ED143BCF01001C98CE /* Development */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                       };
+                       name = Development;
+               };
+               C26AC0EE143BCF01001C98CE /* Deployment */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                       };
+                       name = Deployment;
+               };
+               C26AC0EF143BCF01001C98CE /* Default */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                       };
+                       name = Default;
+               };
                C26AC70A0DAEB3A8005BFB40 /* Development */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                GCC_MODEL_TUNING = G5;
                                GCC_OPTIMIZATION_LEVEL = 0;
                                INSTALL_PATH = /usr/local/lib;
-                               PREBINDING = NO;
                                PRODUCT_NAME = integrity;
                                ZERO_LINK = YES;
                        };
                                FRAMEWORK_SEARCH_PATHS = /usr/local/SecurityPieces/Frameworks;
                                GCC_MODEL_TUNING = G5;
                                INSTALL_PATH = /usr/local/lib;
-                               PREBINDING = NO;
                                PRODUCT_NAME = integrity;
                                ZERO_LINK = NO;
                        };
                                FRAMEWORK_SEARCH_PATHS = /usr/local/SecurityPieces/Frameworks;
                                GCC_MODEL_TUNING = G5;
                                INSTALL_PATH = /usr/local/lib;
-                               PREBINDING = NO;
                                PRODUCT_NAME = integrity;
                                ZERO_LINK = YES;
                        };
                                        "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1)",
                                        "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1)",
                                );
-                               PREBINDING = NO;
                                PRODUCT_NAME = codehost;
                                ZERO_LINK = YES;
                        };
                                        "$(LIBRARY_SEARCH_PATHS_QUOTED_1)",
                                        "$(LIBRARY_SEARCH_PATHS_QUOTED_1)",
                                );
-                               PREBINDING = NO;
                                PRODUCT_NAME = codehost;
                                ZERO_LINK = NO;
                        };
                                        "$(LIBRARY_SEARCH_PATHS_QUOTED_1)",
                                        "$(LIBRARY_SEARCH_PATHS_QUOTED_1)",
                                );
-                               PREBINDING = NO;
                                PRODUCT_NAME = codehost;
                                ZERO_LINK = YES;
                        };
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Default;
                };
+               C26AC0EC143BCF01001C98CE /* Build configuration list for PBXAggregateTarget "SystemPolicy" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               C26AC0ED143BCF01001C98CE /* Development */,
+                               C26AC0EE143BCF01001C98CE /* Deployment */,
+                               C26AC0EF143BCF01001C98CE /* Default */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Default;
+               };
                C26AC70D0DAEB3C6005BFB40 /* Build configuration list for PBXAggregateTarget "DTrace" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
index 9e8843c8dc74ba14ee437c808579fe45dad422cd..f6972e7accbf38e8fe395def575e9de5aeb2d3ed 100644 (file)
@@ -129,6 +129,11 @@ options {
                        maker.put(slot);
                        CssmAutoData oid(Allocator::standard()); oid.fromOid(oids);
                        maker.putData(oid.data(), oid.length());
+               } else if (const char *oids = matchPrefix(key, "policy.")) {
+                       maker.put(opCertPolicy);
+                       maker.put(slot);
+                       CssmAutoData oid(Allocator::standard()); oid.fromOid(oids);
+                       maker.putData(oid.data(), oid.length());
                } else {
                        throw antlr::SemanticException(key + ": unrecognized certificate field");
                }
@@ -187,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()); }
        ;
@@ -235,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); }
        ;
 
 
@@ -257,6 +266,8 @@ appleanchor[Maker &maker]
                        { maker.put(opAppleAnchor); }
        |       "generic"
                        { maker.put(opAppleGenericAnchor); }
+|      |       { string name; } name=identifierString
+                       { maker.put(opNamedAnchor); maker.put(name); }
        ;
 
 certslotspec[Maker &maker, int32_t slot]       { string key; }