2 * Copyright (c) 2000-2006,2011,2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 // acl_codesigning - ACL subject for signature of calling application
28 #include <security_cdsa_utilities/acl_codesigning.h>
29 #include <security_cdsa_utilities/cssmdata.h>
30 #include <security_utilities/endian.h>
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.
39 bool CodeSignatureAclSubject::validate(const AclValidationContext
&context
) const
41 // a suitable environment is required for a match
42 if (Environment
*env
= context
.environment
<Environment
>())
43 return env
->verifyCodeSignature(*this, context
);
50 // Make a copy of this subject in CSSM_LIST form.
51 // The format is (head), (type code: Wordid), (signature data: datum), (comment: datum)
53 CssmList
CodeSignatureAclSubject::toList(Allocator
&alloc
) const
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)));
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
)));
67 for (AuxMap::const_iterator it
= beginAux(); it
!= endAux(); it
++)
68 list
+= new(alloc
) ListElement(alloc
, CssmData(*it
->second
));
74 // Create a CodeSignatureAclSubject
76 CodeSignatureAclSubject
*CodeSignatureAclSubject::Maker::make(const TypedList
&list
) const
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
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
)) {
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
);
104 CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE
);
108 CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE
);
111 CodeSignatureAclSubject
*CodeSignatureAclSubject::Maker::make(Version version
,
112 Reader
&pub
, Reader
&priv
) const
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
));
122 CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE
);
125 CodeSignatureAclSubject
*CodeSignatureAclSubject::Maker::make(const SHA1::Byte
*hash
,
126 const CssmData
&commentBag
) const
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
147 // Export the subject to a memory blob
149 void CodeSignatureAclSubject::exportBlob(Writer::Counter
&pub
, Writer::Counter
&priv
)
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;
157 CFRef
<CFDataRef
> reqData
;
158 MacOSError::check(SecRequirementCopyData(requirement(), kSecCSDefaultFlags
, &reqData
.aref()));
159 size
= alignUp(size
, commentBagAlignment
) + CFDataGetLength(reqData
);
161 for (AuxMap::const_iterator it
= beginAux(); it
!= endAux(); it
++) {
162 size
= alignUp(size
, commentBagAlignment
) + it
->second
->length();
164 pub
.countedData(NULL
, size
);
167 void CodeSignatureAclSubject::exportBlob(Writer
&pub
, Writer
&priv
)
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;
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
));
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
));
186 pub
.countedData(commentBag
);
192 void CodeSignatureAclSubject::debugDump() const
194 Debug::dump("CodeSigning ");