2 * Copyright (c) 2000-2006,2011-2012,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 // context - CSSM cryptographic context objects
31 #include <security_utilities/utilities.h>
32 #include <security_utilities/debugging.h>
33 #include <security_cdsa_utilities/cssmalloc.h>
34 #include <security_cdsa_utilities/cssmwalkers.h>
35 #include <security_cdsa_utilities/cssmacl.h> // to serialize/copy access credentials
36 #include <security_cdsa_utilities/cssmdates.h>
42 // Context is a POD overlay for the CSSM_CONTEXT type. It does
43 // add allocation functions and lots of good stuff.
44 // Note that if you're outside CSSM proper, you are not supposed to
45 // memory-manage Context structures on your own. Be a good boy and
46 // call the CSSM API functions.
47 // We also provide a POD overlay for CSSM_CONTEXT_ATTRIBUTE, with
48 // the obvious semantics.
50 class Context
: public PodWrapper
<Context
, CSSM_CONTEXT
> {
52 Context(CSSM_CONTEXT_TYPE type
, CSSM_ALGORITHMS algorithmId
);
54 uint32
attributesInUse() const { return NumberOfAttributes
; }
55 CSSM_CONTEXT_TYPE
type() const { return ContextType
; }
56 CSSM_ALGORITHMS
algorithm() const { return AlgorithmType
; }
57 CSSM_CSP_HANDLE
cspHandle() const { return CSPHandle
; }
59 void deleteAttribute(CSSM_ATTRIBUTE_TYPE type
);
60 size_t copyAttributes(CSSM_CONTEXT_ATTRIBUTE
* &attrs
, uint32
&count
, Allocator
&alloc
) const;
62 void copyFrom(const Context
&source
, Allocator
&alloc
)
63 { source
.copyAttributes(ContextAttributes
, NumberOfAttributes
, alloc
); }
66 class Attr
: public PodWrapper
<Attr
, CSSM_CONTEXT_ATTRIBUTE
> {
69 Attr(const CSSM_CONTEXT_ATTRIBUTE
&attr
) { (CSSM_CONTEXT_ATTRIBUTE
&)*this = attr
; }
72 Attr(CSSM_ATTRIBUTE_TYPE typ
, T
&value
, size_t size
= 0)
75 // attribute component pointers are stupidly non-const; allow const input
76 Attribute
.String
= const_cast<char *>(reinterpret_cast<const char *>(&value
));
77 AttributeLength
= (uint32_t) (size
? size
: sizeof(T
));
80 Attr(CSSM_ATTRIBUTE_TYPE typ
, uint32 value
)
83 Attribute
.Uint32
= value
;
87 CSSM_ATTRIBUTE_TYPE
type() const { return AttributeType
; }
88 uint32
baseType() const { return AttributeType
& CSSM_ATTRIBUTE_TYPE_MASK
; }
90 operator char * () const
91 { assert(baseType() == CSSM_ATTRIBUTE_DATA_STRING
); return Attribute
.String
; }
92 operator CssmData
& () const
93 { assert(baseType() == CSSM_ATTRIBUTE_DATA_CSSM_DATA
);
94 return CssmData::overlay(*Attribute
.Data
); }
95 operator CssmCryptoData
& () const
96 { assert(baseType() == CSSM_ATTRIBUTE_DATA_CRYPTO_DATA
);
97 return CssmCryptoData::overlay(*Attribute
.CryptoData
); }
98 operator CssmKey
& () const
99 { assert(baseType() == CSSM_ATTRIBUTE_DATA_KEY
); return CssmKey::overlay(*Attribute
.Key
); }
100 operator AccessCredentials
& () const
101 { assert(baseType() == CSSM_ATTRIBUTE_DATA_ACCESS_CREDENTIALS
);
102 return AccessCredentials::overlay(*Attribute
.AccessCredentials
); }
103 operator uint32 () const
104 { assert(baseType() == CSSM_ATTRIBUTE_DATA_UINT32
); return Attribute
.Uint32
; }
105 operator CSSM_DL_DB_HANDLE
&() const
107 assert(baseType() == CSSM_ATTRIBUTE_DATA_DL_DB_HANDLE
);
108 if (Attribute
.DLDBHandle
== NULL
)
109 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_DL_DB_HANDLE
);
110 return *Attribute
.DLDBHandle
;
112 operator CssmDate
& () const
113 { assert(baseType() == CSSM_ATTRIBUTE_DATA_DATE
);
114 return CssmDate::overlay(*Attribute
.Date
); }
115 // @@@ etc. etc. - add yours today!
117 void operator = (uint32 value
) { Attribute
.Uint32
= value
; }
119 void operator = (T
*ptr
) { Attribute
.String
= reinterpret_cast<char *>(ptr
); }
121 IFDUMP(void dump() const;) // debug dump this Attr to stdout (one line)
124 // Attributes by position
125 Attr
*attributes() const { return Attr::overlay(ContextAttributes
); }
126 Attr
&operator [] (unsigned int ix
)
127 { assert(ix
< NumberOfAttributes
); return static_cast<Attr
&>(ContextAttributes
[ix
]); }
128 const Attr
&operator [] (unsigned int ix
) const
129 { assert(ix
< NumberOfAttributes
); return static_cast<Attr
&>(ContextAttributes
[ix
]); }
131 // general attribute retrieval by type
132 Attr
*find(CSSM_ATTRIBUTE_TYPE theType
) const
133 { return find(theType
, ContextAttributes
, NumberOfAttributes
); }
135 template <class Elem
>
136 Elem
&get(CSSM_ATTRIBUTE_TYPE type
, CSSM_RETURN err
) const
138 if (Attr
*attr
= find(type
))
139 return static_cast<Elem
&>(*attr
);
141 CssmError::throwMe(err
);
144 template <class Elem
>
145 Elem
*get(CSSM_ATTRIBUTE_TYPE type
) const
147 if (Attr
*attr
= find(type
))
148 // @@@ Invoking conversion operator to Elem & on *attr and taking address of result.
149 return &static_cast<Elem
&>(*attr
);
154 uint32
getInt(CSSM_ATTRIBUTE_TYPE type
, CSSM_RETURN err
) const
156 if (Attr
*attr
= find(type
))
157 return static_cast<uint32
>(*attr
);
159 CssmError::throwMe(err
);
162 uint32
getInt(CSSM_ATTRIBUTE_TYPE type
) const
164 if (Attr
*attr
= find(type
))
165 return static_cast<uint32
>(*attr
);
170 bool getInt(CSSM_ATTRIBUTE_TYPE type
, uint32
&value
) const
172 if (Attr
*attr
= find(type
)) {
173 value
= static_cast<uint32
>(*attr
);
181 void replace(CSSM_ATTRIBUTE_TYPE type
, const T
&newValue
) const
183 if (Attr
*attr
= find(type
))
184 *attr
= Attr(type
, newValue
);
186 CssmError::throwMe(CSSMERR_CSSM_ATTRIBUTE_NOT_IN_CONTEXT
);
190 void *operator new (size_t size
, Allocator
&alloc
)
191 { return alloc
.malloc(size
); }
192 void operator delete (void *addr
, size_t, Allocator
&alloc
) _NOEXCEPT
193 { return alloc
.free(addr
); }
194 static void destroy(Context
*context
, Allocator
&alloc
) _NOEXCEPT
195 { alloc
.free(context
->ContextAttributes
); alloc
.free(context
); }
198 // Post-IPC context fixup.
199 // This can only be called on a Built Context after IPC transmission.
200 void postIPC(void *base
, CSSM_CONTEXT_ATTRIBUTE
*ipcAttributes
);
205 // dump to stdout, multiline format
206 IFDUMP(void dump(const char *title
= NULL
,
207 const CSSM_CONTEXT_ATTRIBUTE
*attrs
= NULL
) const;)
210 // find an attribute in a plain array of attribute structures (no context)
211 static Attr
*find(CSSM_ATTRIBUTE_TYPE theType
,
212 const CSSM_CONTEXT_ATTRIBUTE
*attrs
, unsigned int count
);
216 namespace DataWalkers
{
219 template <class Action
>
220 void walk(Action
&operate
, CSSM_CONTEXT_ATTRIBUTE
&attr
)
223 if (attr
.Attribute
.String
) // non-NULL pointer (imprecise but harmless)
224 switch (attr
.AttributeType
& CSSM_ATTRIBUTE_TYPE_MASK
) {
225 case CSSM_ATTRIBUTE_DATA_CSSM_DATA
:
226 walk(operate
, attr
.Attribute
.Data
); break;
227 case CSSM_ATTRIBUTE_DATA_CRYPTO_DATA
:
228 walk(operate
, attr
.Attribute
.CryptoData
); break;
229 case CSSM_ATTRIBUTE_DATA_KEY
:
230 walk(operate
, attr
.Attribute
.Key
); break;
231 case CSSM_ATTRIBUTE_DATA_STRING
:
232 walk(operate
, attr
.Attribute
.String
); break;
233 case CSSM_ATTRIBUTE_DATA_DATE
:
234 walk(operate
, attr
.Attribute
.Date
); break;
235 case CSSM_ATTRIBUTE_DATA_RANGE
:
236 walk(operate
, attr
.Attribute
.Range
); break;
237 case CSSM_ATTRIBUTE_DATA_ACCESS_CREDENTIALS
:
238 walk(operate
, attr
.Attribute
.AccessCredentials
); break;
239 case CSSM_ATTRIBUTE_DATA_VERSION
:
240 walk(operate
, attr
.Attribute
.Version
); break;
241 case CSSM_ATTRIBUTE_DATA_DL_DB_HANDLE
:
242 walk(operate
, attr
.Attribute
.DLDBHandle
); break;
243 case CSSM_ATTRIBUTE_NONE
:
244 case CSSM_ATTRIBUTE_DATA_UINT32
:
247 secinfo("walkers", "invalid attribute (%ux) in context", (unsigned)attr
.AttributeType
);
252 template <class Action
>
253 void walk(Action
&operate
, Context::Attr
&attr
)
255 walk(operate
, static_cast<CSSM_CONTEXT_ATTRIBUTE
&>(attr
));
258 } // end namespace DataWalkers
262 // Context::Builder - make context attributes the fun way.
264 // A Context (aka CSSM_CONTEXT) has a pointer to an array of context attributes,
265 // most of which contain pointers to other stuff with pointers to God Knows Where.
266 // Instead of allocating this all over the heap, a Context::Builder performs
267 // a two-pass algorithm that places all that stuff into a single heap node.
268 // Specifically, the builder will allocate and create a vector of CSSM_CONTEXT_ATTRIBUTE
269 // structures and all their subordinate heap storage.
270 // A Builder does not deal in Context objects and does not care what you do with your
271 // CSSM_CONTEXT_ATTRIBUTE array once it's delivered. Since it's a single heap node,
272 // you can just free() it using the appropriate allocator when you're done with it.
274 // Theory of operation:
275 // Builder works in two phases, called scan and build. During scan, you call setup()
276 // with the desired data to be placed into the attribute vector. When done, call make()
277 // to switch to build phase. Then call put() with the SAME sequence of values as in phase 1.
278 // Finally, call done() to receive the pointer-and-count values.
279 // @@@ Add comment about IPC use.
281 using namespace DataWalkers
;
283 class Context::Builder
{
286 Builder(Allocator
&alloc
) : allocator(alloc
)
287 { slotCount
= 0; attributes
= NULL
; }
288 ~Builder() { allocator
.free(attributes
); }
290 Allocator
&allocator
;
292 // switch to build phase
295 void done(CSSM_CONTEXT_ATTRIBUTE
* &attributes
, uint32
&count
);
299 // Phase 1 (scan) dispatch. Call once for each attribute needed.
302 void setup(T p
, CSSM_RETURN invalidError
= CSSM_OK
)
306 walk(sizer
, unconst_ref_cast(p
));
307 } else if (invalidError
)
308 CssmError::throwMe(invalidError
);
311 void setup(uint32 n
, CSSM_RETURN invalidError
= CSSM_OK
)
315 else if (invalidError
)
316 CssmError::throwMe(invalidError
);
319 void setup(CSSM_SIZE n
, CSSM_RETURN invalidError
= CSSM_OK
)
323 else if (invalidError
)
324 CssmError::throwMe(invalidError
);
327 void setup(const CSSM_KEY
*k
, CSSM_RETURN invalidError
= CSSM_OK
)
332 walk(sizer
, unconst_ref_cast(k
));
334 return; // no additional validation performed
336 // perform a basic sanity check of the input CSSM_KEY
337 if (!(k
) || (k
->KeyHeader
.HeaderVersion
> CSSM_KEYHEADER_VERSION
)) {
338 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_REFERENCE
);
340 // must not point to an odd address or NULL
341 if (!(k
->KeyData
.Data
) || ((uint64_t)k
->KeyData
.Data
& (uint64_t)1)) {
342 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_POINTER
);
344 // simplistic key data length check
345 if ((k
->KeyData
.Length
< 4) || (k
->KeyData
.Length
> 32768)) {
346 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT
);
349 walk(sizer
, unconst_ref_cast(k
));
352 // dynamic attribute type
353 void setup(const CSSM_CONTEXT_ATTRIBUTE
&attr
)
354 { slotCount
++; walk(sizer
, const_cast<CSSM_CONTEXT_ATTRIBUTE
&>(attr
)); }
355 void setup(const Context::Attr
&attr
) { setup(static_cast<const CSSM_CONTEXT_ATTRIBUTE
&>(attr
)); }
358 // Phase 2 (copy) dispatch. Call once for each attribute, in same order as setup().
361 void put(CSSM_ATTRIBUTE_TYPE type
, const T
*p
)
364 assert(slot
< slotCount
); // check overflow
365 Attr
&attribute
= attributes
[slot
++];
366 attribute
.AttributeType
= type
;
367 attribute
.AttributeLength
= (uint32
)size(p
); //@@@ needed? how/when/what for?
368 T
*tmp
= const_cast<T
*>(p
);
369 attribute
= walk(copier
, tmp
);
372 void put(CSSM_ATTRIBUTE_TYPE type
, uint32 value
)
375 assert(slot
< slotCount
); // check overflow
376 Attr
&attribute
= attributes
[slot
++];
377 attribute
.AttributeType
= type
;
378 attribute
.AttributeLength
= 0; //@@@ unclear what that should be
379 attribute
= value
; // no heap data (immediate value)
382 void put(const CSSM_CONTEXT_ATTRIBUTE
&attr
)
384 assert(slot
< slotCount
);
385 Attr
&attribute
= attributes
[slot
++];
386 attribute
= attr
; // shallow copy
387 walk(copier
, attribute
); // deep copy
389 void put(const Context::Attr
&attr
) { put(static_cast<const CSSM_CONTEXT_ATTRIBUTE
&>(attr
)); }
392 // pass 1 state: collect sizes and counts
393 unsigned slotCount
; // count of attribute slots in use
394 SizeWalker sizer
; // memory size calculator
396 // pass 2 state: build the data set
397 Context::Attr
*attributes
; // attribute vector and start of block
398 CopyWalker copier
; // data copy engine
399 uint32 slot
; // writer slot position
402 } // end namespace Security