]> git.saurik.com Git - apple/security.git/blob - libsecurity_codesigning/lib/requirement.cpp
Security-55163.44.tar.gz
[apple/security.git] / libsecurity_codesigning / lib / requirement.cpp
1 /*
2 * Copyright (c) 2006-2012 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 //
25 // requirement - Code Requirement Blob description
26 //
27 #include "requirement.h"
28 #include "reqinterp.h"
29 #include "codesigning_dtrace.h"
30 #include <security_utilities/errors.h>
31 #include <security_utilities/unix++.h>
32 #include <security_utilities/logging.h>
33 #include <security_utilities/cfutilities.h>
34 #include <security_utilities/hashing.h>
35
36 #ifdef DEBUGDUMP
37 #include <security_codesigning/reqdumper.h>
38 #endif
39
40 namespace Security {
41 namespace CodeSigning {
42
43
44 //
45 // The (SHA-1) hash of the canonical Apple certificate root anchor
46 //
47 static const SHA1::Digest gAppleAnchorHash =
48 { 0x61, 0x1e, 0x5b, 0x66, 0x2c, 0x59, 0x3a, 0x08, 0xff, 0x58,
49 0xd1, 0x4a, 0xe2, 0x24, 0x52, 0xd1, 0x98, 0xdf, 0x6c, 0x60 };
50
51
52 //
53 // Canonical names for requirement types
54 //
55 const char *const Requirement::typeNames[] = {
56 "invalid",
57 "host",
58 "guest",
59 "designated",
60 "library",
61 "plugin",
62 };
63
64
65 //
66 // validate a requirement against a code context
67 //
68 void Requirement::validate(const Requirement::Context &ctx, OSStatus failure /* = errSecCSReqFailed */) const
69 {
70 if (!this->validates(ctx, failure))
71 MacOSError::throwMe(failure);
72 }
73
74 bool Requirement::validates(const Requirement::Context &ctx, OSStatus failure /* = errSecCSReqFailed */) const
75 {
76 CODESIGN_EVAL_REQINT_START((void*)this, this->length());
77 switch (kind()) {
78 case exprForm:
79 if (Requirement::Interpreter(this, &ctx).evaluate()) {
80 CODESIGN_EVAL_REQINT_END(this, 0);
81 return true;
82 } else {
83 CODESIGN_EVAL_REQINT_END(this, failure);
84 return false;
85 }
86 default:
87 CODESIGN_EVAL_REQINT_END(this, errSecCSReqUnsupported);
88 MacOSError::throwMe(errSecCSReqUnsupported);
89 }
90 }
91
92
93 //
94 // Retrieve one certificate from the cert chain.
95 // Positive and negative indices can be used:
96 // [ leaf, intermed-1, ..., intermed-n, anchor ]
97 // 0 1 ... -2 -1
98 // Returns NULL if unavailable for any reason.
99 //
100 SecCertificateRef Requirement::Context::cert(int ix) const
101 {
102 if (certs) {
103 if (ix < 0)
104 ix += certCount();
105 if (ix >= CFArrayGetCount(certs))
106 return NULL;
107 if (CFTypeRef element = CFArrayGetValueAtIndex(certs, ix))
108 return SecCertificateRef(element);
109 }
110 return NULL;
111 }
112
113 unsigned int Requirement::Context::certCount() const
114 {
115 if (certs)
116 return CFArrayGetCount(certs);
117 else
118 return 0;
119 }
120
121
122 //
123 // Return the hash of the canonical Apple certificate root (anchor).
124 // In a special test mode, also return an alternate root hash for testing.
125 //
126 const SHA1::Digest &Requirement::appleAnchorHash()
127 {
128 return gAppleAnchorHash;
129 }
130
131 #if defined(TEST_APPLE_ANCHOR)
132
133 const char Requirement::testAppleAnchorEnv[] = "TEST_APPLE_ANCHOR";
134
135 const SHA1::Digest &Requirement::testAppleAnchorHash()
136 {
137 static bool tried = false;
138 static SHA1::Digest testHash;
139 if (!tried) {
140 // see if we have one configured
141 if (const char *path = getenv(testAppleAnchorEnv))
142 try {
143 UnixPlusPlus::FileDesc fd(path);
144 char buffer[2048]; // arbitrary limit
145 size_t size = fd.read(buffer, sizeof(buffer));
146 SHA1 hash;
147 hash(buffer, size);
148 hash.finish(testHash);
149 Syslog::alert("ACCEPTING TEST AUTHORITY %s FOR APPLE CODE IDENTITY", path);
150 } catch (...) { }
151 tried = true;
152 }
153 return testHash; // will be zeroes (no match) if not configured
154 }
155
156 #endif //TEST_APPLE_ANCHOR
157
158
159 //
160 // Debug dump support
161 //
162 #ifdef DEBUGDUMP
163
164 void Requirement::dump() const
165 {
166 Debug::dump("%s\n", Dumper::dump(this).c_str());
167 }
168
169 #endif //DEBUGDUMP
170
171
172 } // CodeSigning
173 } // Security