/* * Copyright (c) 2006-2007 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ // // 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; // 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(). static const SHA1::Digest &appleAnchorHash(); #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 // struct Requirement::Context { Context(CFArrayRef certChain, CFDictionaryRef infoDict, CFDictionaryRef entitlementDict, const CodeDirectory *dir) : certs(certChain), info(infoDict), entitlements(entitlementDict), directory(dir) { } const CFArrayRef certs; const CFDictionaryRef info; const CFDictionaryRef entitlements; const CodeDirectory * const directory; SecCertificateRef cert(int ix) const; // get a cert from the cert chain unsigned int certCount() const; // length of cert chain }; // // 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] 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; // // A helper to deal with the magic merger logic of internal requirements // class InternalRequirements : public Requirements::Maker { public: InternalRequirements() : mReqs(NULL) { } ~InternalRequirements() { ::free((void *)mReqs); } void operator () (const Requirements *given, const Requirements *defaulted); operator const Requirements * () const { return mReqs; } private: const Requirements *mReqs; }; } // CodeSigning // // Flipper overloads must go directly into the Security namespace // 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))); } } // Security #endif //_H_REQUIREMENT