]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 A |
1 | /* |
2 | * Copyright (c) 2000-2006 Apple Computer, 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 | // | |
26 | // acl_codesigning - ACL subject for signature of calling application | |
27 | // | |
28 | #include <security_cdsa_utilities/acl_codesigning.h> | |
29 | #include <security_cdsa_utilities/cssmdata.h> | |
30 | #include <security_utilities/endian.h> | |
31 | #include <algorithm> | |
32 | ||
33 | ||
34 | // | |
35 | // Code signature credentials are validated globally - they are entirely | |
36 | // a feature of "the" process (defined by the environment), and take no | |
37 | // samples whatsoever. | |
38 | // | |
39 | bool CodeSignatureAclSubject::validate(const AclValidationContext &context) const | |
40 | { | |
41 | // a suitable environment is required for a match | |
42 | if (Environment *env = context.environment<Environment>()) | |
43 | return env->verifyCodeSignature(*this, context); | |
44 | else | |
45 | return false; | |
46 | } | |
47 | ||
48 | ||
49 | // | |
50 | // Make a copy of this subject in CSSM_LIST form. | |
51 | // The format is (head), (type code: Wordid), (signature data: datum), (comment: datum) | |
52 | // | |
53 | CssmList CodeSignatureAclSubject::toList(Allocator &alloc) const | |
54 | { | |
55 | assert(path().find('\0') == string::npos); // no embedded nulls in path | |
56 | uint32_t type = CSSM_ACL_CODE_SIGNATURE_OSX; | |
57 | TypedList list(alloc, CSSM_ACL_SUBJECT_TYPE_CODE_SIGNATURE, | |
58 | new(alloc) ListElement(type), | |
59 | new(alloc) ListElement(alloc, CssmData::wrap(legacyHash(), SHA1::digestLength)), | |
60 | new(alloc) ListElement(alloc, CssmData::wrap(path().c_str(), path().size() + 1))); | |
61 | if (requirement()) { | |
62 | CFRef<CFDataRef> reqData; | |
63 | MacOSError::check(SecRequirementCopyData(requirement(), kSecCSDefaultFlags, &reqData.aref())); | |
64 | list += new(alloc) ListElement(alloc, | |
65 | CssmData::wrap(CFDataGetBytePtr(reqData), CFDataGetLength(reqData))); | |
66 | } | |
67 | for (AuxMap::const_iterator it = beginAux(); it != endAux(); it++) | |
68 | list += new(alloc) ListElement(alloc, CssmData(*it->second)); | |
69 | return list; | |
70 | } | |
71 | ||
72 | ||
73 | // | |
74 | // Create a CodeSignatureAclSubject | |
75 | // | |
76 | CodeSignatureAclSubject *CodeSignatureAclSubject::Maker::make(const TypedList &list) const | |
77 | { | |
78 | // there once was a format with only a hash (length 2+1). It is no longer supported | |
79 | unsigned total = list.length(); // includes subject type header | |
80 | if (total >= 3 + 1 | |
81 | && list[1].is(CSSM_LIST_ELEMENT_WORDID) // [1] == signature type | |
82 | && list[1] == CSSM_ACL_CODE_SIGNATURE_OSX | |
83 | && list[2].is(CSSM_LIST_ELEMENT_DATUM) // [2] == legacy hash | |
84 | && list[2].data().length() == SHA1::digestLength | |
85 | && list[3].is(CSSM_LIST_ELEMENT_DATUM)) { | |
86 | // structurally okay | |
87 | CodeSignatureAclSubject *subj = | |
88 | new CodeSignatureAclSubject(list[2].data().interpretedAs<const SHA1::Byte>(), | |
89 | list[3].data().interpretedAs<const char>()); | |
90 | for (unsigned n = 3 + 1; n < total; n++) { | |
91 | if (list[n].is(CSSM_LIST_ELEMENT_DATUM)) { | |
92 | const BlobCore *blob = list[n].data().interpretedAs<const BlobCore>(); | |
93 | if (blob->length() < sizeof(BlobCore)) { | |
94 | secdebug("csblob", "runt blob (0x%x/%zd) slot %d in CSSM_LIST", | |
95 | blob->magic(), blob->length(), n); | |
96 | CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE); | |
97 | } else if (blob->length() != list[n].data().length()) { | |
98 | secdebug("csblob", "badly sized blob (0x%x/%zd) slot %d in CSSM_LIST", | |
99 | blob->magic(), blob->length(), n); | |
100 | CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE); | |
101 | } | |
102 | subj->add(blob); | |
103 | } else | |
104 | CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE); | |
105 | } | |
106 | return subj; | |
107 | } else | |
108 | CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE); | |
109 | } | |
110 | ||
111 | CodeSignatureAclSubject *CodeSignatureAclSubject::Maker::make(Version version, | |
112 | Reader &pub, Reader &priv) const | |
113 | { | |
114 | assert(version == 0); | |
115 | Endian<uint32> sigType; pub(sigType); | |
116 | const void *data; size_t length; pub.countedData(data, length); | |
117 | const void *commentData; size_t commentLength; pub.countedData(commentData, commentLength); | |
118 | if (sigType == CSSM_ACL_CODE_SIGNATURE_OSX | |
119 | && length == SHA1::digestLength) { | |
120 | return make((const SHA1::Byte *)data, CssmData::wrap(commentData, commentLength)); | |
121 | } | |
122 | CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE); | |
123 | } | |
124 | ||
125 | CodeSignatureAclSubject *CodeSignatureAclSubject::Maker::make(const SHA1::Byte *hash, | |
126 | const CssmData &commentBag) const | |
127 | { | |
128 | using namespace LowLevelMemoryUtilities; | |
129 | const char *path = commentBag.interpretedAs<const char>(); | |
130 | CodeSignatureAclSubject *subj = new CodeSignatureAclSubject(hash, path); | |
131 | for (const BlobCore *blob = increment<BlobCore>(commentBag.data(), alignUp(strlen(path) + 1, commentBagAlignment)); | |
132 | blob < commentBag.end(); | |
133 | blob = increment<const BlobCore>(blob, alignUp(blob->length(), commentBagAlignment))) { | |
134 | size_t leftInBag = difference(commentBag.end(), blob); | |
135 | if (leftInBag < sizeof(BlobCore) || blob->length() < sizeof(BlobCore) || blob->length() > leftInBag) { | |
136 | secdebug("csblob", "invalid blob (0x%x/%zd) [%zd in bag] in code signing ACL for %s - stopping scan", | |
137 | blob->magic(), blob->length(), leftInBag, subj->path().c_str()); | |
138 | break; // can't trust anything beyond this blob | |
139 | } | |
140 | subj->add(blob); | |
141 | } | |
142 | return subj; | |
143 | } | |
144 | ||
145 | ||
146 | // | |
147 | // Export the subject to a memory blob | |
148 | // | |
149 | void CodeSignatureAclSubject::exportBlob(Writer::Counter &pub, Writer::Counter &priv) | |
150 | { | |
151 | using LowLevelMemoryUtilities::alignUp; | |
152 | assert(path().find('\0') == string::npos); // no embedded nulls in path | |
153 | Endian<uint32> sigType = CSSM_ACL_CODE_SIGNATURE_OSX; pub(sigType); | |
154 | pub.countedData(legacyHash(), SHA1::digestLength); | |
155 | size_t size = path().size() + 1; | |
156 | if (requirement()) { | |
157 | CFRef<CFDataRef> reqData; | |
158 | MacOSError::check(SecRequirementCopyData(requirement(), kSecCSDefaultFlags, &reqData.aref())); | |
159 | size = alignUp(size, commentBagAlignment) + CFDataGetLength(reqData); | |
160 | } | |
161 | for (AuxMap::const_iterator it = beginAux(); it != endAux(); it++) { | |
162 | size = alignUp(size, commentBagAlignment) + it->second->length(); | |
163 | } | |
164 | pub.countedData(NULL, size); | |
165 | } | |
166 | ||
167 | void CodeSignatureAclSubject::exportBlob(Writer &pub, Writer &priv) | |
168 | { | |
169 | using LowLevelMemoryUtilities::alignUp; | |
170 | Endian<uint32> sigType = CSSM_ACL_CODE_SIGNATURE_OSX; pub(sigType); | |
171 | pub.countedData(legacyHash(), SHA1::digestLength); | |
172 | CssmAutoData commentBag(Allocator::standard(), path().c_str(), path().size() + 1); | |
173 | static const uint32_t zero = 0; | |
174 | if (requirement()) { | |
175 | CFRef<CFDataRef> reqData; | |
176 | MacOSError::check(SecRequirementCopyData(requirement(), kSecCSDefaultFlags, &reqData.aref())); | |
177 | commentBag.append(&zero, | |
178 | alignUp(commentBag.length(), commentBagAlignment) - commentBag.length()); | |
179 | commentBag.append(CFDataGetBytePtr(reqData), CFDataGetLength(reqData)); | |
180 | } | |
181 | for (AuxMap::const_iterator it = beginAux(); it != endAux(); it++) { | |
182 | commentBag.append(&zero, | |
183 | alignUp(commentBag.length(), commentBagAlignment) - commentBag.length()); | |
184 | commentBag.append(CssmData(*it->second)); | |
185 | } | |
186 | pub.countedData(commentBag); | |
187 | } | |
188 | ||
189 | ||
190 | #ifdef DEBUGDUMP | |
191 | ||
192 | void CodeSignatureAclSubject::debugDump() const | |
193 | { | |
194 | Debug::dump("CodeSigning "); | |
195 | OSXVerifier::dump(); | |
196 | } | |
197 | ||
198 | #endif //DEBUGDUMP |