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