]> git.saurik.com Git - apple/libsecurity_codesigning.git/blob - lib/requirement.cpp
b1e136e198406ae4a45bf2a9c8d04f8a082f7018
[apple/libsecurity_codesigning.git] / lib / requirement.cpp
1 /*
2 * Copyright (c) 2006-2007 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 };
62
63
64 //
65 // validate a requirement against a code context
66 //
67 void Requirement::validate(const Requirement::Context &ctx, OSStatus failure /* = errSecCSReqFailed */) const
68 {
69 CODESIGN_EVAL_REQINT_START((void*)this, this->length());
70 switch (kind()) {
71 case exprForm:
72 if (Requirement::Interpreter(this, &ctx).evaluate()) {
73 CODESIGN_EVAL_REQINT_END(0);
74 return;
75 } else {
76 CODESIGN_EVAL_REQINT_END(failure);
77 MacOSError::throwMe(failure);
78 }
79 default:
80 CODESIGN_EVAL_REQINT_END(errSecCSReqUnsupported);
81 MacOSError::throwMe(errSecCSReqUnsupported);
82 }
83 }
84
85
86 //
87 // Retrieve one certificate from the cert chain.
88 // Positive and negative indices can be used:
89 // [ leaf, intermed-1, ..., intermed-n, anchor ]
90 // 0 1 ... -2 -1
91 // Returns NULL if unavailable for any reason.
92 //
93 SecCertificateRef Requirement::Context::cert(int ix) const
94 {
95 if (certs) {
96 if (ix < 0)
97 ix += certCount();
98 if (CFTypeRef element = CFArrayGetValueAtIndex(certs, ix))
99 return SecCertificateRef(element);
100 }
101 return NULL;
102 }
103
104 unsigned int Requirement::Context::certCount() const
105 {
106 if (certs)
107 return CFArrayGetCount(certs);
108 else
109 return 0;
110 }
111
112
113 //
114 // Return the hash of the canonical Apple certificate root (anchor).
115 // In a special test mode, also return an alternate root hash for testing.
116 //
117 const SHA1::Digest &Requirement::appleAnchorHash()
118 {
119 return gAppleAnchorHash;
120 }
121
122 #if defined(TEST_APPLE_ANCHOR)
123
124 const char Requirement::testAppleAnchorEnv[] = "TEST_APPLE_ANCHOR";
125
126 const SHA1::Digest &Requirement::testAppleAnchorHash()
127 {
128 static bool tried = false;
129 static SHA1::Digest testHash;
130 if (!tried) {
131 // see if we have one configured
132 if (const char *path = getenv(testAppleAnchorEnv))
133 try {
134 UnixPlusPlus::FileDesc fd(path);
135 char buffer[2048]; // arbitrary limit
136 size_t size = fd.read(buffer, sizeof(buffer));
137 SHA1 hash;
138 hash(buffer, size);
139 hash.finish(testHash);
140 Syslog::alert("ACCEPTING TEST AUTHORITY %s FOR APPLE CODE IDENTITY", path);
141 } catch (...) { }
142 tried = true;
143 }
144 return testHash; // will be zeroes (no match) if not configured
145 }
146
147 #endif //TEST_APPLE_ANCHOR
148
149
150 //
151 // InternalRequirements
152 //
153 void InternalRequirements::operator () (const Requirements *given, const Requirements *defaulted)
154 {
155 if (defaulted) {
156 this->add(defaulted);
157 ::free((void *)defaulted); // was malloc(3)ed by DiskRep
158 }
159 if (given)
160 this->add(given);
161 mReqs = make();
162 }
163
164
165 //
166 // Debug dump support
167 //
168 #ifdef DEBUGDUMP
169
170 void Requirement::dump() const
171 {
172 Debug::dump("%s\n", Dumper::dump(this).c_str());
173 }
174
175 #endif //DEBUGDUMP
176
177
178 } // CodeSigning
179 } // Security