]> git.saurik.com Git - apple/security.git/blobdiff - Security/libsecurity_codesigning/lib/requirement.h
Security-57031.1.35.tar.gz
[apple/security.git] / Security / libsecurity_codesigning / lib / requirement.h
diff --git a/Security/libsecurity_codesigning/lib/requirement.h b/Security/libsecurity_codesigning/lib/requirement.h
new file mode 100644 (file)
index 0000000..c6e46bf
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2006-2012 Apple Inc. All Rights Reserved.
+ * 
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+//
+// requirement - Code Requirement Blob description
+//
+#ifndef _H_REQUIREMENT
+#define _H_REQUIREMENT
+
+#include <security_utilities/blob.h>
+#include <security_utilities/superblob.h>
+#include <security_utilities/hashing.h>
+#include <Security/CodeSigning.h>
+#include "codedirectory.h"
+#include <map>
+
+namespace Security {
+namespace CodeSigning {
+
+
+//
+// Single requirement.
+// This is a contiguous binary blob, starting with this header
+// and followed by binary expr-code. All links within the blob
+// are offset-relative to the start of the header.
+// This is designed to be a binary stable format. Note that we restrict
+// outselves to 4GB maximum size (4 byte size/offset), and we expect real
+// Requirement blobs to be fairly small (a few kilobytes at most).
+//
+// The "kind" field allows for adding different kinds of Requirements altogether
+// in the future. We expect to stay within the framework of "opExpr" requirements,
+// but it never hurts to have a way out.
+//
+class Requirement: public Blob<Requirement, 0xfade0c00> {
+public:        
+       class Maker;                            // makes Requirement blobs
+       class Context;                          // evaluation context
+       class Reader;                           // structured reader
+       class Interpreter;                      // evaluation engine
+
+       // different forms of Requirements. Right now, we only support exprForm ("opExprs")
+       enum Kind {
+               exprForm = 1                    // prefix expr form
+       };
+       
+       void kind(Kind k) { mKind = k; }
+       Kind kind() const { return Kind(uint32_t(mKind)); }
+       
+       // validate this requirement against a code context
+       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)
+       static const int anchorCert = -1;       // index for anchor (last in chain)
+       
+       // the SHA1 hash of the canonical "Apple Anchor", i.e. the X509 Anchor
+       // that is considered "Apple's anchor certificate", as defined by hashOfCertificate().
+#if defined(TEST_APPLE_ANCHOR)
+       static const char testAppleAnchorEnv[];
+       static const SHA1::Digest &testAppleAnchorHash();
+#endif //TEST_APPLE_ANCHOR
+       
+       // common alignment rule for all requirement forms
+       static const size_t baseAlignment = sizeof(uint32_t); // (we might as well say "four")
+       
+    // canonical (source) names of Requirement types (matched to SecRequirementType in CSCommon.h)
+    static const char *const typeNames[];
+       
+       IFDUMP(void dump() const);
+
+private:
+       Endian<uint32_t> mKind;                 // expression kind
+};
+
+
+//
+// An interpretation context
+//
+class Requirement::Context {
+protected:
+       Context()
+               : certs(NULL), info(NULL), entitlements(NULL), identifier(""), directory(NULL) { }
+
+public:
+       Context(CFArrayRef certChain, CFDictionaryRef infoDict, CFDictionaryRef entitlementDict,
+                       const std::string &ident, const CodeDirectory *dir)
+               : certs(certChain), info(infoDict), entitlements(entitlementDict), identifier(ident), directory(dir) { }
+
+       CFArrayRef certs;                                                               // certificate chain
+       CFDictionaryRef info;                                                   // Info.plist
+       CFDictionaryRef entitlements;                                   // entitlement plist
+       std::string identifier;                                         // signing identifier
+       const CodeDirectory *directory;                         // CodeDirectory
+
+       SecCertificateRef cert(int ix) const;                   // get a cert from the cert chain (NULL if not found)
+       unsigned int certCount() const;                         // length of cert chain (including root)
+};
+
+
+//
+// exprForm opcodes.
+//
+// Opcodes are broken into flags in the (HBO) high byte, and an opcode value
+// in the remaining 24 bits. Note that opcodes will remain fairly small
+// (almost certainly <60000), so we have the third byte to play around with
+// in the future, if needed. For now, small opcodes effective reserve this byte
+// as zero.
+// The flag byte allows for limited understanding of unknown opcodes. It allows
+// the interpreter to use the known opcode parts of the program while semi-creatively
+// disregarding the parts it doesn't know about. An unrecognized opcode with zero
+// flag byte causes evaluation to categorically fail, since the semantics of such
+// an opcode cannot safely be predicted.
+//
+enum {
+       // semantic bits or'ed into the opcode
+       opFlagMask =     0xFF000000,    // high bit flags
+       opGenericFalse = 0x80000000,    // has size field; okay to default to false
+       opGenericSkip =  0x40000000,    // has size field; skip and continue
+};
+
+enum ExprOp {
+       opFalse,                                                // unconditionally false
+       opTrue,                                                 // unconditionally true
+       opIdent,                                                // match canonical code [string]
+       opAppleAnchor,                                  // signed by Apple as Apple's product
+       opAnchorHash,                                   // match anchor [cert hash]
+       opInfoKeyValue,                                 // *legacy* - use opInfoKeyField [key; value]
+       opAnd,                                                  // binary prefix expr AND expr [expr; expr]
+       opOr,                                                   // binary prefix expr OR expr [expr; expr]
+       opCDHash,                                               // match hash of CodeDirectory directly [cd hash]
+       opNot,                                                  // logical inverse [expr]
+       opInfoKeyField,                                 // Info.plist key field [string; match suffix]
+       opCertField,                                    // Certificate field [cert index; field name; match suffix]
+       opTrustedCert,                                  // require trust settings to approve one particular cert [cert index]
+       opTrustedCerts,                                 // require trust settings to approve the cert chain
+       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)
+};
+
+// match suffix opcodes
+enum MatchOperation {
+       matchExists,                                    // anything but explicit "false" - no value stored
+       matchEqual,                                             // equal (CFEqual)
+       matchContains,                                  // partial match (substring)
+       matchBeginsWith,                                // partial match (initial substring)
+       matchEndsWith,                                  // partial match (terminal substring)
+       matchLessThan,                                  // less than (string with numeric comparison)
+       matchGreaterThan,                               // greater than (string with numeric comparison)
+       matchLessEqual,                                 // less or equal (string with numeric comparison)
+       matchGreaterEqual,                              // greater or equal (string with numeric comparison)
+};
+
+
+//
+// We keep Requirement groups in SuperBlobs, indexed by SecRequirementType
+//
+typedef SuperBlob<0xfade0c01> Requirements;
+
+
+//
+// Byte order flippers
+//
+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