1 /*===========================================================================
2 *
3 * PUBLIC DOMAIN NOTICE
4 * National Center for Biotechnology Information
5 *
6 * This software/database is a "United States Government Work" under the
7 * terms of the United States Copyright Act. It was written as part of
8 * the author's official duties as a United States Government employee and
9 * thus cannot be copyrighted. This software/database is freely available
10 * to the public for use. The National Library of Medicine and the U.S.
11 * Government have not placed any restriction on its use or reproduction.
12 *
13 * Although all reasonable efforts have been taken to ensure the accuracy
14 * and reliability of the software and data, the NLM and the U.S.
15 * Government do not and cannot warrant the performance or results that
16 * may be obtained by using this software or data. The NLM and the U.S.
17 * Government disclaim all warranties, express or implied, including
18 * warranties of performance, merchantability or fitness for any particular
19 * purpose.
20 *
21 * Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26
27 #define USE_AES_NI false
28
29 #include <krypto/extern.h>
30 #include <krypto/ciphermgr.h>
31 #include <krypto/cipher.h>
32
33 #include "cipher-priv.h"
34
35 #include <kproc/lock.h>
36
37 #include <klib/rc.h>
38 #include <klib/refcount.h>
39 #include <klib/debug.h>
40
41 #include <sysalloc.h>
42
43 #include <atomic.h>
44
45 #include <stdlib.h>
46 #include <assert.h>
47
48 #ifdef _DEBUGGING
49 #define MGR_DEBUG(msg) DBGMSG(DBG_KFS,DBG_FLAG(DBG_KFS_MGR), msg)
50 #else
51 #define MGR_DEBUG(msg)
52 #endif
53
54
55
56 static const char kciphermanager_classname [] = "KCipherManager";
57
58
59 /*--------------------------------------------------------------------------
60 * KCipherManager
61 */
62 /* currently expected to be a singleton and not use a vtable but
63 * be fully fleshed out here */
64 static atomic_ptr_t singleton;
65 /*static KCipherManager * singleton = NULL;*/
66
67 struct KCipherManager
68 {
69 KRefcount refcount;
70
71 KLock * lock;
72
73 };
74
75
76 static
KCipherManagerAlloc(KCipherManager ** ppobj)77 rc_t KCipherManagerAlloc (KCipherManager ** ppobj)
78 {
79 KCipherManager * pobj;
80
81 assert (ppobj);
82
83 pobj = calloc (sizeof *pobj, 1);
84 if (pobj)
85 {
86 *ppobj = pobj;
87 return 0;
88 }
89
90 *ppobj = NULL;
91 return RC (rcKrypto, rcMgr, rcConstructing, rcMemory, rcExhausted);
92 }
93
94
95 static
KCipherManagerInit(KCipherManager * self)96 rc_t KCipherManagerInit (KCipherManager * self)
97 {
98 rc_t rc;
99
100 rc = KLockMake (&self->lock);
101 if (rc == 0)
102 {
103 KRefcountInit (&self->refcount, 1, kciphermanager_classname, "init",
104 "singleton");
105 }
106
107 return rc;
108 }
109
110
111 /* Destroy
112 * destroy
113 */
KCipherManagerDestroy(KCipherManager * self)114 LIB_EXPORT rc_t CC KCipherManagerDestroy ( KCipherManager *self )
115 {
116 rc_t rc = 0;
117
118 if ( self == NULL )
119 rc = RC ( rcKrypto, rcMgr, rcDestroying, rcSelf, rcNull );
120 else
121 {
122 if (self == singleton . ptr)
123 {
124 KCipherManager * reread;
125
126 reread = atomic_test_and_set_ptr (&singleton, NULL, self);
127
128 /* ignore results: just going for guaranteed atomicity though might not need it */
129 ( void ) reread;
130 }
131
132 /* no return value */
133 KRefcountWhack (&self->refcount, kciphermanager_classname);
134
135 rc = KLockRelease (self->lock);
136
137 free (self);
138 }
139 return rc;
140 }
141
142
143 /* AddRef
144 * creates a new reference
145 * ignores NULL references
146 */
KCipherManagerAddRef(const KCipherManager * self)147 LIB_EXPORT rc_t CC KCipherManagerAddRef ( const KCipherManager *self )
148 {
149 if (self != NULL)
150 {
151 switch (KRefcountAdd (&self->refcount, kciphermanager_classname))
152 {
153 case krefOkay:
154 break;
155 case krefZero:
156 return RC (rcFS, rcMgr, rcAttaching, rcRefcount, rcIncorrect);
157 case krefLimit:
158 return RC (rcFS, rcMgr, rcAttaching, rcRefcount, rcExhausted);
159 case krefNegative:
160 return RC (rcFS, rcMgr, rcAttaching, rcRefcount, rcInvalid);
161 default:
162 return RC (rcFS, rcMgr, rcAttaching, rcRefcount, rcUnknown);
163 }
164 }
165 return 0;
166 }
167
168
169 /* Release
170 * discard reference to manager
171 * ignores NULL references
172 */
KCipherManagerRelease(const KCipherManager * self)173 LIB_EXPORT rc_t CC KCipherManagerRelease ( const KCipherManager *self )
174 {
175 rc_t rc = 0;
176 if (self != NULL)
177 {
178 switch (KRefcountDrop (&self->refcount, kciphermanager_classname))
179 {
180 case krefOkay:
181 case krefZero:
182 break;
183 case krefWhack:
184 rc = KCipherManagerDestroy ((KCipherManager*)self);
185 break;
186 case krefNegative:
187 return RC (rcFS, rcMgr, rcAttaching, rcRefcount, rcInvalid);
188 default:
189 rc = RC (rcFS, rcMgr, rcAttaching, rcRefcount, rcUnknown);
190 break;
191 }
192 }
193 return rc;
194 }
195
196
197 /* Make
198 * we have a shared singleton for the cipher manager
199 * first call actually makes the managerblo
200 * subsequent calls get added references
201 */
KCipherManagerMake(KCipherManager ** mgr)202 LIB_EXPORT rc_t CC KCipherManagerMake (KCipherManager ** mgr)
203 {
204 rc_t rc = 0;
205
206 if (mgr == NULL)
207 return RC (rcKrypto, rcMgr, rcConstructing, rcSelf, rcNull);
208
209 *mgr = NULL;
210
211 make_race_retry:
212
213 if (singleton . ptr)
214 {
215 rc = KCipherManagerAddRef (singleton.ptr);
216 if (rc == 0)
217 {
218 *mgr = singleton . ptr;
219 return 0;
220 }
221 }
222 else
223 {
224 KCipherManager * self;
225
226 rc = KCipherManagerAlloc (&self);
227 if (rc == 0)
228 {
229 rc = KCipherManagerInit (self);
230 if (rc == 0)
231 {
232 KCipherManager * reread;
233
234 reread = atomic_test_and_set_ptr (&singleton, self, NULL);
235
236 if (reread)
237 {
238 KCipherManagerDestroy (self);
239 goto make_race_retry;
240 }
241
242 *mgr = self;
243 return 0;
244 }
245 else
246 {
247 KCipherManagerDestroy (self);
248 }
249 }
250 }
251 return rc;
252 }
253
254
255 static __inline__
KCipherManagerMakeCipherInt(const KCipherManager * self,KCipher ** pcipher,kcipher_type type)256 rc_t KCipherManagerMakeCipherInt (const KCipherManager *self,
257 KCipher ** pcipher,
258 kcipher_type type)
259 {
260 KCipher * pc;
261 rc_t rc;
262
263 assert (self);
264 assert (pcipher);
265
266 rc = KCipherMake (&pc, type);
267
268 *pcipher = rc ? NULL : pc;
269
270 return rc;
271 }
272
273
274 LIB_EXPORT
KCipherManagerMakeCipher(const KCipherManager * self,struct KCipher ** pcipher,kcipher_type type)275 rc_t CC KCipherManagerMakeCipher (const KCipherManager * self,
276 struct KCipher ** pcipher,
277 kcipher_type type)
278 {
279 rc_t rc;
280
281 if (self == NULL)
282 return RC (rcKrypto, rcMgr, rcConstructing, rcSelf, rcNull);
283
284 if (pcipher == NULL)
285 return RC (rcKrypto, rcMgr, rcConstructing, rcParam, rcNull);
286
287 *pcipher = NULL;
288
289 rc = KCipherManagerMakeCipherInt (self, pcipher, type);
290
291 return rc;
292 }
293
294
295
296