]> git.saurik.com Git - apple/security.git/blob - cdsa/cdsa_utilities/utilities.cpp
66ffb8b1a6e7df94df7cd365cdbc481228dc7576
[apple/security.git] / cdsa / cdsa_utilities / utilities.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 //
20 // Utilities
21 //
22 #include <Security/utilities.h>
23
24 #include <Security/cssmerrno.h>
25 #include <Security/debugging.h>
26 #include <typeinfo>
27 #include <stdio.h>
28
29
30 //
31 // The base of the exception hierarchy.
32 // Note that the debug output here depends on a particular
33 // implementation feature of gcc; to wit, that the exception object
34 // is created and then copied (at least once) via its copy constructor.
35 // If your compiler does not invoke the copy constructor, you won't get
36 // debug output, but nothing worse should happen.
37 //
38 CssmCommonError::CssmCommonError()
39 IFDEBUG(: mCarrier(true))
40 {
41 }
42
43 CssmCommonError::CssmCommonError(const CssmCommonError &source)
44 {
45 #if !defined(NDEBUG)
46 source.debugDiagnose(this);
47 mCarrier = source.mCarrier;
48 source.mCarrier = false;
49 #endif //NDEBUG
50 }
51
52 CssmCommonError::~CssmCommonError() throw ()
53 {
54 #if !defined(NDEBUG)
55 if (mCarrier)
56 secdebug("exception", "%p handled", this);
57 #endif //NDEBUG
58 }
59
60 OSStatus CssmCommonError::osStatus() const
61 { return cssmError(); }
62
63 int CssmCommonError::unixError() const
64 {
65 OSStatus err = osStatus();
66
67 // embedded UNIX errno values are returned verbatim
68 if (err >= errSecErrnoBase && err <= errSecErrnoLimit)
69 return err - errSecErrnoBase;
70
71 // re-map certain CSSM errors
72 switch (err) {
73 case CSSM_ERRCODE_MEMORY_ERROR:
74 return ENOMEM;
75 case CSSMERR_APPLEDL_DISK_FULL:
76 return ENOSPC;
77 case CSSMERR_APPLEDL_QUOTA_EXCEEDED:
78 return EDQUOT;
79 case CSSMERR_APPLEDL_FILE_TOO_BIG:
80 return EFBIG;
81 default:
82 // cannot map this to errno space
83 return -1;
84 }
85 }
86
87 CSSM_RETURN CssmCommonError::cssmError(CSSM_RETURN base) const
88 { return CssmError::merge(cssmError(), base); }
89
90 // default debugDiagnose gets what it can (virtually)
91 void CssmCommonError::debugDiagnose(const void *id) const
92 {
93 #if !defined(NDEBUG)
94 secdebug("exception", "%p %s %s/0x%lx osstatus %ld",
95 id, Debug::typeName(*this).c_str(),
96 cssmErrorString(cssmError()).c_str(), cssmError(),
97 osStatus());
98 #endif //NDEBUG
99 }
100
101
102 //
103 // CssmError exceptions
104 //
105 CssmError::CssmError(CSSM_RETURN err) : error(err) { }
106
107 const char *CssmError::what() const throw ()
108 { return "CSSM exception"; }
109
110 CSSM_RETURN CssmError::cssmError() const { return error; }
111
112 OSStatus CssmError::osStatus() const { return error; }
113
114 void CssmError::throwMe(CSSM_RETURN err) { throw CssmError(err); }
115
116
117 //
118 // UnixError exceptions
119 //
120 UnixError::UnixError() : error(errno) { }
121
122 UnixError::UnixError(int err) : error(err) { }
123
124 const char *UnixError::what() const throw ()
125 { return "UNIX error exception"; }
126
127 CSSM_RETURN UnixError::cssmError() const
128 {
129 // map some UNIX errors to well defined CSSM codes; embed the rest
130 switch (error) {
131 #if defined(ENOMEM)
132 case ENOMEM:
133 return CSSM_ERRCODE_MEMORY_ERROR;
134 #endif
135 #if defined(ENOSPC)
136 case ENOSPC:
137 return CSSMERR_APPLEDL_DISK_FULL;
138 #endif
139 #if defined(EDQUOT)
140 case EDQUOT:
141 return CSSMERR_APPLEDL_QUOTA_EXCEEDED;
142 #endif
143 #if defined(EFBIG)
144 case EFBIG:
145 return CSSMERR_APPLEDL_FILE_TOO_BIG;
146 #endif
147 default:
148 return errSecErrnoBase + error;
149 }
150 }
151
152 OSStatus UnixError::osStatus() const
153 { return error + errSecErrnoBase; }
154
155 int UnixError::unixError() const
156 { return error; }
157
158 void UnixError::throwMe(int err) { throw UnixError(err); }
159
160 // @@@ This is a hack for the Network protocol state machine
161 UnixError UnixError::make(int err) { return UnixError(err); }
162
163 #if !defined(NDEBUG)
164 void UnixError::debugDiagnose(const void *id) const
165 {
166 secdebug("exception", "%p UnixError %s (%d) osStatus %ld",
167 id, strerror(error), error, osStatus());
168 }
169 #endif //NDEBUG
170
171
172 //
173 // MacOSError exceptions
174 //
175 MacOSError::MacOSError(int err) : error(err) { }
176
177 const char *MacOSError::what() const throw ()
178 { return "MacOS error"; }
179
180 CSSM_RETURN MacOSError::cssmError() const
181 { return error; } // @@@ eventually...
182
183 OSStatus MacOSError::osStatus() const
184 { return error; }
185
186 void MacOSError::throwMe(int error)
187 { throw MacOSError(error); }
188
189
190 //
191 // Manage CSSM errors
192 //
193 CSSM_RETURN CssmError::merge(CSSM_RETURN error, CSSM_RETURN base)
194 {
195 if (0 < error && error < CSSM_ERRORCODE_COMMON_EXTENT) {
196 return base + error;
197 } else {
198 return error;
199 }
200 }
201
202
203 //
204 // CssmData out of line members
205 //
206 string CssmData::toString() const
207 {
208 return data() ?
209 string(reinterpret_cast<const char *>(data()), length())
210 :
211 string();
212 }
213
214
215 //
216 // GUID <-> string conversions.
217 // Note that we DO check for {} on input and insist on rigid formatting.
218 // We don't require a terminating null byte on input, but generate it on output.
219 //
220 char *Guid::toString(char buffer[stringRepLength+1]) const
221 {
222 sprintf(buffer, "{%8.8lx-%4.4x-%4.4x-",
223 (unsigned long)Data1, unsigned(Data2), unsigned(Data3));
224 for (int n = 0; n < 2; n++)
225 sprintf(buffer + 20 + 2*n, "%2.2x", Data4[n]);
226 buffer[24] = '-';
227 for (int n = 2; n < 8; n++)
228 sprintf(buffer + 21 + 2*n, "%2.2x", Data4[n]);
229 buffer[37] = '}';
230 buffer[38] = '\0';
231 return buffer;
232 }
233
234 Guid::Guid(const char *string)
235 {
236 // Arguably, we should be more flexible on input. But exactly what
237 // padding rules should we follow, and how should we try to interprete
238 // "doubtful" variations? Given that GUIDs are essentially magic
239 // cookies, everybody's better off if we just cut-and-paste them
240 // around the universe...
241 unsigned long d1;
242 unsigned int d2, d3;
243 if (sscanf(string, "{%lx-%x-%x-", &d1, &d2, &d3) != 3)
244 CssmError::throwMe(CSSM_ERRCODE_INVALID_GUID);
245 Data1 = d1; Data2 = d2; Data3 = d3;
246 // once, we did not expect the - after byte 2 of Data4
247 bool newForm = string[24] == '-';
248 for (int n = 0; n < 8; n++) {
249 unsigned int dn;
250 if (sscanf(string + 20 + 2*n + (newForm && n >= 2), "%2x", &dn) != 1)
251 CssmError::throwMe(CSSM_ERRCODE_INVALID_GUID);
252 Data4[n] = dn;
253 }
254 if (string[37 - !newForm] != '}')
255 CssmError::throwMe(CSSM_ERRCODE_INVALID_GUID);
256 }
257
258
259 //
260 // CssmSubserviceUids.
261 // Note that for comparison, we ignore the version field.
262 // This is not necessarily the Right Choice, but suits certain
263 // constraints in the Sec* layer. Perhaps we might reconsider
264 // this after a thorough code review to determine the intended
265 // (by the standard) semantics and proper use. Yeah, right.
266 //
267 CssmSubserviceUid::CssmSubserviceUid(const CSSM_GUID &guid,
268 const CSSM_VERSION *version, uint32 subserviceId, CSSM_SERVICE_TYPE subserviceType)
269 {
270 Guid = guid;
271 SubserviceId = subserviceId;
272 SubserviceType = subserviceType;
273 if (version)
274 Version = *version;
275 else
276 Version.Major = Version.Minor = 0;
277 }
278
279
280 bool CssmSubserviceUid::operator == (const CSSM_SUBSERVICE_UID &otherUid) const
281 {
282 const CssmSubserviceUid &other = CssmSubserviceUid::overlay(otherUid);
283 return subserviceId() == other.subserviceId()
284 && subserviceType() == other.subserviceType()
285 && guid() == other.guid();
286 }
287
288 bool CssmSubserviceUid::operator < (const CSSM_SUBSERVICE_UID &otherUid) const
289 {
290 const CssmSubserviceUid &other = CssmSubserviceUid::overlay(otherUid);
291 if (subserviceId() < other.subserviceId())
292 return true;
293 if (subserviceId() > other.subserviceId())
294 return false;
295 if (subserviceType() < other.subserviceType())
296 return true;
297 if (subserviceType() > other.subserviceType())
298 return false;
299 return guid() < other.guid();
300 }
301
302
303 //
304 // Methods for the CssmKey class
305 //
306 CssmKey::CssmKey(const CSSM_KEY &key)
307 {
308 KeyHeader = key.KeyHeader;
309 KeyData = key.KeyData;
310 }
311
312 CssmKey::CssmKey(const CSSM_DATA &keyData)
313 {
314 clearPod();
315 KeyData = keyData;
316 KeyHeader.HeaderVersion = CSSM_KEYHEADER_VERSION;
317 KeyHeader.BlobType = CSSM_KEYBLOB_RAW;
318 KeyHeader.Format = CSSM_KEYBLOB_RAW_FORMAT_NONE;
319 }
320
321 CssmKey::CssmKey(uint32 length, void *data)
322 {
323 clearPod();
324 KeyData = CssmData(data, length);
325 KeyHeader.HeaderVersion = CSSM_KEYHEADER_VERSION;
326 KeyHeader.BlobType = CSSM_KEYBLOB_RAW;
327 KeyHeader.Format = CSSM_KEYBLOB_RAW_FORMAT_NONE;
328 }
329
330 CryptoDataClass::~CryptoDataClass()
331 {
332 }
333
334 //
335 // Debug support
336 //
337 #if !defined(NDEBUG)
338
339 #endif //NDEBUG
340