/* * 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 #include #include #include #include "codedirectory.h" #include 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 { 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 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