/src/nss-nspr/nss/lib/softoken/sftkdb.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
2 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
3 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | | /* |
5 | | * The following code handles the storage of PKCS 11 modules used by the |
6 | | * NSS. For the rest of NSS, only one kind of database handle exists: |
7 | | * |
8 | | * SFTKDBHandle |
9 | | * |
10 | | * There is one SFTKDBHandle for the each key database and one for each cert |
11 | | * database. These databases are opened as associated pairs, one pair per |
12 | | * slot. SFTKDBHandles are reference counted objects. |
13 | | * |
14 | | * Each SFTKDBHandle points to a low level database handle (SDB). This handle |
15 | | * represents the underlying physical database. These objects are not |
16 | | * reference counted, an are 'owned' by their respective SFTKDBHandles. |
17 | | * |
18 | | * |
19 | | */ |
20 | | #include "sftkdb.h" |
21 | | #include "sftkdbti.h" |
22 | | #include "pkcs11t.h" |
23 | | #include "pkcs11i.h" |
24 | | #include "sdb.h" |
25 | | #include "prprf.h" |
26 | | #include "pratom.h" |
27 | | #include "lgglue.h" |
28 | | #include "utilpars.h" |
29 | | #include "secerr.h" |
30 | | #include "softoken.h" |
31 | | #if defined(_WIN32) |
32 | | #include <windows.h> |
33 | | #endif |
34 | | |
35 | | /* |
36 | | * We want all databases to have the same binary representation independent of |
37 | | * endianness or length of the host architecture. In general PKCS #11 attributes |
38 | | * are endian/length independent except those attributes that pass CK_ULONG. |
39 | | * |
40 | | * The following functions fixes up the CK_ULONG type attributes so that the data |
41 | | * base sees a machine independent view. CK_ULONGs are stored as 4 byte network |
42 | | * byte order values (big endian). |
43 | | */ |
44 | 0 | #define BBP 8 |
45 | | |
46 | | PRBool |
47 | | sftkdb_isULONGAttribute(CK_ATTRIBUTE_TYPE type) |
48 | 0 | { |
49 | 0 | switch (type) { |
50 | 0 | case CKA_CERTIFICATE_CATEGORY: |
51 | 0 | case CKA_CERTIFICATE_TYPE: |
52 | 0 | case CKA_CLASS: |
53 | 0 | case CKA_JAVA_MIDP_SECURITY_DOMAIN: |
54 | 0 | case CKA_KEY_GEN_MECHANISM: |
55 | 0 | case CKA_KEY_TYPE: |
56 | 0 | case CKA_MECHANISM_TYPE: |
57 | 0 | case CKA_MODULUS_BITS: |
58 | 0 | case CKA_PRIME_BITS: |
59 | 0 | case CKA_SUBPRIME_BITS: |
60 | 0 | case CKA_VALUE_BITS: |
61 | 0 | case CKA_VALUE_LEN: |
62 | |
|
63 | 0 | case CKA_TRUST_DIGITAL_SIGNATURE: |
64 | 0 | case CKA_TRUST_NON_REPUDIATION: |
65 | 0 | case CKA_TRUST_KEY_ENCIPHERMENT: |
66 | 0 | case CKA_TRUST_DATA_ENCIPHERMENT: |
67 | 0 | case CKA_TRUST_KEY_AGREEMENT: |
68 | 0 | case CKA_TRUST_KEY_CERT_SIGN: |
69 | 0 | case CKA_TRUST_CRL_SIGN: |
70 | |
|
71 | 0 | case CKA_TRUST_SERVER_AUTH: |
72 | 0 | case CKA_TRUST_CLIENT_AUTH: |
73 | 0 | case CKA_TRUST_CODE_SIGNING: |
74 | 0 | case CKA_TRUST_EMAIL_PROTECTION: |
75 | 0 | case CKA_TRUST_IPSEC_END_SYSTEM: |
76 | 0 | case CKA_TRUST_IPSEC_TUNNEL: |
77 | 0 | case CKA_TRUST_IPSEC_USER: |
78 | 0 | case CKA_TRUST_TIME_STAMPING: |
79 | 0 | case CKA_TRUST_STEP_UP_APPROVED: |
80 | 0 | return PR_TRUE; |
81 | 0 | default: |
82 | 0 | break; |
83 | 0 | } |
84 | 0 | return PR_FALSE; |
85 | 0 | } |
86 | | |
87 | | /* are the attributes private? */ |
88 | | static PRBool |
89 | | sftkdb_isPrivateAttribute(CK_ATTRIBUTE_TYPE type) |
90 | 0 | { |
91 | 0 | switch (type) { |
92 | 0 | case CKA_VALUE: |
93 | 0 | case CKA_PRIVATE_EXPONENT: |
94 | 0 | case CKA_PRIME_1: |
95 | 0 | case CKA_PRIME_2: |
96 | 0 | case CKA_EXPONENT_1: |
97 | 0 | case CKA_EXPONENT_2: |
98 | 0 | case CKA_COEFFICIENT: |
99 | 0 | return PR_TRUE; |
100 | 0 | default: |
101 | 0 | break; |
102 | 0 | } |
103 | 0 | return PR_FALSE; |
104 | 0 | } |
105 | | |
106 | | /* These attributes must be authenticated with an hmac. */ |
107 | | static PRBool |
108 | | sftkdb_isAuthenticatedAttribute(CK_ATTRIBUTE_TYPE type) |
109 | 0 | { |
110 | 0 | switch (type) { |
111 | 0 | case CKA_MODULUS: |
112 | 0 | case CKA_PUBLIC_EXPONENT: |
113 | 0 | case CKA_CERT_SHA1_HASH: |
114 | 0 | case CKA_CERT_MD5_HASH: |
115 | 0 | case CKA_TRUST_SERVER_AUTH: |
116 | 0 | case CKA_TRUST_CLIENT_AUTH: |
117 | 0 | case CKA_TRUST_EMAIL_PROTECTION: |
118 | 0 | case CKA_TRUST_CODE_SIGNING: |
119 | 0 | case CKA_TRUST_STEP_UP_APPROVED: |
120 | 0 | case CKA_NSS_OVERRIDE_EXTENSIONS: |
121 | 0 | return PR_TRUE; |
122 | 0 | default: |
123 | 0 | break; |
124 | 0 | } |
125 | 0 | return PR_FALSE; |
126 | 0 | } |
127 | | /* |
128 | | * convert a native ULONG to a database ulong. Database ulong's |
129 | | * are all 4 byte big endian values. |
130 | | */ |
131 | | void |
132 | | sftk_ULong2SDBULong(unsigned char *data, CK_ULONG value) |
133 | 0 | { |
134 | 0 | int i; |
135 | |
|
136 | 0 | for (i = 0; i < SDB_ULONG_SIZE; i++) { |
137 | 0 | data[i] = (value >> (SDB_ULONG_SIZE - 1 - i) * BBP) & 0xff; |
138 | 0 | } |
139 | 0 | } |
140 | | |
141 | | /* |
142 | | * convert a database ulong back to a native ULONG. (reverse of the above |
143 | | * function). |
144 | | */ |
145 | | static CK_ULONG |
146 | | sftk_SDBULong2ULong(unsigned char *data) |
147 | 0 | { |
148 | 0 | int i; |
149 | 0 | CK_ULONG value = 0; |
150 | |
|
151 | 0 | for (i = 0; i < SDB_ULONG_SIZE; i++) { |
152 | 0 | value |= (((CK_ULONG)data[i]) << (SDB_ULONG_SIZE - 1 - i) * BBP); |
153 | 0 | } |
154 | 0 | return value; |
155 | 0 | } |
156 | | |
157 | | /* certain trust records are default values, which are the values |
158 | | * returned if the signature check fails anyway. |
159 | | * In those cases, we can skip the signature check. */ |
160 | | PRBool |
161 | | sftkdb_isNullTrust(const CK_ATTRIBUTE *template) |
162 | 0 | { |
163 | 0 | switch (template->type) { |
164 | 0 | case CKA_TRUST_SERVER_AUTH: |
165 | 0 | case CKA_TRUST_CLIENT_AUTH: |
166 | 0 | case CKA_TRUST_EMAIL_PROTECTION: |
167 | 0 | case CKA_TRUST_CODE_SIGNING: |
168 | 0 | if (template->ulValueLen != SDB_ULONG_SIZE) { |
169 | 0 | break; |
170 | 0 | } |
171 | 0 | if (sftk_SDBULong2ULong(template->pValue) == |
172 | 0 | CKT_NSS_TRUST_UNKNOWN) { |
173 | 0 | return PR_TRUE; |
174 | 0 | } |
175 | 0 | break; |
176 | 0 | case CKA_TRUST_STEP_UP_APPROVED: |
177 | 0 | if (template->ulValueLen != 1) { |
178 | 0 | break; |
179 | 0 | } |
180 | 0 | if (*((unsigned char *)(template->pValue)) == 0) { |
181 | 0 | return PR_TRUE; |
182 | 0 | } |
183 | 0 | break; |
184 | 0 | default: |
185 | 0 | break; |
186 | 0 | } |
187 | 0 | return PR_FALSE; |
188 | 0 | } |
189 | | |
190 | | /* |
191 | | * fix up the input templates. Our fixed up ints are stored in data and must |
192 | | * be freed by the caller. The new template must also be freed. If there are no |
193 | | * CK_ULONG attributes, the orignal template is passed in as is. |
194 | | */ |
195 | | static CK_ATTRIBUTE * |
196 | | sftkdb_fixupTemplateIn(const CK_ATTRIBUTE *template, int count, |
197 | | unsigned char **dataOut, int *dataOutSize) |
198 | 0 | { |
199 | 0 | int i; |
200 | 0 | int ulongCount = 0; |
201 | 0 | unsigned char *data; |
202 | 0 | CK_ATTRIBUTE *ntemplate; |
203 | |
|
204 | 0 | *dataOut = NULL; |
205 | 0 | *dataOutSize = 0; |
206 | | |
207 | | /* first count the number of CK_ULONG attributes */ |
208 | 0 | for (i = 0; i < count; i++) { |
209 | | /* Don't 'fixup' NULL values */ |
210 | 0 | if (!template[i].pValue) { |
211 | 0 | continue; |
212 | 0 | } |
213 | 0 | if (template[i].ulValueLen == sizeof(CK_ULONG)) { |
214 | 0 | if (sftkdb_isULONGAttribute(template[i].type)) { |
215 | 0 | ulongCount++; |
216 | 0 | } |
217 | 0 | } |
218 | 0 | } |
219 | | /* no attributes to fixup, just call on through */ |
220 | 0 | if (ulongCount == 0) { |
221 | 0 | return (CK_ATTRIBUTE *)template; |
222 | 0 | } |
223 | | |
224 | | /* allocate space for new ULONGS */ |
225 | 0 | data = (unsigned char *)PORT_Alloc(SDB_ULONG_SIZE * ulongCount); |
226 | 0 | if (!data) { |
227 | 0 | return NULL; |
228 | 0 | } |
229 | | |
230 | | /* allocate new template */ |
231 | 0 | ntemplate = PORT_NewArray(CK_ATTRIBUTE, count); |
232 | 0 | if (!ntemplate) { |
233 | 0 | PORT_Free(data); |
234 | 0 | return NULL; |
235 | 0 | } |
236 | 0 | *dataOut = data; |
237 | 0 | *dataOutSize = SDB_ULONG_SIZE * ulongCount; |
238 | | /* copy the old template, fixup the actual ulongs */ |
239 | 0 | for (i = 0; i < count; i++) { |
240 | 0 | ntemplate[i] = template[i]; |
241 | | /* Don't 'fixup' NULL values */ |
242 | 0 | if (!template[i].pValue) { |
243 | 0 | continue; |
244 | 0 | } |
245 | 0 | if (template[i].ulValueLen == sizeof(CK_ULONG)) { |
246 | 0 | if (sftkdb_isULONGAttribute(template[i].type)) { |
247 | 0 | CK_ULONG value = *(CK_ULONG *)template[i].pValue; |
248 | 0 | sftk_ULong2SDBULong(data, value); |
249 | 0 | ntemplate[i].pValue = data; |
250 | 0 | ntemplate[i].ulValueLen = SDB_ULONG_SIZE; |
251 | 0 | data += SDB_ULONG_SIZE; |
252 | 0 | } |
253 | 0 | } |
254 | 0 | } |
255 | 0 | return ntemplate; |
256 | 0 | } |
257 | | |
258 | | static const char SFTKDB_META_SIG_TEMPLATE[] = "sig_%s_%08x_%08x"; |
259 | | |
260 | | /* |
261 | | * return a string describing the database type (key or cert) |
262 | | */ |
263 | | const char * |
264 | | sftkdb_TypeString(SFTKDBHandle *handle) |
265 | 0 | { |
266 | 0 | return (handle->type == SFTK_KEYDB_TYPE) ? "key" : "cert"; |
267 | 0 | } |
268 | | |
269 | | /* |
270 | | * Some attributes are signed with an Hmac and a pbe key generated from |
271 | | * the password. This signature is stored indexed by object handle and |
272 | | * attribute type in the meta data table in the key database. |
273 | | * |
274 | | * Signature entries are indexed by the string |
275 | | * sig_[cert/key]_{ObjectID}_{Attribute} |
276 | | * |
277 | | * This function fetches that pkcs5 signature. Caller supplies a SECItem |
278 | | * pre-allocated to the appropriate size if the SECItem is too small the |
279 | | * function will fail with CKR_BUFFER_TOO_SMALL. |
280 | | */ |
281 | | static CK_RV |
282 | | sftkdb_getRawAttributeSignature(SFTKDBHandle *handle, SDB *db, |
283 | | CK_OBJECT_HANDLE objectID, |
284 | | CK_ATTRIBUTE_TYPE type, |
285 | | SECItem *signText) |
286 | 0 | { |
287 | 0 | char id[30]; |
288 | 0 | CK_RV crv; |
289 | |
|
290 | 0 | snprintf(id, sizeof(id), SFTKDB_META_SIG_TEMPLATE, |
291 | 0 | sftkdb_TypeString(handle), |
292 | 0 | (unsigned int)objectID, (unsigned int)type); |
293 | |
|
294 | 0 | crv = (*db->sdb_GetMetaData)(db, id, signText, NULL); |
295 | 0 | return crv; |
296 | 0 | } |
297 | | |
298 | | CK_RV |
299 | | sftkdb_GetAttributeSignature(SFTKDBHandle *handle, SFTKDBHandle *keyHandle, |
300 | | CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE type, |
301 | | SECItem *signText) |
302 | 0 | { |
303 | 0 | SDB *db = SFTK_GET_SDB(keyHandle); |
304 | 0 | return sftkdb_getRawAttributeSignature(handle, db, objectID, type, signText); |
305 | 0 | } |
306 | | |
307 | | CK_RV |
308 | | sftkdb_DestroyAttributeSignature(SFTKDBHandle *handle, SDB *db, |
309 | | CK_OBJECT_HANDLE objectID, |
310 | | CK_ATTRIBUTE_TYPE type) |
311 | 0 | { |
312 | 0 | char id[30]; |
313 | 0 | CK_RV crv; |
314 | |
|
315 | 0 | snprintf(id, sizeof(id), SFTKDB_META_SIG_TEMPLATE, |
316 | 0 | sftkdb_TypeString(handle), |
317 | 0 | (unsigned int)objectID, (unsigned int)type); |
318 | |
|
319 | 0 | crv = (*db->sdb_DestroyMetaData)(db, id); |
320 | 0 | return crv; |
321 | 0 | } |
322 | | |
323 | | /* |
324 | | * Some attributes are signed with an Hmac and a pbe key generated from |
325 | | * the password. This signature is stored indexed by object handle and |
326 | | * attribute type in the meta data table in the key database. |
327 | | * |
328 | | * Signature entries are indexed by the string |
329 | | * sig_[cert/key]_{ObjectID}_{Attribute} |
330 | | * |
331 | | * This function stores that pkcs5 signature. |
332 | | */ |
333 | | CK_RV |
334 | | sftkdb_PutAttributeSignature(SFTKDBHandle *handle, SDB *keyTarget, |
335 | | CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE type, |
336 | | SECItem *signText) |
337 | 0 | { |
338 | 0 | char id[30]; |
339 | 0 | CK_RV crv; |
340 | |
|
341 | 0 | snprintf(id, sizeof(id), SFTKDB_META_SIG_TEMPLATE, |
342 | 0 | sftkdb_TypeString(handle), |
343 | 0 | (unsigned int)objectID, (unsigned int)type); |
344 | |
|
345 | 0 | crv = (*keyTarget->sdb_PutMetaData)(keyTarget, id, signText, NULL); |
346 | 0 | return crv; |
347 | 0 | } |
348 | | |
349 | | /* |
350 | | * fix up returned data. NOTE: sftkdb_fixupTemplateIn has already allocated |
351 | | * separate data sections for the database ULONG values. |
352 | | */ |
353 | | static CK_RV |
354 | | sftkdb_fixupTemplateOut(CK_ATTRIBUTE *template, CK_OBJECT_HANDLE objectID, |
355 | | CK_ATTRIBUTE *ntemplate, int count, SFTKDBHandle *handle) |
356 | 0 | { |
357 | 0 | int i; |
358 | 0 | CK_RV crv = CKR_OK; |
359 | 0 | SFTKDBHandle *keyHandle; |
360 | 0 | PRBool checkSig = PR_TRUE; |
361 | 0 | PRBool checkEnc = PR_TRUE; |
362 | |
|
363 | 0 | PORT_Assert(handle); |
364 | | |
365 | | /* find the key handle */ |
366 | 0 | keyHandle = handle; |
367 | 0 | if (handle->type != SFTK_KEYDB_TYPE) { |
368 | 0 | checkEnc = PR_FALSE; |
369 | 0 | keyHandle = handle->peerDB; |
370 | 0 | } |
371 | |
|
372 | 0 | if ((keyHandle == NULL) || |
373 | 0 | ((SFTK_GET_SDB(keyHandle)->sdb_flags & SDB_HAS_META) == 0) || |
374 | 0 | (sftkdb_PWCached(keyHandle) != SECSuccess)) { |
375 | 0 | checkSig = PR_FALSE; |
376 | 0 | } |
377 | |
|
378 | 0 | for (i = 0; i < count; i++) { |
379 | 0 | CK_ULONG length = template[i].ulValueLen; |
380 | 0 | template[i].ulValueLen = ntemplate[i].ulValueLen; |
381 | | /* fixup ulongs */ |
382 | 0 | if (ntemplate[i].ulValueLen == SDB_ULONG_SIZE) { |
383 | 0 | if (sftkdb_isULONGAttribute(template[i].type)) { |
384 | 0 | if (template[i].pValue) { |
385 | 0 | CK_ULONG value; |
386 | |
|
387 | 0 | value = sftk_SDBULong2ULong(ntemplate[i].pValue); |
388 | 0 | if (length < sizeof(CK_ULONG)) { |
389 | 0 | template[i].ulValueLen = -1; |
390 | 0 | crv = CKR_BUFFER_TOO_SMALL; |
391 | 0 | continue; |
392 | 0 | } |
393 | 0 | PORT_Memcpy(template[i].pValue, &value, sizeof(CK_ULONG)); |
394 | 0 | } |
395 | 0 | template[i].ulValueLen = sizeof(CK_ULONG); |
396 | 0 | } |
397 | 0 | } |
398 | | |
399 | | /* if no data was retrieved, no need to process encrypted or signed |
400 | | * attributes */ |
401 | 0 | if ((template[i].pValue == NULL) || (template[i].ulValueLen == -1)) { |
402 | 0 | continue; |
403 | 0 | } |
404 | | |
405 | | /* fixup private attributes */ |
406 | 0 | if (checkEnc && sftkdb_isPrivateAttribute(ntemplate[i].type)) { |
407 | | /* we have a private attribute */ |
408 | | /* This code depends on the fact that the cipherText is bigger |
409 | | * than the plain text */ |
410 | 0 | SECItem cipherText; |
411 | 0 | SECItem *plainText; |
412 | 0 | SECStatus rv; |
413 | |
|
414 | 0 | cipherText.data = ntemplate[i].pValue; |
415 | 0 | cipherText.len = ntemplate[i].ulValueLen; |
416 | 0 | PZ_Lock(handle->passwordLock); |
417 | 0 | if (handle->passwordKey.data == NULL) { |
418 | 0 | PZ_Unlock(handle->passwordLock); |
419 | 0 | template[i].ulValueLen = -1; |
420 | 0 | crv = CKR_USER_NOT_LOGGED_IN; |
421 | 0 | continue; |
422 | 0 | } |
423 | 0 | rv = sftkdb_DecryptAttribute(handle, |
424 | 0 | &handle->passwordKey, |
425 | 0 | objectID, |
426 | 0 | ntemplate[i].type, |
427 | 0 | &cipherText, &plainText); |
428 | 0 | PZ_Unlock(handle->passwordLock); |
429 | 0 | if (rv != SECSuccess) { |
430 | 0 | PORT_Memset(template[i].pValue, 0, template[i].ulValueLen); |
431 | 0 | template[i].ulValueLen = -1; |
432 | 0 | crv = CKR_GENERAL_ERROR; |
433 | 0 | continue; |
434 | 0 | } |
435 | 0 | PORT_Assert(template[i].ulValueLen >= plainText->len); |
436 | 0 | if (template[i].ulValueLen < plainText->len) { |
437 | 0 | SECITEM_ZfreeItem(plainText, PR_TRUE); |
438 | 0 | PORT_Memset(template[i].pValue, 0, template[i].ulValueLen); |
439 | 0 | template[i].ulValueLen = -1; |
440 | 0 | crv = CKR_GENERAL_ERROR; |
441 | 0 | continue; |
442 | 0 | } |
443 | | |
444 | | /* copy the plain text back into the template */ |
445 | 0 | PORT_Memcpy(template[i].pValue, plainText->data, plainText->len); |
446 | 0 | template[i].ulValueLen = plainText->len; |
447 | 0 | SECITEM_ZfreeItem(plainText, PR_TRUE); |
448 | 0 | } |
449 | | /* make sure signed attributes are valid */ |
450 | 0 | if (checkSig && sftkdb_isAuthenticatedAttribute(ntemplate[i].type) && !sftkdb_isNullTrust(&ntemplate[i])) { |
451 | 0 | SECStatus rv; |
452 | 0 | CK_RV local_crv; |
453 | 0 | SECItem signText; |
454 | 0 | SECItem plainText; |
455 | 0 | unsigned char signData[SDB_MAX_META_DATA_LEN]; |
456 | |
|
457 | 0 | signText.data = signData; |
458 | 0 | signText.len = sizeof(signData); |
459 | | |
460 | | /* Use a local variable so that we don't clobber any already |
461 | | * set error. This function returns either CKR_OK or the last |
462 | | * found error in the template */ |
463 | 0 | local_crv = sftkdb_GetAttributeSignature(handle, keyHandle, |
464 | 0 | objectID, |
465 | 0 | ntemplate[i].type, |
466 | 0 | &signText); |
467 | 0 | if (local_crv != CKR_OK) { |
468 | 0 | PORT_Memset(template[i].pValue, 0, template[i].ulValueLen); |
469 | 0 | template[i].ulValueLen = -1; |
470 | 0 | crv = local_crv; |
471 | 0 | continue; |
472 | 0 | } |
473 | | |
474 | 0 | plainText.data = ntemplate[i].pValue; |
475 | 0 | plainText.len = ntemplate[i].ulValueLen; |
476 | | |
477 | | /* |
478 | | * we do a second check holding the lock just in case the user |
479 | | * loggout while we were trying to get the signature. |
480 | | */ |
481 | 0 | PZ_Lock(keyHandle->passwordLock); |
482 | 0 | if (keyHandle->passwordKey.data == NULL) { |
483 | | /* if we are no longer logged in, no use checking the other |
484 | | * Signatures either. */ |
485 | 0 | checkSig = PR_FALSE; |
486 | 0 | PZ_Unlock(keyHandle->passwordLock); |
487 | 0 | continue; |
488 | 0 | } |
489 | | |
490 | 0 | rv = sftkdb_VerifyAttribute(keyHandle, |
491 | 0 | &keyHandle->passwordKey, |
492 | 0 | objectID, ntemplate[i].type, |
493 | 0 | &plainText, &signText); |
494 | 0 | PZ_Unlock(keyHandle->passwordLock); |
495 | 0 | if (rv != SECSuccess) { |
496 | 0 | PORT_Memset(template[i].pValue, 0, template[i].ulValueLen); |
497 | 0 | template[i].ulValueLen = -1; |
498 | 0 | crv = CKR_SIGNATURE_INVALID; /* better error code? */ |
499 | 0 | } |
500 | | /* This Attribute is fine */ |
501 | 0 | } |
502 | 0 | } |
503 | 0 | return crv; |
504 | 0 | } |
505 | | |
506 | | /* |
507 | | * Some attributes are signed with an HMAC and a pbe key generated from |
508 | | * the password. This signature is stored indexed by object handle and |
509 | | * |
510 | | * Those attributes are: |
511 | | * 1) Trust object hashes and trust values. |
512 | | * 2) public key values. |
513 | | * |
514 | | * Certs themselves are considered properly authenticated by virtue of their |
515 | | * signature, or their matching hash with the trust object. |
516 | | * |
517 | | * These signature is only checked for objects coming from shared databases. |
518 | | * Older dbm style databases have such no signature checks. HMACs are also |
519 | | * only checked when the token is logged in, as it requires a pbe generated |
520 | | * from the password. |
521 | | * |
522 | | * Tokens which have no key database (and therefore no master password) do not |
523 | | * have any stored signature values. Signature values are stored in the key |
524 | | * database, since the signature data is tightly coupled to the key database |
525 | | * password. |
526 | | * |
527 | | * This function takes a template of attributes that were either created or |
528 | | * modified. These attributes are checked to see if the need to be signed. |
529 | | * If they do, then this function signs the attributes and writes them |
530 | | * to the meta data store. |
531 | | * |
532 | | * This function can fail if there are attributes that must be signed, but |
533 | | * the token is not logged in. |
534 | | * |
535 | | * The caller is expected to abort any transaction he was in in the |
536 | | * event of a failure of this function. |
537 | | */ |
538 | | static CK_RV |
539 | | sftk_signTemplate(PLArenaPool *arena, SFTKDBHandle *handle, |
540 | | PRBool mayBeUpdateDB, |
541 | | CK_OBJECT_HANDLE objectID, const CK_ATTRIBUTE *template, |
542 | | CK_ULONG count) |
543 | 0 | { |
544 | 0 | unsigned int i; |
545 | 0 | CK_RV crv; |
546 | 0 | SFTKDBHandle *keyHandle = handle; |
547 | 0 | SDB *keyTarget = NULL; |
548 | 0 | PRBool usingPeerDB = PR_FALSE; |
549 | 0 | PRBool inPeerDBTransaction = PR_FALSE; |
550 | |
|
551 | 0 | PORT_Assert(handle); |
552 | |
|
553 | 0 | if (handle->type != SFTK_KEYDB_TYPE) { |
554 | 0 | keyHandle = handle->peerDB; |
555 | 0 | usingPeerDB = PR_TRUE; |
556 | 0 | } |
557 | | |
558 | | /* no key DB defined? then no need to sign anything */ |
559 | 0 | if (keyHandle == NULL) { |
560 | 0 | crv = CKR_OK; |
561 | 0 | goto loser; |
562 | 0 | } |
563 | | |
564 | | /* When we are in a middle of an update, we have an update database set, |
565 | | * but we want to write to the real database. The bool mayBeUpdateDB is |
566 | | * set to TRUE if it's possible that we want to write an update database |
567 | | * rather than a primary */ |
568 | 0 | keyTarget = (mayBeUpdateDB && keyHandle->update) ? keyHandle->update : keyHandle->db; |
569 | | |
570 | | /* skip the the database does not support meta data */ |
571 | 0 | if ((keyTarget->sdb_flags & SDB_HAS_META) == 0) { |
572 | 0 | crv = CKR_OK; |
573 | 0 | goto loser; |
574 | 0 | } |
575 | | |
576 | | /* If we had to switch databases, we need to initialize a transaction. */ |
577 | 0 | if (usingPeerDB) { |
578 | 0 | crv = (*keyTarget->sdb_Begin)(keyTarget); |
579 | 0 | if (crv != CKR_OK) { |
580 | 0 | goto loser; |
581 | 0 | } |
582 | 0 | inPeerDBTransaction = PR_TRUE; |
583 | 0 | } |
584 | | |
585 | 0 | for (i = 0; i < count; i++) { |
586 | 0 | if (sftkdb_isAuthenticatedAttribute(template[i].type)) { |
587 | 0 | SECStatus rv; |
588 | 0 | SECItem *signText; |
589 | 0 | SECItem plainText; |
590 | |
|
591 | 0 | plainText.data = template[i].pValue; |
592 | 0 | plainText.len = template[i].ulValueLen; |
593 | 0 | PZ_Lock(keyHandle->passwordLock); |
594 | 0 | if (keyHandle->passwordKey.data == NULL) { |
595 | 0 | PZ_Unlock(keyHandle->passwordLock); |
596 | 0 | crv = CKR_USER_NOT_LOGGED_IN; |
597 | 0 | goto loser; |
598 | 0 | } |
599 | 0 | rv = sftkdb_SignAttribute(arena, keyHandle, keyTarget, |
600 | 0 | &keyHandle->passwordKey, |
601 | 0 | keyHandle->defaultIterationCount, |
602 | 0 | objectID, template[i].type, |
603 | 0 | &plainText, &signText); |
604 | 0 | PZ_Unlock(keyHandle->passwordLock); |
605 | 0 | if (rv != SECSuccess) { |
606 | 0 | crv = CKR_GENERAL_ERROR; /* better error code here? */ |
607 | 0 | goto loser; |
608 | 0 | } |
609 | 0 | crv = sftkdb_PutAttributeSignature(handle, keyTarget, objectID, |
610 | 0 | template[i].type, signText); |
611 | 0 | if (crv != CKR_OK) { |
612 | 0 | goto loser; |
613 | 0 | } |
614 | 0 | } |
615 | 0 | } |
616 | 0 | crv = CKR_OK; |
617 | | |
618 | | /* If necessary, commit the transaction */ |
619 | 0 | if (inPeerDBTransaction) { |
620 | 0 | crv = (*keyTarget->sdb_Commit)(keyTarget); |
621 | 0 | if (crv != CKR_OK) { |
622 | 0 | goto loser; |
623 | 0 | } |
624 | 0 | inPeerDBTransaction = PR_FALSE; |
625 | 0 | } |
626 | | |
627 | 0 | loser: |
628 | 0 | if (inPeerDBTransaction) { |
629 | | /* The transaction must have failed. Abort. */ |
630 | 0 | (*keyTarget->sdb_Abort)(keyTarget); |
631 | 0 | PORT_Assert(crv != CKR_OK); |
632 | 0 | if (crv == CKR_OK) |
633 | 0 | crv = CKR_GENERAL_ERROR; |
634 | 0 | } |
635 | 0 | return crv; |
636 | 0 | } |
637 | | |
638 | | static CK_RV |
639 | | sftkdb_CreateObject(PLArenaPool *arena, SFTKDBHandle *handle, |
640 | | SDB *db, CK_OBJECT_HANDLE *objectID, |
641 | | CK_ATTRIBUTE *template, CK_ULONG count) |
642 | 0 | { |
643 | 0 | CK_RV crv; |
644 | |
|
645 | 0 | crv = (*db->sdb_CreateObject)(db, objectID, template, count); |
646 | 0 | if (crv != CKR_OK) { |
647 | 0 | goto loser; |
648 | 0 | } |
649 | 0 | crv = sftk_signTemplate(arena, handle, (db == handle->update), |
650 | 0 | *objectID, template, count); |
651 | 0 | loser: |
652 | |
|
653 | 0 | return crv; |
654 | 0 | } |
655 | | |
656 | | static CK_RV |
657 | | sftkdb_fixupSignatures(SFTKDBHandle *handle, |
658 | | SDB *db, CK_OBJECT_HANDLE oldID, CK_OBJECT_HANDLE newID, |
659 | | CK_ATTRIBUTE *ptemplate, CK_ULONG max_attributes) |
660 | 0 | { |
661 | 0 | unsigned int i; |
662 | 0 | CK_RV crv = CKR_OK; |
663 | | |
664 | | /* if we don't have a meta table, we didn't write any signature objects */ |
665 | 0 | if ((db->sdb_flags & SDB_HAS_META) == 0) { |
666 | 0 | return CKR_OK; |
667 | 0 | } |
668 | 0 | for (i = 0; i < max_attributes; i++) { |
669 | 0 | CK_ATTRIBUTE *att = &ptemplate[i]; |
670 | 0 | CK_ATTRIBUTE_TYPE type = att->type; |
671 | 0 | if (sftkdb_isPrivateAttribute(type)) { |
672 | | /* move the signature from one object handle to another and delete |
673 | | * the old entry */ |
674 | 0 | SECItem signature; |
675 | 0 | unsigned char signData[SDB_MAX_META_DATA_LEN]; |
676 | |
|
677 | 0 | signature.data = signData; |
678 | 0 | signature.len = sizeof(signData); |
679 | 0 | crv = sftkdb_getRawAttributeSignature(handle, db, oldID, type, |
680 | 0 | &signature); |
681 | 0 | if (crv != CKR_OK) { |
682 | | /* NOTE: if we ever change our default write from AES_CBC |
683 | | * to AES_KW, We'll need to change this to a continue as |
684 | | * we won't need the integrity record for AES_KW */ |
685 | 0 | break; |
686 | 0 | } |
687 | 0 | crv = sftkdb_PutAttributeSignature(handle, db, newID, type, |
688 | 0 | &signature); |
689 | 0 | if (crv != CKR_OK) { |
690 | 0 | break; |
691 | 0 | } |
692 | | /* now get rid of the old one */ |
693 | 0 | crv = sftkdb_DestroyAttributeSignature(handle, db, oldID, type); |
694 | 0 | if (crv != CKR_OK) { |
695 | 0 | break; |
696 | 0 | } |
697 | 0 | } |
698 | 0 | } |
699 | 0 | return crv; |
700 | 0 | } |
701 | | |
702 | | CK_ATTRIBUTE * |
703 | | sftk_ExtractTemplate(PLArenaPool *arena, SFTKObject *object, |
704 | | SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID, |
705 | | SDB *db, CK_ULONG *pcount, CK_RV *crv) |
706 | 0 | { |
707 | 0 | unsigned int count; |
708 | 0 | CK_ATTRIBUTE *template; |
709 | 0 | unsigned int i, templateIndex; |
710 | 0 | SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object); |
711 | 0 | PRBool doEnc = PR_TRUE; |
712 | |
|
713 | 0 | *crv = CKR_OK; |
714 | |
|
715 | 0 | if (sessObject == NULL) { |
716 | 0 | *crv = CKR_GENERAL_ERROR; /* internal programming error */ |
717 | 0 | return NULL; |
718 | 0 | } |
719 | | |
720 | 0 | PORT_Assert(handle); |
721 | | /* find the key handle */ |
722 | 0 | if (handle->type != SFTK_KEYDB_TYPE) { |
723 | 0 | doEnc = PR_FALSE; |
724 | 0 | } |
725 | |
|
726 | 0 | PZ_Lock(sessObject->attributeLock); |
727 | 0 | count = 0; |
728 | 0 | for (i = 0; i < sessObject->hashSize; i++) { |
729 | 0 | SFTKAttribute *attr; |
730 | 0 | for (attr = sessObject->head[i]; attr; attr = attr->next) { |
731 | 0 | count++; |
732 | 0 | } |
733 | 0 | } |
734 | 0 | template = PORT_ArenaNewArray(arena, CK_ATTRIBUTE, count); |
735 | 0 | if (template == NULL) { |
736 | 0 | PZ_Unlock(sessObject->attributeLock); |
737 | 0 | *crv = CKR_HOST_MEMORY; |
738 | 0 | return NULL; |
739 | 0 | } |
740 | 0 | templateIndex = 0; |
741 | 0 | for (i = 0; i < sessObject->hashSize; i++) { |
742 | 0 | SFTKAttribute *attr; |
743 | 0 | for (attr = sessObject->head[i]; attr; attr = attr->next) { |
744 | 0 | CK_ATTRIBUTE *tp = &template[templateIndex++]; |
745 | | /* copy the attribute */ |
746 | 0 | *tp = attr->attrib; |
747 | | |
748 | | /* fixup ULONG s */ |
749 | 0 | if ((tp->ulValueLen == sizeof(CK_ULONG)) && |
750 | 0 | (sftkdb_isULONGAttribute(tp->type))) { |
751 | 0 | CK_ULONG value = *(CK_ULONG *)tp->pValue; |
752 | 0 | unsigned char *data; |
753 | |
|
754 | 0 | tp->pValue = PORT_ArenaAlloc(arena, SDB_ULONG_SIZE); |
755 | 0 | data = (unsigned char *)tp->pValue; |
756 | 0 | if (data == NULL) { |
757 | 0 | *crv = CKR_HOST_MEMORY; |
758 | 0 | break; |
759 | 0 | } |
760 | 0 | sftk_ULong2SDBULong(data, value); |
761 | 0 | tp->ulValueLen = SDB_ULONG_SIZE; |
762 | 0 | } |
763 | | |
764 | | /* encrypt private attributes */ |
765 | 0 | if (doEnc && sftkdb_isPrivateAttribute(tp->type)) { |
766 | | /* we have a private attribute */ |
767 | 0 | SECItem *cipherText; |
768 | 0 | SECItem plainText; |
769 | 0 | SECStatus rv; |
770 | |
|
771 | 0 | plainText.data = tp->pValue; |
772 | 0 | plainText.len = tp->ulValueLen; |
773 | 0 | PZ_Lock(handle->passwordLock); |
774 | 0 | if (handle->passwordKey.data == NULL) { |
775 | 0 | PZ_Unlock(handle->passwordLock); |
776 | 0 | *crv = CKR_USER_NOT_LOGGED_IN; |
777 | 0 | break; |
778 | 0 | } |
779 | 0 | rv = sftkdb_EncryptAttribute(arena, handle, db, |
780 | 0 | &handle->passwordKey, |
781 | 0 | handle->defaultIterationCount, |
782 | 0 | objectID, |
783 | 0 | tp->type, |
784 | 0 | &plainText, &cipherText); |
785 | 0 | PZ_Unlock(handle->passwordLock); |
786 | 0 | if (rv == SECSuccess) { |
787 | 0 | tp->pValue = cipherText->data; |
788 | 0 | tp->ulValueLen = cipherText->len; |
789 | 0 | } else { |
790 | 0 | *crv = CKR_GENERAL_ERROR; /* better error code here? */ |
791 | 0 | break; |
792 | 0 | } |
793 | 0 | PORT_Memset(plainText.data, 0, plainText.len); |
794 | 0 | } |
795 | 0 | } |
796 | 0 | } |
797 | 0 | PORT_Assert(templateIndex <= count); |
798 | 0 | PZ_Unlock(sessObject->attributeLock); |
799 | |
|
800 | 0 | if (*crv != CKR_OK) { |
801 | 0 | return NULL; |
802 | 0 | } |
803 | 0 | if (pcount) { |
804 | 0 | *pcount = count; |
805 | 0 | } |
806 | 0 | return template; |
807 | 0 | } |
808 | | |
809 | | /* |
810 | | * return a pointer to the attribute in the give template. |
811 | | * The return value is not const, as the caller may modify |
812 | | * the given attribute value, but such modifications will |
813 | | * modify the actual value in the template. |
814 | | */ |
815 | | static CK_ATTRIBUTE * |
816 | | sftkdb_getAttributeFromTemplate(CK_ATTRIBUTE_TYPE attribute, |
817 | | CK_ATTRIBUTE *ptemplate, CK_ULONG len) |
818 | 0 | { |
819 | 0 | CK_ULONG i; |
820 | |
|
821 | 0 | for (i = 0; i < len; i++) { |
822 | 0 | if (attribute == ptemplate[i].type) { |
823 | 0 | return &ptemplate[i]; |
824 | 0 | } |
825 | 0 | } |
826 | 0 | return NULL; |
827 | 0 | } |
828 | | |
829 | | static const CK_ATTRIBUTE * |
830 | | sftkdb_getAttributeFromConstTemplate(CK_ATTRIBUTE_TYPE attribute, |
831 | | const CK_ATTRIBUTE *ptemplate, CK_ULONG len) |
832 | 0 | { |
833 | 0 | CK_ULONG i; |
834 | |
|
835 | 0 | for (i = 0; i < len; i++) { |
836 | 0 | if (attribute == ptemplate[i].type) { |
837 | 0 | return &ptemplate[i]; |
838 | 0 | } |
839 | 0 | } |
840 | 0 | return NULL; |
841 | 0 | } |
842 | | |
843 | | /* |
844 | | * fetch a template which identifies 'unique' entries based on object type |
845 | | */ |
846 | | static CK_RV |
847 | | sftkdb_getFindTemplate(CK_OBJECT_CLASS objectType, unsigned char *objTypeData, |
848 | | CK_ATTRIBUTE *findTemplate, CK_ULONG *findCount, |
849 | | CK_ATTRIBUTE *ptemplate, int len) |
850 | 0 | { |
851 | 0 | CK_ATTRIBUTE *attr; |
852 | 0 | CK_ULONG count = 1; |
853 | |
|
854 | 0 | sftk_ULong2SDBULong(objTypeData, objectType); |
855 | 0 | findTemplate[0].type = CKA_CLASS; |
856 | 0 | findTemplate[0].pValue = objTypeData; |
857 | 0 | findTemplate[0].ulValueLen = SDB_ULONG_SIZE; |
858 | |
|
859 | 0 | switch (objectType) { |
860 | 0 | case CKO_CERTIFICATE: |
861 | 0 | case CKO_NSS_TRUST: |
862 | 0 | attr = sftkdb_getAttributeFromTemplate(CKA_ISSUER, ptemplate, len); |
863 | 0 | if (attr == NULL) { |
864 | 0 | return CKR_TEMPLATE_INCOMPLETE; |
865 | 0 | } |
866 | 0 | findTemplate[1] = *attr; |
867 | 0 | attr = sftkdb_getAttributeFromTemplate(CKA_SERIAL_NUMBER, |
868 | 0 | ptemplate, len); |
869 | 0 | if (attr == NULL) { |
870 | 0 | return CKR_TEMPLATE_INCOMPLETE; |
871 | 0 | } |
872 | 0 | findTemplate[2] = *attr; |
873 | 0 | count = 3; |
874 | 0 | break; |
875 | | |
876 | 0 | case CKO_PRIVATE_KEY: |
877 | 0 | case CKO_PUBLIC_KEY: |
878 | 0 | case CKO_SECRET_KEY: |
879 | 0 | attr = sftkdb_getAttributeFromTemplate(CKA_ID, ptemplate, len); |
880 | 0 | if (attr == NULL) { |
881 | 0 | return CKR_TEMPLATE_INCOMPLETE; |
882 | 0 | } |
883 | 0 | if (attr->ulValueLen == 0) { |
884 | | /* key is too generic to determine that it's unique, usually |
885 | | * happens in the key gen case */ |
886 | 0 | return CKR_OBJECT_HANDLE_INVALID; |
887 | 0 | } |
888 | | |
889 | 0 | findTemplate[1] = *attr; |
890 | 0 | count = 2; |
891 | 0 | break; |
892 | | |
893 | 0 | case CKO_NSS_CRL: |
894 | 0 | attr = sftkdb_getAttributeFromTemplate(CKA_SUBJECT, ptemplate, len); |
895 | 0 | if (attr == NULL) { |
896 | 0 | return CKR_TEMPLATE_INCOMPLETE; |
897 | 0 | } |
898 | 0 | findTemplate[1] = *attr; |
899 | 0 | count = 2; |
900 | 0 | break; |
901 | | |
902 | 0 | case CKO_NSS_SMIME: |
903 | 0 | attr = sftkdb_getAttributeFromTemplate(CKA_SUBJECT, ptemplate, len); |
904 | 0 | if (attr == NULL) { |
905 | 0 | return CKR_TEMPLATE_INCOMPLETE; |
906 | 0 | } |
907 | 0 | findTemplate[1] = *attr; |
908 | 0 | attr = sftkdb_getAttributeFromTemplate(CKA_NSS_EMAIL, ptemplate, len); |
909 | 0 | if (attr == NULL) { |
910 | 0 | return CKR_TEMPLATE_INCOMPLETE; |
911 | 0 | } |
912 | 0 | findTemplate[2] = *attr; |
913 | 0 | count = 3; |
914 | 0 | break; |
915 | 0 | default: |
916 | 0 | attr = sftkdb_getAttributeFromTemplate(CKA_VALUE, ptemplate, len); |
917 | 0 | if (attr == NULL) { |
918 | 0 | return CKR_TEMPLATE_INCOMPLETE; |
919 | 0 | } |
920 | 0 | findTemplate[1] = *attr; |
921 | 0 | count = 2; |
922 | 0 | break; |
923 | 0 | } |
924 | 0 | *findCount = count; |
925 | |
|
926 | 0 | return CKR_OK; |
927 | 0 | } |
928 | | |
929 | | /* |
930 | | * look to see if this object already exists and return its object ID if |
931 | | * it does. |
932 | | */ |
933 | | static CK_RV |
934 | | sftkdb_lookupObject(SDB *db, CK_OBJECT_CLASS objectType, |
935 | | CK_OBJECT_HANDLE *id, CK_ATTRIBUTE *ptemplate, CK_ULONG len) |
936 | 0 | { |
937 | 0 | CK_ATTRIBUTE findTemplate[3]; |
938 | 0 | CK_ULONG count = 1; |
939 | 0 | CK_ULONG objCount = 0; |
940 | 0 | SDBFind *find = NULL; |
941 | 0 | unsigned char objTypeData[SDB_ULONG_SIZE]; |
942 | 0 | CK_RV crv; |
943 | |
|
944 | 0 | *id = CK_INVALID_HANDLE; |
945 | 0 | if (objectType == CKO_NSS_CRL) { |
946 | 0 | return CKR_OK; |
947 | 0 | } |
948 | 0 | crv = sftkdb_getFindTemplate(objectType, objTypeData, |
949 | 0 | findTemplate, &count, ptemplate, len); |
950 | |
|
951 | 0 | if (crv == CKR_OBJECT_HANDLE_INVALID) { |
952 | | /* key is too generic to determine that it's unique, usually |
953 | | * happens in the key gen case, tell the caller to go ahead |
954 | | * and just create it */ |
955 | 0 | return CKR_OK; |
956 | 0 | } |
957 | 0 | if (crv != CKR_OK) { |
958 | 0 | return crv; |
959 | 0 | } |
960 | | |
961 | | /* use the raw find, so we get the correct database */ |
962 | 0 | crv = (*db->sdb_FindObjectsInit)(db, findTemplate, count, &find); |
963 | 0 | if (crv != CKR_OK) { |
964 | 0 | return crv; |
965 | 0 | } |
966 | 0 | (*db->sdb_FindObjects)(db, find, id, 1, &objCount); |
967 | 0 | (*db->sdb_FindObjectsFinal)(db, find); |
968 | |
|
969 | 0 | if (objCount == 0) { |
970 | 0 | *id = CK_INVALID_HANDLE; |
971 | 0 | } |
972 | 0 | return CKR_OK; |
973 | 0 | } |
974 | | |
975 | | /* |
976 | | * check to see if this template conflicts with others in our current database. |
977 | | */ |
978 | | static CK_RV |
979 | | sftkdb_checkConflicts(SDB *db, CK_OBJECT_CLASS objectType, |
980 | | const CK_ATTRIBUTE *ptemplate, CK_ULONG len, |
981 | | CK_OBJECT_HANDLE sourceID) |
982 | 0 | { |
983 | 0 | CK_ATTRIBUTE findTemplate[2]; |
984 | 0 | unsigned char objTypeData[SDB_ULONG_SIZE]; |
985 | | /* we may need to allocate some temporaries. Keep track of what was |
986 | | * allocated so we can free it in the end */ |
987 | 0 | unsigned char *temp1 = NULL; |
988 | 0 | unsigned char *temp2 = NULL; |
989 | 0 | CK_ULONG objCount = 0; |
990 | 0 | SDBFind *find = NULL; |
991 | 0 | CK_OBJECT_HANDLE id; |
992 | 0 | const CK_ATTRIBUTE *attr, *attr2; |
993 | 0 | CK_RV crv; |
994 | 0 | CK_ATTRIBUTE subject; |
995 | | |
996 | | /* Currently the only conflict is with nicknames pointing to the same |
997 | | * subject when creating or modifying a certificate. */ |
998 | | /* If the object is not a cert, no problem. */ |
999 | 0 | if (objectType != CKO_CERTIFICATE) { |
1000 | 0 | return CKR_OK; |
1001 | 0 | } |
1002 | | /* if not setting a nickname then there's still no problem */ |
1003 | 0 | attr = sftkdb_getAttributeFromConstTemplate(CKA_LABEL, ptemplate, len); |
1004 | 0 | if ((attr == NULL) || (attr->ulValueLen == 0)) { |
1005 | 0 | return CKR_OK; |
1006 | 0 | } |
1007 | | /* fetch the subject of the source. For creation and merge, this should |
1008 | | * be found in the template */ |
1009 | 0 | attr2 = sftkdb_getAttributeFromConstTemplate(CKA_SUBJECT, ptemplate, len); |
1010 | 0 | if (sourceID == CK_INVALID_HANDLE) { |
1011 | 0 | if ((attr2 == NULL) || ((CK_LONG)attr2->ulValueLen < 0)) { |
1012 | 0 | crv = CKR_TEMPLATE_INCOMPLETE; |
1013 | 0 | goto done; |
1014 | 0 | } |
1015 | 0 | } else if ((attr2 == NULL) || ((CK_LONG)attr2->ulValueLen <= 0)) { |
1016 | | /* sourceID is set if we are trying to modify an existing entry instead |
1017 | | * of creating a new one. In this case the subject may not be (probably |
1018 | | * isn't) in the template, we have to read it from the database */ |
1019 | 0 | subject.type = CKA_SUBJECT; |
1020 | 0 | subject.pValue = NULL; |
1021 | 0 | subject.ulValueLen = 0; |
1022 | 0 | crv = (*db->sdb_GetAttributeValue)(db, sourceID, &subject, 1); |
1023 | 0 | if (crv != CKR_OK) { |
1024 | 0 | goto done; |
1025 | 0 | } |
1026 | 0 | if ((CK_LONG)subject.ulValueLen < 0) { |
1027 | 0 | crv = CKR_DEVICE_ERROR; /* closest pkcs11 error to corrupted DB */ |
1028 | 0 | goto done; |
1029 | 0 | } |
1030 | 0 | temp1 = subject.pValue = PORT_Alloc(++subject.ulValueLen); |
1031 | 0 | if (temp1 == NULL) { |
1032 | 0 | crv = CKR_HOST_MEMORY; |
1033 | 0 | goto done; |
1034 | 0 | } |
1035 | 0 | crv = (*db->sdb_GetAttributeValue)(db, sourceID, &subject, 1); |
1036 | 0 | if (crv != CKR_OK) { |
1037 | 0 | goto done; |
1038 | 0 | } |
1039 | 0 | attr2 = &subject; |
1040 | 0 | } |
1041 | | |
1042 | | /* check for another cert in the database with the same nickname */ |
1043 | 0 | sftk_ULong2SDBULong(objTypeData, objectType); |
1044 | 0 | findTemplate[0].type = CKA_CLASS; |
1045 | 0 | findTemplate[0].pValue = objTypeData; |
1046 | 0 | findTemplate[0].ulValueLen = SDB_ULONG_SIZE; |
1047 | 0 | findTemplate[1] = *attr; |
1048 | |
|
1049 | 0 | crv = (*db->sdb_FindObjectsInit)(db, findTemplate, 2, &find); |
1050 | 0 | if (crv != CKR_OK) { |
1051 | 0 | goto done; |
1052 | 0 | } |
1053 | 0 | (*db->sdb_FindObjects)(db, find, &id, 1, &objCount); |
1054 | 0 | (*db->sdb_FindObjectsFinal)(db, find); |
1055 | | |
1056 | | /* object count == 0 means no conflicting certs found, |
1057 | | * go on with the operation */ |
1058 | 0 | if (objCount == 0) { |
1059 | 0 | crv = CKR_OK; |
1060 | 0 | goto done; |
1061 | 0 | } |
1062 | | |
1063 | | /* There is a least one cert that shares the nickname, make sure it also |
1064 | | * matches the subject. */ |
1065 | 0 | findTemplate[0] = *attr2; |
1066 | | /* we know how big the source subject was. Use that length to create the |
1067 | | * space for the target. If it's not enough space, then it means the |
1068 | | * source subject is too big, and therefore not a match. GetAttributeValue |
1069 | | * will return CKR_BUFFER_TOO_SMALL. Otherwise it should be exactly enough |
1070 | | * space (or enough space to be able to compare the result. */ |
1071 | 0 | temp2 = findTemplate[0].pValue = PORT_Alloc(++findTemplate[0].ulValueLen); |
1072 | 0 | if (temp2 == NULL) { |
1073 | 0 | crv = CKR_HOST_MEMORY; |
1074 | 0 | goto done; |
1075 | 0 | } |
1076 | 0 | crv = (*db->sdb_GetAttributeValue)(db, id, findTemplate, 1); |
1077 | 0 | if (crv != CKR_OK) { |
1078 | 0 | if (crv == CKR_BUFFER_TOO_SMALL) { |
1079 | | /* if our buffer is too small, then the Subjects clearly do |
1080 | | * not match */ |
1081 | 0 | crv = CKR_ATTRIBUTE_VALUE_INVALID; |
1082 | 0 | goto loser; |
1083 | 0 | } |
1084 | | /* otherwise we couldn't get the value, just fail */ |
1085 | 0 | goto done; |
1086 | 0 | } |
1087 | | |
1088 | | /* Ok, we have both subjects, make sure they are the same. |
1089 | | * Compare the subjects */ |
1090 | 0 | if ((findTemplate[0].ulValueLen != attr2->ulValueLen) || |
1091 | 0 | (attr2->ulValueLen > 0 && |
1092 | 0 | PORT_Memcmp(findTemplate[0].pValue, attr2->pValue, attr2->ulValueLen) != 0)) { |
1093 | 0 | crv = CKR_ATTRIBUTE_VALUE_INVALID; |
1094 | 0 | goto loser; |
1095 | 0 | } |
1096 | 0 | crv = CKR_OK; |
1097 | |
|
1098 | 0 | done: |
1099 | | /* If we've failed for some other reason than a conflict, make sure we |
1100 | | * return an error code other than CKR_ATTRIBUTE_VALUE_INVALID. |
1101 | | * (NOTE: neither sdb_FindObjectsInit nor sdb_GetAttributeValue should |
1102 | | * return CKR_ATTRIBUTE_VALUE_INVALID, so the following is paranoia). |
1103 | | */ |
1104 | 0 | if (crv == CKR_ATTRIBUTE_VALUE_INVALID) { |
1105 | 0 | crv = CKR_GENERAL_ERROR; /* clearly a programming error */ |
1106 | 0 | } |
1107 | | |
1108 | | /* exit point if we found a conflict */ |
1109 | 0 | loser: |
1110 | 0 | PORT_Free(temp1); |
1111 | 0 | PORT_Free(temp2); |
1112 | 0 | return crv; |
1113 | 0 | } |
1114 | | |
1115 | | /* |
1116 | | * try to update the template to fix any errors. This is only done |
1117 | | * during update. |
1118 | | * |
1119 | | * NOTE: we must update the template or return an error, or the update caller |
1120 | | * will loop forever! |
1121 | | * |
1122 | | * Two copies of the source code for this algorithm exist in NSS. |
1123 | | * Changes must be made in both copies. |
1124 | | * The other copy is in pk11_IncrementNickname() in pk11wrap/pk11merge.c. |
1125 | | * |
1126 | | */ |
1127 | | static CK_RV |
1128 | | sftkdb_resolveConflicts(PLArenaPool *arena, CK_OBJECT_CLASS objectType, |
1129 | | CK_ATTRIBUTE *ptemplate, CK_ULONG *plen) |
1130 | 0 | { |
1131 | 0 | CK_ATTRIBUTE *attr; |
1132 | 0 | char *nickname, *newNickname; |
1133 | 0 | unsigned int end, digit; |
1134 | | |
1135 | | /* sanity checks. We should never get here with these errors */ |
1136 | 0 | if (objectType != CKO_CERTIFICATE) { |
1137 | 0 | return CKR_GENERAL_ERROR; /* shouldn't happen */ |
1138 | 0 | } |
1139 | 0 | attr = sftkdb_getAttributeFromTemplate(CKA_LABEL, ptemplate, *plen); |
1140 | 0 | if ((attr == NULL) || (attr->ulValueLen == 0)) { |
1141 | 0 | return CKR_GENERAL_ERROR; /* shouldn't happen */ |
1142 | 0 | } |
1143 | | |
1144 | | /* update the nickname */ |
1145 | | /* is there a number at the end of the nickname already? |
1146 | | * if so just increment that number */ |
1147 | 0 | nickname = (char *)attr->pValue; |
1148 | | |
1149 | | /* does nickname end with " #n*" ? */ |
1150 | 0 | for (end = attr->ulValueLen - 1; |
1151 | 0 | end >= 2 && (digit = nickname[end]) <= '9' && digit >= '0'; |
1152 | 0 | end--) /* just scan */ |
1153 | 0 | ; |
1154 | 0 | if (attr->ulValueLen >= 3 && |
1155 | 0 | end < (attr->ulValueLen - 1) /* at least one digit */ && |
1156 | 0 | nickname[end] == '#' && |
1157 | 0 | nickname[end - 1] == ' ') { |
1158 | | /* Already has a suitable suffix string */ |
1159 | 0 | } else { |
1160 | | /* ... append " #2" to the name */ |
1161 | 0 | static const char num2[] = " #2"; |
1162 | 0 | newNickname = PORT_ArenaAlloc(arena, attr->ulValueLen + sizeof(num2)); |
1163 | 0 | if (!newNickname) { |
1164 | 0 | return CKR_HOST_MEMORY; |
1165 | 0 | } |
1166 | 0 | PORT_Memcpy(newNickname, nickname, attr->ulValueLen); |
1167 | 0 | PORT_Memcpy(&newNickname[attr->ulValueLen], num2, sizeof(num2)); |
1168 | 0 | attr->pValue = newNickname; /* modifies ptemplate */ |
1169 | 0 | attr->ulValueLen += 3; /* 3 is strlen(num2) */ |
1170 | 0 | return CKR_OK; |
1171 | 0 | } |
1172 | | |
1173 | 0 | for (end = attr->ulValueLen; end-- > 0;) { |
1174 | 0 | digit = nickname[end]; |
1175 | 0 | if (digit > '9' || digit < '0') { |
1176 | 0 | break; |
1177 | 0 | } |
1178 | 0 | if (digit < '9') { |
1179 | 0 | nickname[end]++; |
1180 | 0 | return CKR_OK; |
1181 | 0 | } |
1182 | 0 | nickname[end] = '0'; |
1183 | 0 | } |
1184 | | |
1185 | | /* we overflowed, insert a new '1' for a carry in front of the number */ |
1186 | 0 | newNickname = PORT_ArenaAlloc(arena, attr->ulValueLen + 1); |
1187 | 0 | if (!newNickname) { |
1188 | 0 | return CKR_HOST_MEMORY; |
1189 | 0 | } |
1190 | | /* PORT_Memcpy should handle len of '0' */ |
1191 | 0 | PORT_Memcpy(newNickname, nickname, ++end); |
1192 | 0 | newNickname[end] = '1'; |
1193 | 0 | PORT_Memset(&newNickname[end + 1], '0', attr->ulValueLen - end); |
1194 | 0 | attr->pValue = newNickname; |
1195 | 0 | attr->ulValueLen++; |
1196 | 0 | return CKR_OK; |
1197 | 0 | } |
1198 | | |
1199 | | /* |
1200 | | * set an attribute and sign it if necessary |
1201 | | */ |
1202 | | static CK_RV |
1203 | | sftkdb_setAttributeValue(PLArenaPool *arena, SFTKDBHandle *handle, |
1204 | | SDB *db, CK_OBJECT_HANDLE objectID, const CK_ATTRIBUTE *template, |
1205 | | CK_ULONG count) |
1206 | 0 | { |
1207 | 0 | CK_RV crv; |
1208 | 0 | crv = (*db->sdb_SetAttributeValue)(db, objectID, template, count); |
1209 | 0 | if (crv != CKR_OK) { |
1210 | 0 | return crv; |
1211 | 0 | } |
1212 | 0 | crv = sftk_signTemplate(arena, handle, db == handle->update, |
1213 | 0 | objectID, template, count); |
1214 | 0 | return crv; |
1215 | 0 | } |
1216 | | |
1217 | | /* |
1218 | | * write a softoken object out to the database. |
1219 | | */ |
1220 | | CK_RV |
1221 | | sftkdb_write(SFTKDBHandle *handle, SFTKObject *object, |
1222 | | CK_OBJECT_HANDLE *objectID) |
1223 | 0 | { |
1224 | 0 | CK_ATTRIBUTE *template; |
1225 | 0 | PLArenaPool *arena; |
1226 | 0 | CK_ULONG count; |
1227 | 0 | CK_RV crv; |
1228 | 0 | SDB *db; |
1229 | 0 | PRBool inTransaction = PR_FALSE; |
1230 | 0 | CK_OBJECT_HANDLE id, candidateID; |
1231 | |
|
1232 | 0 | *objectID = CK_INVALID_HANDLE; |
1233 | |
|
1234 | 0 | if (handle == NULL) { |
1235 | 0 | return CKR_TOKEN_WRITE_PROTECTED; |
1236 | 0 | } |
1237 | 0 | db = SFTK_GET_SDB(handle); |
1238 | | |
1239 | | /* |
1240 | | * we have opened a new database, but we have not yet updated it. We are |
1241 | | * still running pointing to the old database (so the application can |
1242 | | * still read). We don't want to write to the old database at this point, |
1243 | | * however, since it leads to user confusion. So at this point we simply |
1244 | | * require a user login. Let NSS know this so it can prompt the user. |
1245 | | */ |
1246 | 0 | if (db == handle->update) { |
1247 | 0 | return CKR_USER_NOT_LOGGED_IN; |
1248 | 0 | } |
1249 | | |
1250 | 0 | arena = PORT_NewArena(256); |
1251 | 0 | if (arena == NULL) { |
1252 | 0 | return CKR_HOST_MEMORY; |
1253 | 0 | } |
1254 | | |
1255 | 0 | crv = (*db->sdb_Begin)(db); |
1256 | 0 | if (crv != CKR_OK) { |
1257 | 0 | goto loser; |
1258 | 0 | } |
1259 | 0 | inTransaction = PR_TRUE; |
1260 | |
|
1261 | 0 | crv = (*db->sdb_GetNewObjectID)(db, &candidateID); |
1262 | 0 | if (crv != CKR_OK) { |
1263 | 0 | goto loser; |
1264 | 0 | } |
1265 | | |
1266 | 0 | template = sftk_ExtractTemplate(arena, object, handle, candidateID, db, &count, &crv); |
1267 | 0 | if (!template) { |
1268 | 0 | goto loser; |
1269 | 0 | } |
1270 | | |
1271 | | /* |
1272 | | * We want to make the base database as free from object specific knowledge |
1273 | | * as possible. To maintain compatibility, keep some of the desirable |
1274 | | * object specific semantics of the old database. |
1275 | | * |
1276 | | * These were 2 fold: |
1277 | | * 1) there were certain conflicts (like trying to set the same nickname |
1278 | | * on two different subjects) that would return an error. |
1279 | | * 2) Importing the 'same' object would silently update that object. |
1280 | | * |
1281 | | * The following 2 functions mimic the desirable effects of these two |
1282 | | * semantics without pushing any object knowledge to the underlying database |
1283 | | * code. |
1284 | | */ |
1285 | | |
1286 | | /* make sure we don't have attributes that conflict with the existing DB */ |
1287 | 0 | crv = sftkdb_checkConflicts(db, object->objclass, template, count, |
1288 | 0 | CK_INVALID_HANDLE); |
1289 | 0 | if (crv != CKR_OK) { |
1290 | 0 | goto loser; |
1291 | 0 | } |
1292 | | /* Find any copies that match this particular object */ |
1293 | 0 | crv = sftkdb_lookupObject(db, object->objclass, &id, template, count); |
1294 | 0 | if (crv != CKR_OK) { |
1295 | 0 | goto loser; |
1296 | 0 | } |
1297 | 0 | if (id == CK_INVALID_HANDLE) { |
1298 | 0 | *objectID = candidateID; |
1299 | 0 | crv = sftkdb_CreateObject(arena, handle, db, objectID, template, count); |
1300 | 0 | } else { |
1301 | | /* object already exists, modify it's attributes */ |
1302 | 0 | *objectID = id; |
1303 | | /* The object ID changed from our candidate, we need to move any |
1304 | | * signature attribute signatures to the new object ID. */ |
1305 | 0 | crv = sftkdb_fixupSignatures(handle, db, candidateID, id, |
1306 | 0 | template, count); |
1307 | 0 | if (crv != CKR_OK) { |
1308 | 0 | goto loser; |
1309 | 0 | } |
1310 | 0 | crv = sftkdb_setAttributeValue(arena, handle, db, id, template, count); |
1311 | 0 | } |
1312 | 0 | if (crv != CKR_OK) { |
1313 | 0 | goto loser; |
1314 | 0 | } |
1315 | 0 | crv = (*db->sdb_Commit)(db); |
1316 | 0 | inTransaction = PR_FALSE; |
1317 | |
|
1318 | 0 | loser: |
1319 | 0 | if (inTransaction) { |
1320 | 0 | (*db->sdb_Abort)(db); |
1321 | | /* It is trivial to show the following code cannot |
1322 | | * happen unless something is horribly wrong with our compilier or |
1323 | | * hardware */ |
1324 | 0 | PORT_Assert(crv != CKR_OK); |
1325 | 0 | if (crv == CKR_OK) |
1326 | 0 | crv = CKR_GENERAL_ERROR; |
1327 | 0 | } |
1328 | |
|
1329 | 0 | if (arena) { |
1330 | 0 | PORT_FreeArena(arena, PR_TRUE); |
1331 | 0 | } |
1332 | 0 | if (crv == CKR_OK) { |
1333 | 0 | *objectID |= (handle->type | SFTK_TOKEN_TYPE); |
1334 | 0 | } |
1335 | 0 | return crv; |
1336 | 0 | } |
1337 | | |
1338 | | CK_RV |
1339 | | sftkdb_FindObjectsInit(SFTKDBHandle *handle, const CK_ATTRIBUTE *template, |
1340 | | CK_ULONG count, SDBFind **find) |
1341 | 8 | { |
1342 | 8 | unsigned char *data = NULL; |
1343 | 8 | CK_ATTRIBUTE *ntemplate = NULL; |
1344 | 8 | CK_RV crv; |
1345 | 8 | int dataSize; |
1346 | 8 | SDB *db; |
1347 | | |
1348 | 8 | if (handle == NULL) { |
1349 | 8 | return CKR_OK; |
1350 | 8 | } |
1351 | 0 | db = SFTK_GET_SDB(handle); |
1352 | |
|
1353 | 0 | if (count != 0) { |
1354 | 0 | ntemplate = sftkdb_fixupTemplateIn(template, count, &data, &dataSize); |
1355 | 0 | if (ntemplate == NULL) { |
1356 | 0 | return CKR_HOST_MEMORY; |
1357 | 0 | } |
1358 | 0 | } |
1359 | | |
1360 | 0 | crv = (*db->sdb_FindObjectsInit)(db, ntemplate, |
1361 | 0 | count, find); |
1362 | 0 | if (data) { |
1363 | 0 | PORT_Free(ntemplate); |
1364 | 0 | PORT_ZFree(data, dataSize); |
1365 | 0 | } |
1366 | 0 | return crv; |
1367 | 0 | } |
1368 | | |
1369 | | CK_RV |
1370 | | sftkdb_FindObjects(SFTKDBHandle *handle, SDBFind *find, |
1371 | | CK_OBJECT_HANDLE *ids, int arraySize, CK_ULONG *count) |
1372 | 8 | { |
1373 | 8 | CK_RV crv; |
1374 | 8 | SDB *db; |
1375 | | |
1376 | 8 | if (handle == NULL) { |
1377 | 8 | *count = 0; |
1378 | 8 | return CKR_OK; |
1379 | 8 | } |
1380 | 0 | db = SFTK_GET_SDB(handle); |
1381 | |
|
1382 | 0 | crv = (*db->sdb_FindObjects)(db, find, ids, |
1383 | 0 | arraySize, count); |
1384 | 0 | if (crv == CKR_OK) { |
1385 | 0 | unsigned int i; |
1386 | 0 | for (i = 0; i < *count; i++) { |
1387 | 0 | ids[i] |= (handle->type | SFTK_TOKEN_TYPE); |
1388 | 0 | } |
1389 | 0 | } |
1390 | 0 | return crv; |
1391 | 8 | } |
1392 | | |
1393 | | CK_RV |
1394 | | sftkdb_FindObjectsFinal(SFTKDBHandle *handle, SDBFind *find) |
1395 | 8 | { |
1396 | 8 | SDB *db; |
1397 | 8 | if (handle == NULL) { |
1398 | 8 | return CKR_OK; |
1399 | 8 | } |
1400 | 0 | db = SFTK_GET_SDB(handle); |
1401 | 0 | return (*db->sdb_FindObjectsFinal)(db, find); |
1402 | 8 | } |
1403 | | |
1404 | | CK_RV |
1405 | | sftkdb_GetAttributeValue(SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID, |
1406 | | CK_ATTRIBUTE *template, CK_ULONG count) |
1407 | 0 | { |
1408 | 0 | CK_RV crv, crv2; |
1409 | 0 | CK_ATTRIBUTE *ntemplate; |
1410 | 0 | unsigned char *data = NULL; |
1411 | 0 | int dataSize = 0; |
1412 | 0 | SDB *db; |
1413 | |
|
1414 | 0 | if (handle == NULL) { |
1415 | 0 | return CKR_GENERAL_ERROR; |
1416 | 0 | } |
1417 | | |
1418 | | /* short circuit common attributes */ |
1419 | 0 | if (count == 1 && |
1420 | 0 | (template[0].type == CKA_TOKEN || |
1421 | 0 | template[0].type == CKA_PRIVATE || |
1422 | 0 | template[0].type == CKA_SENSITIVE)) { |
1423 | 0 | CK_BBOOL boolVal = CK_TRUE; |
1424 | |
|
1425 | 0 | if (template[0].pValue == NULL) { |
1426 | 0 | template[0].ulValueLen = sizeof(CK_BBOOL); |
1427 | 0 | return CKR_OK; |
1428 | 0 | } |
1429 | 0 | if (template[0].ulValueLen < sizeof(CK_BBOOL)) { |
1430 | 0 | template[0].ulValueLen = -1; |
1431 | 0 | return CKR_BUFFER_TOO_SMALL; |
1432 | 0 | } |
1433 | | |
1434 | 0 | if ((template[0].type == CKA_PRIVATE) && |
1435 | 0 | (handle->type != SFTK_KEYDB_TYPE)) { |
1436 | 0 | boolVal = CK_FALSE; |
1437 | 0 | } |
1438 | 0 | if ((template[0].type == CKA_SENSITIVE) && |
1439 | 0 | (handle->type != SFTK_KEYDB_TYPE)) { |
1440 | 0 | boolVal = CK_FALSE; |
1441 | 0 | } |
1442 | 0 | *(CK_BBOOL *)template[0].pValue = boolVal; |
1443 | 0 | template[0].ulValueLen = sizeof(CK_BBOOL); |
1444 | 0 | return CKR_OK; |
1445 | 0 | } |
1446 | | |
1447 | 0 | db = SFTK_GET_SDB(handle); |
1448 | | /* nothing to do */ |
1449 | 0 | if (count == 0) { |
1450 | 0 | return CKR_OK; |
1451 | 0 | } |
1452 | 0 | ntemplate = sftkdb_fixupTemplateIn(template, count, &data, &dataSize); |
1453 | 0 | if (ntemplate == NULL) { |
1454 | 0 | return CKR_HOST_MEMORY; |
1455 | 0 | } |
1456 | 0 | objectID &= SFTK_OBJ_ID_MASK; |
1457 | 0 | crv = (*db->sdb_GetAttributeValue)(db, objectID, |
1458 | 0 | ntemplate, count); |
1459 | 0 | crv2 = sftkdb_fixupTemplateOut(template, objectID, ntemplate, |
1460 | 0 | count, handle); |
1461 | 0 | if (crv == CKR_OK) |
1462 | 0 | crv = crv2; |
1463 | 0 | if (data) { |
1464 | 0 | PORT_Free(ntemplate); |
1465 | 0 | PORT_ZFree(data, dataSize); |
1466 | 0 | } |
1467 | 0 | return crv; |
1468 | 0 | } |
1469 | | |
1470 | | CK_RV |
1471 | | sftkdb_SetAttributeValue(SFTKDBHandle *handle, SFTKObject *object, |
1472 | | const CK_ATTRIBUTE *template, CK_ULONG count) |
1473 | 0 | { |
1474 | 0 | CK_ATTRIBUTE *ntemplate; |
1475 | 0 | unsigned char *data = NULL; |
1476 | 0 | PLArenaPool *arena = NULL; |
1477 | 0 | SDB *db; |
1478 | 0 | CK_RV crv = CKR_OK; |
1479 | 0 | CK_OBJECT_HANDLE objectID = (object->handle & SFTK_OBJ_ID_MASK); |
1480 | 0 | PRBool inTransaction = PR_FALSE; |
1481 | 0 | int dataSize; |
1482 | |
|
1483 | 0 | if (handle == NULL) { |
1484 | 0 | return CKR_TOKEN_WRITE_PROTECTED; |
1485 | 0 | } |
1486 | | |
1487 | 0 | db = SFTK_GET_SDB(handle); |
1488 | | /* nothing to do */ |
1489 | 0 | if (count == 0) { |
1490 | 0 | return CKR_OK; |
1491 | 0 | } |
1492 | | /* |
1493 | | * we have opened a new database, but we have not yet updated it. We are |
1494 | | * still running pointing to the old database (so the application can |
1495 | | * still read). We don't want to write to the old database at this point, |
1496 | | * however, since it leads to user confusion. So at this point we simply |
1497 | | * require a user login. Let NSS know this so it can prompt the user. |
1498 | | */ |
1499 | 0 | if (db == handle->update) { |
1500 | 0 | return CKR_USER_NOT_LOGGED_IN; |
1501 | 0 | } |
1502 | | |
1503 | 0 | ntemplate = sftkdb_fixupTemplateIn(template, count, &data, &dataSize); |
1504 | 0 | if (ntemplate == NULL) { |
1505 | 0 | return CKR_HOST_MEMORY; |
1506 | 0 | } |
1507 | | |
1508 | | /* make sure we don't have attributes that conflict with the existing DB */ |
1509 | 0 | crv = sftkdb_checkConflicts(db, object->objclass, ntemplate, count, |
1510 | 0 | objectID); |
1511 | 0 | if (crv != CKR_OK) { |
1512 | 0 | goto loser; |
1513 | 0 | } |
1514 | | |
1515 | 0 | arena = PORT_NewArena(256); |
1516 | 0 | if (arena == NULL) { |
1517 | 0 | crv = CKR_HOST_MEMORY; |
1518 | 0 | goto loser; |
1519 | 0 | } |
1520 | | |
1521 | 0 | crv = (*db->sdb_Begin)(db); |
1522 | 0 | if (crv != CKR_OK) { |
1523 | 0 | goto loser; |
1524 | 0 | } |
1525 | 0 | inTransaction = PR_TRUE; |
1526 | 0 | crv = sftkdb_setAttributeValue(arena, handle, db, objectID, ntemplate, |
1527 | 0 | count); |
1528 | 0 | if (crv != CKR_OK) { |
1529 | 0 | goto loser; |
1530 | 0 | } |
1531 | 0 | crv = (*db->sdb_Commit)(db); |
1532 | 0 | loser: |
1533 | 0 | if (crv != CKR_OK && inTransaction) { |
1534 | 0 | (*db->sdb_Abort)(db); |
1535 | 0 | } |
1536 | 0 | if (data) { |
1537 | 0 | PORT_Free(ntemplate); |
1538 | 0 | PORT_ZFree(data, dataSize); |
1539 | 0 | } |
1540 | 0 | if (arena) { |
1541 | 0 | PORT_FreeArena(arena, PR_FALSE); |
1542 | 0 | } |
1543 | 0 | return crv; |
1544 | 0 | } |
1545 | | |
1546 | | CK_RV |
1547 | | sftkdb_DestroyObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID, |
1548 | | CK_OBJECT_CLASS objclass) |
1549 | 0 | { |
1550 | 0 | CK_RV crv = CKR_OK; |
1551 | 0 | SDB *db; |
1552 | |
|
1553 | 0 | if (handle == NULL) { |
1554 | 0 | return CKR_TOKEN_WRITE_PROTECTED; |
1555 | 0 | } |
1556 | 0 | db = SFTK_GET_SDB(handle); |
1557 | 0 | objectID &= SFTK_OBJ_ID_MASK; |
1558 | |
|
1559 | 0 | crv = (*db->sdb_Begin)(db); |
1560 | 0 | if (crv != CKR_OK) { |
1561 | 0 | return crv; |
1562 | 0 | } |
1563 | 0 | crv = (*db->sdb_DestroyObject)(db, objectID); |
1564 | 0 | if (crv != CKR_OK) { |
1565 | 0 | goto loser; |
1566 | 0 | } |
1567 | | /* if the database supports meta data, delete any old signatures |
1568 | | * that we may have added */ |
1569 | 0 | if ((db->sdb_flags & SDB_HAS_META) == SDB_HAS_META) { |
1570 | 0 | SDB *keydb = db; |
1571 | 0 | if (handle->type == SFTK_KEYDB_TYPE) { |
1572 | | /* delete any private attribute signatures that might exist */ |
1573 | 0 | (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, |
1574 | 0 | CKA_VALUE); |
1575 | 0 | (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, |
1576 | 0 | CKA_PRIVATE_EXPONENT); |
1577 | 0 | (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, |
1578 | 0 | CKA_PRIME_1); |
1579 | 0 | (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, |
1580 | 0 | CKA_PRIME_2); |
1581 | 0 | (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, |
1582 | 0 | CKA_EXPONENT_1); |
1583 | 0 | (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, |
1584 | 0 | CKA_EXPONENT_2); |
1585 | 0 | (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, |
1586 | 0 | CKA_COEFFICIENT); |
1587 | 0 | } else { |
1588 | 0 | keydb = SFTK_GET_SDB(handle->peerDB); |
1589 | 0 | } |
1590 | | /* now destroy any authenticated attributes that may exist */ |
1591 | 0 | (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, |
1592 | 0 | CKA_MODULUS); |
1593 | 0 | (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, |
1594 | 0 | CKA_PUBLIC_EXPONENT); |
1595 | 0 | (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, |
1596 | 0 | CKA_CERT_SHA1_HASH); |
1597 | 0 | (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, |
1598 | 0 | CKA_CERT_MD5_HASH); |
1599 | 0 | (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, |
1600 | 0 | CKA_TRUST_SERVER_AUTH); |
1601 | 0 | (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, |
1602 | 0 | CKA_TRUST_CLIENT_AUTH); |
1603 | 0 | (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, |
1604 | 0 | CKA_TRUST_EMAIL_PROTECTION); |
1605 | 0 | (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, |
1606 | 0 | CKA_TRUST_CODE_SIGNING); |
1607 | 0 | (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, |
1608 | 0 | CKA_TRUST_STEP_UP_APPROVED); |
1609 | 0 | (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID, |
1610 | 0 | CKA_NSS_OVERRIDE_EXTENSIONS); |
1611 | 0 | } |
1612 | 0 | crv = (*db->sdb_Commit)(db); |
1613 | 0 | loser: |
1614 | 0 | if (crv != CKR_OK) { |
1615 | 0 | (*db->sdb_Abort)(db); |
1616 | 0 | } |
1617 | 0 | return crv; |
1618 | 0 | } |
1619 | | |
1620 | | CK_RV |
1621 | | sftkdb_CloseDB(SFTKDBHandle *handle) |
1622 | 0 | { |
1623 | 0 | #ifdef NO_FORK_CHECK |
1624 | 0 | PRBool parentForkedAfterC_Initialize = PR_FALSE; |
1625 | 0 | #endif |
1626 | 0 | if (handle == NULL) { |
1627 | 0 | return CKR_OK; |
1628 | 0 | } |
1629 | 0 | if (handle->update) { |
1630 | 0 | if (handle->db->sdb_SetForkState) { |
1631 | 0 | (*handle->db->sdb_SetForkState)(parentForkedAfterC_Initialize); |
1632 | 0 | } |
1633 | 0 | (*handle->update->sdb_Close)(handle->update); |
1634 | 0 | } |
1635 | 0 | if (handle->db) { |
1636 | 0 | if (handle->db->sdb_SetForkState) { |
1637 | 0 | (*handle->db->sdb_SetForkState)(parentForkedAfterC_Initialize); |
1638 | 0 | } |
1639 | 0 | (*handle->db->sdb_Close)(handle->db); |
1640 | 0 | } |
1641 | 0 | if (handle->passwordLock) { |
1642 | 0 | PZ_Lock(handle->passwordLock); |
1643 | 0 | } |
1644 | 0 | if (handle->passwordKey.data) { |
1645 | 0 | SECITEM_ZfreeItem(&handle->passwordKey, PR_FALSE); |
1646 | 0 | } |
1647 | 0 | if (handle->passwordLock) { |
1648 | 0 | PZ_Unlock(handle->passwordLock); |
1649 | 0 | SKIP_AFTER_FORK(PZ_DestroyLock(handle->passwordLock)); |
1650 | 0 | } |
1651 | 0 | if (handle->updatePasswordKey) { |
1652 | 0 | SECITEM_ZfreeItem(handle->updatePasswordKey, PR_TRUE); |
1653 | 0 | } |
1654 | 0 | if (handle->updateID) { |
1655 | 0 | PORT_Free(handle->updateID); |
1656 | 0 | } |
1657 | 0 | PORT_Free(handle); |
1658 | 0 | return CKR_OK; |
1659 | 0 | } |
1660 | | |
1661 | | /* |
1662 | | * reset a database to it's uninitialized state. |
1663 | | */ |
1664 | | static CK_RV |
1665 | | sftkdb_ResetDB(SFTKDBHandle *handle) |
1666 | 0 | { |
1667 | 0 | CK_RV crv = CKR_OK; |
1668 | 0 | SDB *db; |
1669 | 0 | if (handle == NULL) { |
1670 | 0 | return CKR_TOKEN_WRITE_PROTECTED; |
1671 | 0 | } |
1672 | 0 | db = SFTK_GET_SDB(handle); |
1673 | 0 | crv = (*db->sdb_Begin)(db); |
1674 | 0 | if (crv != CKR_OK) { |
1675 | 0 | goto loser; |
1676 | 0 | } |
1677 | 0 | crv = (*db->sdb_Reset)(db); |
1678 | 0 | if (crv != CKR_OK) { |
1679 | 0 | goto loser; |
1680 | 0 | } |
1681 | 0 | crv = (*db->sdb_Commit)(db); |
1682 | 0 | loser: |
1683 | 0 | if (crv != CKR_OK) { |
1684 | 0 | (*db->sdb_Abort)(db); |
1685 | 0 | } |
1686 | 0 | return crv; |
1687 | 0 | } |
1688 | | |
1689 | | CK_RV |
1690 | | sftkdb_Begin(SFTKDBHandle *handle) |
1691 | 0 | { |
1692 | 0 | CK_RV crv = CKR_OK; |
1693 | 0 | SDB *db; |
1694 | |
|
1695 | 0 | if (handle == NULL) { |
1696 | 0 | return CKR_OK; |
1697 | 0 | } |
1698 | 0 | db = SFTK_GET_SDB(handle); |
1699 | 0 | if (db) { |
1700 | 0 | crv = (*db->sdb_Begin)(db); |
1701 | 0 | } |
1702 | 0 | return crv; |
1703 | 0 | } |
1704 | | |
1705 | | CK_RV |
1706 | | sftkdb_Commit(SFTKDBHandle *handle) |
1707 | 0 | { |
1708 | 0 | CK_RV crv = CKR_OK; |
1709 | 0 | SDB *db; |
1710 | |
|
1711 | 0 | if (handle == NULL) { |
1712 | 0 | return CKR_OK; |
1713 | 0 | } |
1714 | 0 | db = SFTK_GET_SDB(handle); |
1715 | 0 | if (db) { |
1716 | 0 | (*db->sdb_Commit)(db); |
1717 | 0 | } |
1718 | 0 | return crv; |
1719 | 0 | } |
1720 | | |
1721 | | CK_RV |
1722 | | sftkdb_Abort(SFTKDBHandle *handle) |
1723 | 0 | { |
1724 | 0 | CK_RV crv = CKR_OK; |
1725 | 0 | SDB *db; |
1726 | |
|
1727 | 0 | if (handle == NULL) { |
1728 | 0 | return CKR_OK; |
1729 | 0 | } |
1730 | 0 | db = SFTK_GET_SDB(handle); |
1731 | 0 | if (db) { |
1732 | 0 | crv = (db->sdb_Abort)(db); |
1733 | 0 | } |
1734 | 0 | return crv; |
1735 | 0 | } |
1736 | | |
1737 | | /* |
1738 | | * functions to update the database from an old database |
1739 | | */ |
1740 | | |
1741 | | /* |
1742 | | * known attributes |
1743 | | */ |
1744 | | static const CK_ATTRIBUTE_TYPE known_attributes[] = { |
1745 | | CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_APPLICATION, |
1746 | | CKA_VALUE, CKA_OBJECT_ID, CKA_CERTIFICATE_TYPE, CKA_ISSUER, |
1747 | | CKA_SERIAL_NUMBER, CKA_AC_ISSUER, CKA_OWNER, CKA_ATTR_TYPES, CKA_TRUSTED, |
1748 | | CKA_CERTIFICATE_CATEGORY, CKA_JAVA_MIDP_SECURITY_DOMAIN, CKA_URL, |
1749 | | CKA_HASH_OF_SUBJECT_PUBLIC_KEY, CKA_HASH_OF_ISSUER_PUBLIC_KEY, |
1750 | | CKA_CHECK_VALUE, CKA_KEY_TYPE, CKA_SUBJECT, CKA_ID, CKA_SENSITIVE, |
1751 | | CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, CKA_SIGN, CKA_SIGN_RECOVER, |
1752 | | CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_DERIVE, CKA_START_DATE, CKA_END_DATE, |
1753 | | CKA_MODULUS, CKA_MODULUS_BITS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, |
1754 | | CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT, |
1755 | | CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_PRIME_BITS, |
1756 | | CKA_SUB_PRIME_BITS, CKA_VALUE_BITS, CKA_VALUE_LEN, CKA_EXTRACTABLE, |
1757 | | CKA_LOCAL, CKA_NEVER_EXTRACTABLE, CKA_ALWAYS_SENSITIVE, |
1758 | | CKA_KEY_GEN_MECHANISM, CKA_MODIFIABLE, CKA_EC_PARAMS, |
1759 | | CKA_EC_POINT, CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS, |
1760 | | CKA_ALWAYS_AUTHENTICATE, CKA_WRAP_WITH_TRUSTED, CKA_WRAP_TEMPLATE, |
1761 | | CKA_UNWRAP_TEMPLATE, CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT, |
1762 | | CKA_HAS_RESET, CKA_PIXEL_X, CKA_PIXEL_Y, CKA_RESOLUTION, CKA_CHAR_ROWS, |
1763 | | CKA_CHAR_COLUMNS, CKA_COLOR, CKA_BITS_PER_PIXEL, CKA_CHAR_SETS, |
1764 | | CKA_ENCODING_METHODS, CKA_MIME_TYPES, CKA_MECHANISM_TYPE, |
1765 | | CKA_REQUIRED_CMS_ATTRIBUTES, CKA_DEFAULT_CMS_ATTRIBUTES, |
1766 | | CKA_SUPPORTED_CMS_ATTRIBUTES, CKA_NSS_URL, CKA_NSS_EMAIL, |
1767 | | CKA_NSS_SMIME_INFO, CKA_NSS_SMIME_TIMESTAMP, |
1768 | | CKA_NSS_PKCS8_SALT, CKA_NSS_PASSWORD_CHECK, CKA_NSS_EXPIRES, |
1769 | | CKA_NSS_KRL, CKA_NSS_PQG_COUNTER, CKA_NSS_PQG_SEED, |
1770 | | CKA_NSS_PQG_H, CKA_NSS_PQG_SEED_BITS, CKA_NSS_MODULE_SPEC, |
1771 | | CKA_TRUST_DIGITAL_SIGNATURE, CKA_TRUST_NON_REPUDIATION, |
1772 | | CKA_TRUST_KEY_ENCIPHERMENT, CKA_TRUST_DATA_ENCIPHERMENT, |
1773 | | CKA_TRUST_KEY_AGREEMENT, CKA_TRUST_KEY_CERT_SIGN, CKA_TRUST_CRL_SIGN, |
1774 | | CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_CODE_SIGNING, |
1775 | | CKA_TRUST_EMAIL_PROTECTION, CKA_TRUST_IPSEC_END_SYSTEM, |
1776 | | CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, CKA_TRUST_TIME_STAMPING, |
1777 | | CKA_TRUST_STEP_UP_APPROVED, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH, |
1778 | | CKA_NSS_DB, CKA_NSS_TRUST, CKA_NSS_OVERRIDE_EXTENSIONS, |
1779 | | CKA_PUBLIC_KEY_INFO |
1780 | | }; |
1781 | | |
1782 | | static unsigned int known_attributes_size = sizeof(known_attributes) / |
1783 | | sizeof(known_attributes[0]); |
1784 | | |
1785 | | static CK_RV |
1786 | | sftkdb_GetObjectTemplate(SDB *source, CK_OBJECT_HANDLE id, |
1787 | | CK_ATTRIBUTE *ptemplate, CK_ULONG *max) |
1788 | 0 | { |
1789 | 0 | unsigned int i, j; |
1790 | 0 | CK_RV crv; |
1791 | |
|
1792 | 0 | if (*max < known_attributes_size) { |
1793 | 0 | *max = known_attributes_size; |
1794 | 0 | return CKR_BUFFER_TOO_SMALL; |
1795 | 0 | } |
1796 | 0 | for (i = 0; i < known_attributes_size; i++) { |
1797 | 0 | ptemplate[i].type = known_attributes[i]; |
1798 | 0 | ptemplate[i].pValue = NULL; |
1799 | 0 | ptemplate[i].ulValueLen = 0; |
1800 | 0 | } |
1801 | |
|
1802 | 0 | crv = (*source->sdb_GetAttributeValue)(source, id, |
1803 | 0 | ptemplate, known_attributes_size); |
1804 | |
|
1805 | 0 | if ((crv != CKR_OK) && (crv != CKR_ATTRIBUTE_TYPE_INVALID)) { |
1806 | 0 | return crv; |
1807 | 0 | } |
1808 | | |
1809 | 0 | for (i = 0, j = 0; i < known_attributes_size; i++, j++) { |
1810 | 0 | while (i < known_attributes_size && (ptemplate[i].ulValueLen == -1)) { |
1811 | 0 | i++; |
1812 | 0 | } |
1813 | 0 | if (i >= known_attributes_size) { |
1814 | 0 | break; |
1815 | 0 | } |
1816 | | /* cheap optimization */ |
1817 | 0 | if (i == j) { |
1818 | 0 | continue; |
1819 | 0 | } |
1820 | 0 | ptemplate[j] = ptemplate[i]; |
1821 | 0 | } |
1822 | 0 | *max = j; |
1823 | 0 | return CKR_OK; |
1824 | 0 | } |
1825 | | |
1826 | | static const char SFTKDB_META_UPDATE_TEMPLATE[] = "upd_%s_%s"; |
1827 | | |
1828 | | /* |
1829 | | * check to see if we have already updated this database. |
1830 | | * a NULL updateID means we are trying to do an in place |
1831 | | * single database update. In that case we have already |
1832 | | * determined that an update was necessary. |
1833 | | */ |
1834 | | static PRBool |
1835 | | sftkdb_hasUpdate(const char *typeString, SDB *db, const char *updateID) |
1836 | 0 | { |
1837 | 0 | char *id; |
1838 | 0 | CK_RV crv; |
1839 | 0 | SECItem dummy = { 0, NULL, 0 }; |
1840 | 0 | unsigned char dummyData[SDB_MAX_META_DATA_LEN]; |
1841 | |
|
1842 | 0 | if (!updateID) { |
1843 | 0 | return PR_FALSE; |
1844 | 0 | } |
1845 | 0 | id = PR_smprintf(SFTKDB_META_UPDATE_TEMPLATE, typeString, updateID); |
1846 | 0 | if (id == NULL) { |
1847 | 0 | return PR_FALSE; |
1848 | 0 | } |
1849 | 0 | dummy.data = dummyData; |
1850 | 0 | dummy.len = sizeof(dummyData); |
1851 | |
|
1852 | 0 | crv = (*db->sdb_GetMetaData)(db, id, &dummy, NULL); |
1853 | 0 | PR_smprintf_free(id); |
1854 | 0 | return crv == CKR_OK ? PR_TRUE : PR_FALSE; |
1855 | 0 | } |
1856 | | |
1857 | | /* |
1858 | | * we just completed an update, store the update id |
1859 | | * so we don't need to do it again. If non was given, |
1860 | | * there is nothing to do. |
1861 | | */ |
1862 | | static CK_RV |
1863 | | sftkdb_putUpdate(const char *typeString, SDB *db, const char *updateID) |
1864 | 0 | { |
1865 | 0 | char *id; |
1866 | 0 | CK_RV crv; |
1867 | 0 | SECItem dummy = { 0, NULL, 0 }; |
1868 | | |
1869 | | /* if no id was given, nothing to do */ |
1870 | 0 | if (updateID == NULL) { |
1871 | 0 | return CKR_OK; |
1872 | 0 | } |
1873 | | |
1874 | 0 | dummy.data = (unsigned char *)updateID; |
1875 | 0 | dummy.len = PORT_Strlen(updateID); |
1876 | |
|
1877 | 0 | id = PR_smprintf(SFTKDB_META_UPDATE_TEMPLATE, typeString, updateID); |
1878 | 0 | if (id == NULL) { |
1879 | 0 | return PR_FALSE; |
1880 | 0 | } |
1881 | | |
1882 | 0 | crv = (*db->sdb_PutMetaData)(db, id, &dummy, NULL); |
1883 | 0 | PR_smprintf_free(id); |
1884 | 0 | return crv; |
1885 | 0 | } |
1886 | | |
1887 | | /* |
1888 | | * get a ULong attribute from a template: |
1889 | | * NOTE: this is a raw templated stored in database order! |
1890 | | */ |
1891 | | static CK_ULONG |
1892 | | sftkdb_getULongFromTemplate(CK_ATTRIBUTE_TYPE type, |
1893 | | CK_ATTRIBUTE *ptemplate, CK_ULONG len) |
1894 | 0 | { |
1895 | 0 | CK_ATTRIBUTE *attr = sftkdb_getAttributeFromTemplate(type, |
1896 | 0 | ptemplate, len); |
1897 | |
|
1898 | 0 | if (attr && attr->pValue && attr->ulValueLen == SDB_ULONG_SIZE) { |
1899 | 0 | return sftk_SDBULong2ULong(attr->pValue); |
1900 | 0 | } |
1901 | 0 | return (CK_ULONG)-1; |
1902 | 0 | } |
1903 | | |
1904 | | /* |
1905 | | * we need to find a unique CKA_ID. |
1906 | | * The basic idea is to just increment the lowest byte. |
1907 | | * This code also handles the following corner cases: |
1908 | | * 1) the single byte overflows. On overflow we increment the next byte up |
1909 | | * and so forth until we have overflowed the entire CKA_ID. |
1910 | | * 2) If we overflow the entire CKA_ID we expand it by one byte. |
1911 | | * 3) the CKA_ID is non-existant, we create a new one with one byte. |
1912 | | * This means no matter what CKA_ID is passed, the result of this function |
1913 | | * is always a new CKA_ID, and this function will never return the same |
1914 | | * CKA_ID the it has returned in the passed. |
1915 | | */ |
1916 | | static CK_RV |
1917 | | sftkdb_incrementCKAID(PLArenaPool *arena, CK_ATTRIBUTE *ptemplate) |
1918 | 0 | { |
1919 | 0 | unsigned char *buf = ptemplate->pValue; |
1920 | 0 | CK_ULONG len = ptemplate->ulValueLen; |
1921 | |
|
1922 | 0 | if (buf == NULL || len == (CK_ULONG)-1) { |
1923 | | /* we have no valid CKAID, we'll create a basic one byte CKA_ID below */ |
1924 | 0 | len = 0; |
1925 | 0 | } else { |
1926 | 0 | CK_ULONG i; |
1927 | | |
1928 | | /* walk from the back to front, incrementing |
1929 | | * the CKA_ID until we no longer have a carry, |
1930 | | * or have hit the front of the id. */ |
1931 | 0 | for (i = len; i != 0; i--) { |
1932 | 0 | buf[i - 1]++; |
1933 | 0 | if (buf[i - 1] != 0) { |
1934 | | /* no more carries, the increment is complete */ |
1935 | 0 | return CKR_OK; |
1936 | 0 | } |
1937 | 0 | } |
1938 | | /* we've now overflowed, fall through and expand the CKA_ID by |
1939 | | * one byte */ |
1940 | 0 | } |
1941 | 0 | buf = PORT_ArenaAlloc(arena, len + 1); |
1942 | 0 | if (!buf) { |
1943 | 0 | return CKR_HOST_MEMORY; |
1944 | 0 | } |
1945 | 0 | if (len > 0) { |
1946 | 0 | PORT_Memcpy(buf, ptemplate->pValue, len); |
1947 | 0 | } |
1948 | 0 | buf[len] = 0; |
1949 | 0 | ptemplate->pValue = buf; |
1950 | 0 | ptemplate->ulValueLen = len + 1; |
1951 | 0 | return CKR_OK; |
1952 | 0 | } |
1953 | | |
1954 | | /* |
1955 | | * drop an attribute from a template. |
1956 | | */ |
1957 | | void |
1958 | | sftkdb_dropAttribute(CK_ATTRIBUTE *attr, CK_ATTRIBUTE *ptemplate, |
1959 | | CK_ULONG *plen) |
1960 | 0 | { |
1961 | 0 | CK_ULONG count = *plen; |
1962 | 0 | CK_ULONG i; |
1963 | |
|
1964 | 0 | for (i = 0; i < count; i++) { |
1965 | 0 | if (attr->type == ptemplate[i].type) { |
1966 | 0 | break; |
1967 | 0 | } |
1968 | 0 | } |
1969 | |
|
1970 | 0 | if (i == count) { |
1971 | | /* attribute not found */ |
1972 | 0 | return; |
1973 | 0 | } |
1974 | | |
1975 | | /* copy the remaining attributes up */ |
1976 | 0 | for (i++; i < count; i++) { |
1977 | 0 | ptemplate[i - 1] = ptemplate[i]; |
1978 | 0 | } |
1979 | | |
1980 | | /* decrement the template size */ |
1981 | 0 | *plen = count - 1; |
1982 | 0 | } |
1983 | | |
1984 | | /* |
1985 | | * create some defines for the following functions to document the meaning |
1986 | | * of true/false. (make's it easier to remember what means what. |
1987 | | */ |
1988 | | typedef enum { |
1989 | | SFTKDB_DO_NOTHING = 0, |
1990 | | SFTKDB_ADD_OBJECT, |
1991 | | SFTKDB_MODIFY_OBJECT, |
1992 | | SFTKDB_DROP_ATTRIBUTE |
1993 | | } sftkdbUpdateStatus; |
1994 | | |
1995 | | /* |
1996 | | * helper function to reconcile a single trust entry. |
1997 | | * Identify which trust entry we want to keep. |
1998 | | * If we don't need to do anything (the records are already equal). |
1999 | | * return SFTKDB_DO_NOTHING. |
2000 | | * If we want to use the source version, |
2001 | | * return SFTKDB_MODIFY_OBJECT |
2002 | | * If we want to use the target version, |
2003 | | * return SFTKDB_DROP_ATTRIBUTE |
2004 | | * |
2005 | | * In the end the caller will remove any attributes in the source |
2006 | | * template when SFTKDB_DROP_ATTRIBUTE is specified, then use do a |
2007 | | * set attributes with that template on the target if we received |
2008 | | * any SFTKDB_MODIFY_OBJECT returns. |
2009 | | */ |
2010 | | sftkdbUpdateStatus |
2011 | | sftkdb_reconcileTrustEntry(PLArenaPool *arena, CK_ATTRIBUTE *target, |
2012 | | CK_ATTRIBUTE *source) |
2013 | 0 | { |
2014 | 0 | CK_ULONG targetTrust = sftkdb_getULongFromTemplate(target->type, |
2015 | 0 | target, 1); |
2016 | 0 | CK_ULONG sourceTrust = sftkdb_getULongFromTemplate(target->type, |
2017 | 0 | source, 1); |
2018 | | |
2019 | | /* |
2020 | | * try to pick the best solution between the source and the |
2021 | | * target. Update the source template if we want the target value |
2022 | | * to win out. Prefer cases where we don't actually update the |
2023 | | * trust entry. |
2024 | | */ |
2025 | | |
2026 | | /* they are the same, everything is already kosher */ |
2027 | 0 | if (targetTrust == sourceTrust) { |
2028 | 0 | return SFTKDB_DO_NOTHING; |
2029 | 0 | } |
2030 | | |
2031 | | /* handle the case where the source Trust attribute may be a bit |
2032 | | * flakey */ |
2033 | 0 | if (sourceTrust == (CK_ULONG)-1) { |
2034 | | /* |
2035 | | * The source Trust is invalid. We know that the target Trust |
2036 | | * must be valid here, otherwise the above |
2037 | | * targetTrust == sourceTrust check would have succeeded. |
2038 | | */ |
2039 | 0 | return SFTKDB_DROP_ATTRIBUTE; |
2040 | 0 | } |
2041 | | |
2042 | | /* target is invalid, use the source's idea of the trust value */ |
2043 | 0 | if (targetTrust == (CK_ULONG)-1) { |
2044 | | /* overwriting the target in this case is OK */ |
2045 | 0 | return SFTKDB_MODIFY_OBJECT; |
2046 | 0 | } |
2047 | | |
2048 | | /* at this point we know that both attributes exist and have the |
2049 | | * appropriate length (SDB_ULONG_SIZE). We no longer need to check |
2050 | | * ulValueLen for either attribute. |
2051 | | */ |
2052 | 0 | if (sourceTrust == CKT_NSS_TRUST_UNKNOWN) { |
2053 | 0 | return SFTKDB_DROP_ATTRIBUTE; |
2054 | 0 | } |
2055 | | |
2056 | | /* target has no idea, use the source's idea of the trust value */ |
2057 | 0 | if (targetTrust == CKT_NSS_TRUST_UNKNOWN) { |
2058 | | /* overwriting the target in this case is OK */ |
2059 | 0 | return SFTKDB_MODIFY_OBJECT; |
2060 | 0 | } |
2061 | | |
2062 | | /* so both the target and the source have some idea of what this |
2063 | | * trust attribute should be, and neither agree exactly. |
2064 | | * At this point, we prefer 'hard' attributes over 'soft' ones. |
2065 | | * 'hard' ones are CKT_NSS_TRUSTED, CKT_NSS_TRUSTED_DELEGATOR, and |
2066 | | * CKT_NSS_NOT_TRUTED. Soft ones are ones which don't change the |
2067 | | * actual trust of the cert (CKT_MUST_VERIFY_TRUST, |
2068 | | * CKT_NSS_VALID_DELEGATOR). |
2069 | | */ |
2070 | 0 | if ((sourceTrust == CKT_NSS_MUST_VERIFY_TRUST) || (sourceTrust == CKT_NSS_VALID_DELEGATOR)) { |
2071 | 0 | return SFTKDB_DROP_ATTRIBUTE; |
2072 | 0 | } |
2073 | 0 | if ((targetTrust == CKT_NSS_MUST_VERIFY_TRUST) || (targetTrust == CKT_NSS_VALID_DELEGATOR)) { |
2074 | | /* again, overwriting the target in this case is OK */ |
2075 | 0 | return SFTKDB_MODIFY_OBJECT; |
2076 | 0 | } |
2077 | | |
2078 | | /* both have hard attributes, we have a conflict, let the target win. */ |
2079 | 0 | return SFTKDB_DROP_ATTRIBUTE; |
2080 | 0 | } |
2081 | | |
2082 | | const CK_ATTRIBUTE_TYPE sftkdb_trustList[] = { CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, |
2083 | | CKA_TRUST_CODE_SIGNING, CKA_TRUST_EMAIL_PROTECTION, |
2084 | | CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, |
2085 | | CKA_TRUST_TIME_STAMPING }; |
2086 | | |
2087 | | #define SFTK_TRUST_TEMPLATE_COUNT \ |
2088 | 0 | (sizeof(sftkdb_trustList) / sizeof(sftkdb_trustList[0])) |
2089 | | /* |
2090 | | * Run through the list of known trust types, and reconcile each trust |
2091 | | * entry one by one. Keep track of we really need to write out the source |
2092 | | * trust object (overwriting the existing one). |
2093 | | */ |
2094 | | static sftkdbUpdateStatus |
2095 | | sftkdb_reconcileTrust(PLArenaPool *arena, SDB *db, CK_OBJECT_HANDLE id, |
2096 | | CK_ATTRIBUTE *ptemplate, CK_ULONG *plen) |
2097 | 0 | { |
2098 | 0 | CK_ATTRIBUTE trustTemplate[SFTK_TRUST_TEMPLATE_COUNT]; |
2099 | 0 | unsigned char trustData[SFTK_TRUST_TEMPLATE_COUNT * SDB_ULONG_SIZE]; |
2100 | 0 | sftkdbUpdateStatus update = SFTKDB_DO_NOTHING; |
2101 | 0 | CK_ULONG i; |
2102 | 0 | CK_RV crv; |
2103 | |
|
2104 | 0 | for (i = 0; i < SFTK_TRUST_TEMPLATE_COUNT; i++) { |
2105 | 0 | trustTemplate[i].type = sftkdb_trustList[i]; |
2106 | 0 | trustTemplate[i].pValue = &trustData[i * SDB_ULONG_SIZE]; |
2107 | 0 | trustTemplate[i].ulValueLen = SDB_ULONG_SIZE; |
2108 | 0 | } |
2109 | 0 | crv = (*db->sdb_GetAttributeValue)(db, id, |
2110 | 0 | trustTemplate, SFTK_TRUST_TEMPLATE_COUNT); |
2111 | 0 | if ((crv != CKR_OK) && (crv != CKR_ATTRIBUTE_TYPE_INVALID)) { |
2112 | | /* target trust has some problems, update it */ |
2113 | 0 | update = SFTKDB_MODIFY_OBJECT; |
2114 | 0 | goto done; |
2115 | 0 | } |
2116 | | |
2117 | 0 | for (i = 0; i < SFTK_TRUST_TEMPLATE_COUNT; i++) { |
2118 | 0 | CK_ATTRIBUTE *attr = sftkdb_getAttributeFromTemplate( |
2119 | 0 | trustTemplate[i].type, ptemplate, *plen); |
2120 | 0 | sftkdbUpdateStatus status; |
2121 | | |
2122 | | /* if target trust value doesn't exist, nothing to merge */ |
2123 | 0 | if (trustTemplate[i].ulValueLen == (CK_ULONG)-1) { |
2124 | | /* if the source exists, then we want the source entry, |
2125 | | * go ahead and update */ |
2126 | 0 | if (attr && attr->ulValueLen != (CK_ULONG)-1) { |
2127 | 0 | update = SFTKDB_MODIFY_OBJECT; |
2128 | 0 | } |
2129 | 0 | continue; |
2130 | 0 | } |
2131 | | |
2132 | | /* |
2133 | | * the source doesn't have the attribute, go to the next attribute |
2134 | | */ |
2135 | 0 | if (attr == NULL) { |
2136 | 0 | continue; |
2137 | 0 | } |
2138 | 0 | status = sftkdb_reconcileTrustEntry(arena, &trustTemplate[i], attr); |
2139 | 0 | if (status == SFTKDB_MODIFY_OBJECT) { |
2140 | 0 | update = SFTKDB_MODIFY_OBJECT; |
2141 | 0 | } else if (status == SFTKDB_DROP_ATTRIBUTE) { |
2142 | | /* drop the source copy of the attribute, we are going with |
2143 | | * the target's version */ |
2144 | 0 | sftkdb_dropAttribute(attr, ptemplate, plen); |
2145 | 0 | } |
2146 | 0 | } |
2147 | | |
2148 | | /* finally manage stepup */ |
2149 | 0 | if (update == SFTKDB_MODIFY_OBJECT) { |
2150 | 0 | CK_BBOOL stepUpBool = CK_FALSE; |
2151 | | /* if we are going to write from the source, make sure we don't |
2152 | | * overwrite the stepup bit if it's on*/ |
2153 | 0 | trustTemplate[0].type = CKA_TRUST_STEP_UP_APPROVED; |
2154 | 0 | trustTemplate[0].pValue = &stepUpBool; |
2155 | 0 | trustTemplate[0].ulValueLen = sizeof(stepUpBool); |
2156 | 0 | crv = (*db->sdb_GetAttributeValue)(db, id, trustTemplate, 1); |
2157 | 0 | if ((crv == CKR_OK) && (stepUpBool == CK_TRUE)) { |
2158 | 0 | sftkdb_dropAttribute(trustTemplate, ptemplate, plen); |
2159 | 0 | } |
2160 | 0 | } else { |
2161 | | /* we currently aren't going to update. If the source stepup bit is |
2162 | | * on however, do an update so the target gets it as well */ |
2163 | 0 | CK_ATTRIBUTE *attr; |
2164 | |
|
2165 | 0 | attr = sftkdb_getAttributeFromTemplate(CKA_TRUST_STEP_UP_APPROVED, |
2166 | 0 | ptemplate, *plen); |
2167 | 0 | if (attr && (attr->ulValueLen == sizeof(CK_BBOOL)) && |
2168 | 0 | (*(CK_BBOOL *)(attr->pValue) == CK_TRUE)) { |
2169 | 0 | update = SFTKDB_MODIFY_OBJECT; |
2170 | 0 | } |
2171 | 0 | } |
2172 | |
|
2173 | 0 | done: |
2174 | 0 | return update; |
2175 | 0 | } |
2176 | | |
2177 | | static sftkdbUpdateStatus |
2178 | | sftkdb_handleIDAndName(PLArenaPool *arena, SDB *db, CK_OBJECT_HANDLE id, |
2179 | | CK_ATTRIBUTE *ptemplate, CK_ULONG *plen) |
2180 | 0 | { |
2181 | 0 | sftkdbUpdateStatus update = SFTKDB_DO_NOTHING; |
2182 | 0 | CK_ATTRIBUTE *attr1, *attr2; |
2183 | 0 | CK_ATTRIBUTE ttemplate[2] = { |
2184 | 0 | { CKA_ID, NULL, 0 }, |
2185 | 0 | { CKA_LABEL, NULL, 0 } |
2186 | 0 | }; |
2187 | |
|
2188 | 0 | attr1 = sftkdb_getAttributeFromTemplate(CKA_LABEL, ptemplate, *plen); |
2189 | 0 | attr2 = sftkdb_getAttributeFromTemplate(CKA_ID, ptemplate, *plen); |
2190 | | |
2191 | | /* if the source has neither an id nor label, don't bother updating */ |
2192 | 0 | if ((!attr1 || attr1->ulValueLen == 0) && |
2193 | 0 | (!attr2 || attr2->ulValueLen == 0)) { |
2194 | 0 | return SFTKDB_DO_NOTHING; |
2195 | 0 | } |
2196 | | |
2197 | | /* the source has either an id or a label, see what the target has */ |
2198 | 0 | (void)(*db->sdb_GetAttributeValue)(db, id, ttemplate, 2); |
2199 | | |
2200 | | /* if the target has neither, update from the source */ |
2201 | 0 | if (((ttemplate[0].ulValueLen == 0) || |
2202 | 0 | (ttemplate[0].ulValueLen == (CK_ULONG)-1)) && |
2203 | 0 | ((ttemplate[1].ulValueLen == 0) || |
2204 | 0 | (ttemplate[1].ulValueLen == (CK_ULONG)-1))) { |
2205 | 0 | return SFTKDB_MODIFY_OBJECT; |
2206 | 0 | } |
2207 | | |
2208 | | /* check the CKA_ID */ |
2209 | 0 | if ((ttemplate[0].ulValueLen != 0) && |
2210 | 0 | (ttemplate[0].ulValueLen != (CK_ULONG)-1)) { |
2211 | | /* we have a CKA_ID in the target, don't overwrite |
2212 | | * the target with an empty CKA_ID from the source*/ |
2213 | 0 | if (attr1 && attr1->ulValueLen == 0) { |
2214 | 0 | sftkdb_dropAttribute(attr1, ptemplate, plen); |
2215 | 0 | } |
2216 | 0 | } else if (attr1 && attr1->ulValueLen != 0) { |
2217 | | /* source has a CKA_ID, but the target doesn't, update the target */ |
2218 | 0 | update = SFTKDB_MODIFY_OBJECT; |
2219 | 0 | } |
2220 | | |
2221 | | /* check the nickname */ |
2222 | 0 | if ((ttemplate[1].ulValueLen != 0) && |
2223 | 0 | (ttemplate[1].ulValueLen != (CK_ULONG)-1)) { |
2224 | | |
2225 | | /* we have a nickname in the target, and we don't have to update |
2226 | | * the CKA_ID. We are done. NOTE: if we add addition attributes |
2227 | | * in this check, this shortcut can only go on the last of them. */ |
2228 | 0 | if (update == SFTKDB_DO_NOTHING) { |
2229 | 0 | return update; |
2230 | 0 | } |
2231 | | /* we have a nickname in the target, don't overwrite |
2232 | | * the target with an empty nickname from the source */ |
2233 | 0 | if (attr2 && attr2->ulValueLen == 0) { |
2234 | 0 | sftkdb_dropAttribute(attr2, ptemplate, plen); |
2235 | 0 | } |
2236 | 0 | } else if (attr2 && attr2->ulValueLen != 0) { |
2237 | | /* source has a nickname, but the target doesn't, update the target */ |
2238 | 0 | update = SFTKDB_MODIFY_OBJECT; |
2239 | 0 | } |
2240 | | |
2241 | 0 | return update; |
2242 | 0 | } |
2243 | | |
2244 | | /* |
2245 | | * This function updates the template before we write the object out. |
2246 | | * |
2247 | | * If we are going to skip updating this object, return PR_FALSE. |
2248 | | * If it should be updated we return PR_TRUE. |
2249 | | * To help readability, these have been defined |
2250 | | * as SFTK_DONT_UPDATE and SFTK_UPDATE respectively. |
2251 | | */ |
2252 | | static PRBool |
2253 | | sftkdb_updateObjectTemplate(PLArenaPool *arena, SDB *db, |
2254 | | CK_OBJECT_CLASS objectType, |
2255 | | CK_ATTRIBUTE *ptemplate, CK_ULONG *plen, |
2256 | | CK_OBJECT_HANDLE *targetID) |
2257 | 0 | { |
2258 | 0 | PRBool done; /* should we repeat the loop? */ |
2259 | 0 | CK_OBJECT_HANDLE id; |
2260 | 0 | CK_RV crv = CKR_OK; |
2261 | |
|
2262 | 0 | do { |
2263 | 0 | crv = sftkdb_checkConflicts(db, objectType, ptemplate, |
2264 | 0 | *plen, CK_INVALID_HANDLE); |
2265 | 0 | if (crv != CKR_ATTRIBUTE_VALUE_INVALID) { |
2266 | 0 | break; |
2267 | 0 | } |
2268 | 0 | crv = sftkdb_resolveConflicts(arena, objectType, ptemplate, plen); |
2269 | 0 | } while (crv == CKR_OK); |
2270 | | |
2271 | 0 | if (crv != CKR_OK) { |
2272 | 0 | return SFTKDB_DO_NOTHING; |
2273 | 0 | } |
2274 | | |
2275 | 0 | do { |
2276 | 0 | done = PR_TRUE; |
2277 | 0 | crv = sftkdb_lookupObject(db, objectType, &id, ptemplate, *plen); |
2278 | 0 | if (crv != CKR_OK) { |
2279 | 0 | return SFTKDB_DO_NOTHING; |
2280 | 0 | } |
2281 | | |
2282 | | /* This object already exists, merge it, don't update */ |
2283 | 0 | if (id != CK_INVALID_HANDLE) { |
2284 | 0 | CK_ATTRIBUTE *attr = NULL; |
2285 | | /* special post processing for attributes */ |
2286 | 0 | switch (objectType) { |
2287 | 0 | case CKO_CERTIFICATE: |
2288 | 0 | case CKO_PUBLIC_KEY: |
2289 | 0 | case CKO_PRIVATE_KEY: |
2290 | | /* update target's CKA_ID and labels if they don't already |
2291 | | * exist */ |
2292 | 0 | *targetID = id; |
2293 | 0 | return sftkdb_handleIDAndName(arena, db, id, ptemplate, plen); |
2294 | 0 | case CKO_NSS_TRUST: |
2295 | | /* if we have conflicting trust object types, |
2296 | | * we need to reconcile them */ |
2297 | 0 | *targetID = id; |
2298 | 0 | return sftkdb_reconcileTrust(arena, db, id, ptemplate, plen); |
2299 | 0 | case CKO_SECRET_KEY: |
2300 | | /* secret keys in the old database are all sdr keys, |
2301 | | * unfortunately they all appear to have the same CKA_ID, |
2302 | | * even though they are truly different keys, so we always |
2303 | | * want to update these keys, but we need to |
2304 | | * give them a new CKA_ID */ |
2305 | | /* NOTE: this changes ptemplate */ |
2306 | 0 | attr = sftkdb_getAttributeFromTemplate(CKA_ID, ptemplate, *plen); |
2307 | 0 | crv = attr ? sftkdb_incrementCKAID(arena, attr) |
2308 | 0 | : CKR_HOST_MEMORY; |
2309 | | /* in the extremely rare event that we needed memory and |
2310 | | * couldn't get it, just drop the key */ |
2311 | 0 | if (crv != CKR_OK) { |
2312 | 0 | return SFTKDB_DO_NOTHING; |
2313 | 0 | } |
2314 | 0 | done = PR_FALSE; /* repeat this find loop */ |
2315 | 0 | break; |
2316 | 0 | default: |
2317 | | /* for all other objects, if we found the equivalent object, |
2318 | | * don't update it */ |
2319 | 0 | return SFTKDB_DO_NOTHING; |
2320 | 0 | } |
2321 | 0 | } |
2322 | 0 | } while (!done); |
2323 | | |
2324 | | /* this object doesn't exist, update it */ |
2325 | 0 | return SFTKDB_ADD_OBJECT; |
2326 | 0 | } |
2327 | | |
2328 | | static CK_RV |
2329 | | sftkdb_updateIntegrity(PLArenaPool *arena, SFTKDBHandle *handle, |
2330 | | SDB *source, CK_OBJECT_HANDLE sourceID, |
2331 | | SDB *target, CK_OBJECT_HANDLE targetID, |
2332 | | CK_ATTRIBUTE *ptemplate, CK_ULONG max_attributes) |
2333 | 0 | { |
2334 | 0 | unsigned int i; |
2335 | 0 | CK_RV global_crv = CKR_OK; |
2336 | | |
2337 | | /* if the target doesn't have META data, don't need to do anything */ |
2338 | 0 | if ((target->sdb_flags & SDB_HAS_META) == 0) { |
2339 | 0 | return CKR_OK; |
2340 | 0 | } |
2341 | | /* if the source doesn't have meta data, then the record won't require |
2342 | | * integrity */ |
2343 | 0 | if ((source->sdb_flags & SDB_HAS_META) == 0) { |
2344 | 0 | return CKR_OK; |
2345 | 0 | } |
2346 | 0 | for (i = 0; i < max_attributes; i++) { |
2347 | 0 | CK_ATTRIBUTE *att = &ptemplate[i]; |
2348 | 0 | CK_ATTRIBUTE_TYPE type = att->type; |
2349 | 0 | if (sftkdb_isPrivateAttribute(type)) { |
2350 | | /* copy integrity signatures associated with this record (if any) */ |
2351 | 0 | SECItem signature; |
2352 | 0 | unsigned char signData[SDB_MAX_META_DATA_LEN]; |
2353 | 0 | CK_RV crv; |
2354 | |
|
2355 | 0 | signature.data = signData; |
2356 | 0 | signature.len = sizeof(signData); |
2357 | 0 | crv = sftkdb_getRawAttributeSignature(handle, source, sourceID, type, |
2358 | 0 | &signature); |
2359 | 0 | if (crv != CKR_OK) { |
2360 | | /* old databases don't have signature IDs because they are |
2361 | | * 3DES encrypted. Since we know not to look for integrity |
2362 | | * for 3DES records it's OK not to find one here. A new record |
2363 | | * will be created when we reencrypt using AES CBC */ |
2364 | 0 | continue; |
2365 | 0 | } |
2366 | 0 | crv = sftkdb_PutAttributeSignature(handle, target, targetID, type, |
2367 | 0 | &signature); |
2368 | 0 | if (crv != CKR_OK) { |
2369 | | /* we had a signature in the source db, but we couldn't store |
2370 | | * it in the target, remember the error so we can report it. */ |
2371 | 0 | global_crv = crv; |
2372 | 0 | } |
2373 | 0 | } |
2374 | 0 | } |
2375 | 0 | return global_crv; |
2376 | 0 | } |
2377 | | |
2378 | 0 | #define MAX_ATTRIBUTES 500 |
2379 | | static CK_RV |
2380 | | sftkdb_mergeObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE id, |
2381 | | SECItem *key) |
2382 | 0 | { |
2383 | 0 | CK_ATTRIBUTE template[MAX_ATTRIBUTES]; |
2384 | 0 | CK_ATTRIBUTE *ptemplate; |
2385 | 0 | CK_ULONG max_attributes = MAX_ATTRIBUTES; |
2386 | 0 | CK_OBJECT_CLASS objectType; |
2387 | 0 | SDB *source = handle->update; |
2388 | 0 | SDB *target = handle->db; |
2389 | 0 | unsigned int i; |
2390 | 0 | CK_OBJECT_HANDLE newID = CK_INVALID_HANDLE; |
2391 | 0 | CK_RV crv; |
2392 | 0 | PLArenaPool *arena = NULL; |
2393 | |
|
2394 | 0 | arena = PORT_NewArena(256); |
2395 | 0 | if (arena == NULL) { |
2396 | 0 | return CKR_HOST_MEMORY; |
2397 | 0 | } |
2398 | | |
2399 | 0 | ptemplate = &template[0]; |
2400 | 0 | id &= SFTK_OBJ_ID_MASK; |
2401 | 0 | crv = sftkdb_GetObjectTemplate(source, id, ptemplate, &max_attributes); |
2402 | 0 | if (crv == CKR_BUFFER_TOO_SMALL) { |
2403 | 0 | ptemplate = PORT_ArenaNewArray(arena, CK_ATTRIBUTE, max_attributes); |
2404 | 0 | if (ptemplate == NULL) { |
2405 | 0 | crv = CKR_HOST_MEMORY; |
2406 | 0 | } else { |
2407 | 0 | crv = sftkdb_GetObjectTemplate(source, id, |
2408 | 0 | ptemplate, &max_attributes); |
2409 | 0 | } |
2410 | 0 | } |
2411 | 0 | if (crv != CKR_OK) { |
2412 | 0 | goto loser; |
2413 | 0 | } |
2414 | | |
2415 | 0 | for (i = 0; i < max_attributes; i++) { |
2416 | 0 | ptemplate[i].pValue = PORT_ArenaAlloc(arena, ptemplate[i].ulValueLen); |
2417 | 0 | if (ptemplate[i].pValue == NULL) { |
2418 | 0 | crv = CKR_HOST_MEMORY; |
2419 | 0 | goto loser; |
2420 | 0 | } |
2421 | 0 | } |
2422 | 0 | crv = (*source->sdb_GetAttributeValue)(source, id, |
2423 | 0 | ptemplate, max_attributes); |
2424 | 0 | if (crv != CKR_OK) { |
2425 | 0 | goto loser; |
2426 | 0 | } |
2427 | | |
2428 | 0 | objectType = sftkdb_getULongFromTemplate(CKA_CLASS, ptemplate, |
2429 | 0 | max_attributes); |
2430 | | /* |
2431 | | * Update Object updates the object template if necessary then returns |
2432 | | * whether or not we need to actually write the object out to our target |
2433 | | * database. |
2434 | | */ |
2435 | 0 | if (!handle->updateID) { |
2436 | 0 | crv = sftkdb_CreateObject(arena, handle, target, &newID, |
2437 | 0 | ptemplate, max_attributes); |
2438 | 0 | } else { |
2439 | 0 | sftkdbUpdateStatus update_status; |
2440 | 0 | update_status = sftkdb_updateObjectTemplate(arena, target, |
2441 | 0 | objectType, ptemplate, &max_attributes, &newID); |
2442 | 0 | switch (update_status) { |
2443 | 0 | case SFTKDB_ADD_OBJECT: |
2444 | 0 | crv = sftkdb_CreateObject(arena, handle, target, &newID, |
2445 | 0 | ptemplate, max_attributes); |
2446 | 0 | break; |
2447 | 0 | case SFTKDB_MODIFY_OBJECT: |
2448 | 0 | crv = sftkdb_setAttributeValue(arena, handle, target, |
2449 | 0 | newID, ptemplate, max_attributes); |
2450 | 0 | break; |
2451 | 0 | case SFTKDB_DO_NOTHING: |
2452 | 0 | case SFTKDB_DROP_ATTRIBUTE: |
2453 | 0 | break; |
2454 | 0 | } |
2455 | 0 | } |
2456 | | |
2457 | | /* if keyDB copy any meta data hashes to target, Update for the new |
2458 | | * object ID */ |
2459 | 0 | if (crv == CKR_OK) { |
2460 | 0 | crv = sftkdb_updateIntegrity(arena, handle, source, id, target, newID, |
2461 | 0 | ptemplate, max_attributes); |
2462 | 0 | } |
2463 | |
|
2464 | 0 | loser: |
2465 | 0 | if (arena) { |
2466 | 0 | PORT_FreeArena(arena, PR_TRUE); |
2467 | 0 | } |
2468 | 0 | return crv; |
2469 | 0 | } |
2470 | | |
2471 | 0 | #define MAX_IDS 10 |
2472 | | /* |
2473 | | * update a new database from an old one, now that we have the key |
2474 | | */ |
2475 | | CK_RV |
2476 | | sftkdb_Update(SFTKDBHandle *handle, SECItem *key) |
2477 | 0 | { |
2478 | 0 | SDBFind *find = NULL; |
2479 | 0 | CK_ULONG idCount = MAX_IDS; |
2480 | 0 | CK_OBJECT_HANDLE ids[MAX_IDS]; |
2481 | 0 | SECItem *updatePasswordKey = NULL; |
2482 | 0 | CK_RV crv, crv2; |
2483 | 0 | PRBool inTransaction = PR_FALSE; |
2484 | 0 | unsigned int i; |
2485 | |
|
2486 | 0 | if (handle == NULL) { |
2487 | 0 | return CKR_OK; |
2488 | 0 | } |
2489 | 0 | if (handle->update == NULL) { |
2490 | 0 | return CKR_OK; |
2491 | 0 | } |
2492 | | /* |
2493 | | * put the whole update under a transaction. This allows us to handle |
2494 | | * any possible race conditions between with the updateID check. |
2495 | | */ |
2496 | 0 | crv = (*handle->db->sdb_Begin)(handle->db); |
2497 | 0 | if (crv != CKR_OK) { |
2498 | 0 | return crv; |
2499 | 0 | } |
2500 | 0 | inTransaction = PR_TRUE; |
2501 | | |
2502 | | /* some one else has already updated this db */ |
2503 | 0 | if (sftkdb_hasUpdate(sftkdb_TypeString(handle), |
2504 | 0 | handle->db, handle->updateID)) { |
2505 | 0 | crv = CKR_OK; |
2506 | 0 | goto done; |
2507 | 0 | } |
2508 | | |
2509 | 0 | updatePasswordKey = sftkdb_GetUpdatePasswordKey(handle); |
2510 | 0 | if (updatePasswordKey) { |
2511 | | /* pass the source DB key to the legacy code, |
2512 | | * so it can decrypt things */ |
2513 | 0 | handle->oldKey = updatePasswordKey; |
2514 | 0 | } |
2515 | | |
2516 | | /* find all the objects */ |
2517 | 0 | crv = sftkdb_FindObjectsInit(handle, NULL, 0, &find); |
2518 | |
|
2519 | 0 | if (crv != CKR_OK) { |
2520 | 0 | goto loser; |
2521 | 0 | } |
2522 | 0 | while ((crv == CKR_OK) && (idCount == MAX_IDS)) { |
2523 | 0 | crv = sftkdb_FindObjects(handle, find, ids, MAX_IDS, &idCount); |
2524 | 0 | for (i = 0; (crv == CKR_OK) && (i < idCount); i++) { |
2525 | 0 | crv = sftkdb_mergeObject(handle, ids[i], key); |
2526 | 0 | } |
2527 | 0 | } |
2528 | 0 | crv2 = sftkdb_FindObjectsFinal(handle, find); |
2529 | 0 | if (crv == CKR_OK) |
2530 | 0 | crv = crv2; |
2531 | |
|
2532 | 0 | loser: |
2533 | | /* no longer need the old key value */ |
2534 | 0 | handle->oldKey = NULL; |
2535 | | |
2536 | | /* update the password - even if we didn't update objects */ |
2537 | 0 | if (handle->type == SFTK_KEYDB_TYPE) { |
2538 | 0 | SECItem item1, item2; |
2539 | 0 | unsigned char data1[SDB_MAX_META_DATA_LEN]; |
2540 | 0 | unsigned char data2[SDB_MAX_META_DATA_LEN]; |
2541 | |
|
2542 | 0 | item1.data = data1; |
2543 | 0 | item1.len = sizeof(data1); |
2544 | 0 | item2.data = data2; |
2545 | 0 | item2.len = sizeof(data2); |
2546 | | |
2547 | | /* if the target db already has a password, skip this. */ |
2548 | 0 | crv = (*handle->db->sdb_GetMetaData)(handle->db, "password", |
2549 | 0 | &item1, &item2); |
2550 | 0 | if (crv == CKR_OK) { |
2551 | 0 | goto done; |
2552 | 0 | } |
2553 | | |
2554 | | /* nope, update it from the source */ |
2555 | 0 | crv = (*handle->update->sdb_GetMetaData)(handle->update, "password", |
2556 | 0 | &item1, &item2); |
2557 | 0 | if (crv != CKR_OK) { |
2558 | | /* if we get here, neither the source, nor the target has been initialized |
2559 | | * with a password entry. Create a metadata table now so that we don't |
2560 | | * mistake this for a partially updated database */ |
2561 | 0 | item1.data[0] = 0; |
2562 | 0 | item2.data[0] = 0; |
2563 | 0 | item1.len = item2.len = 1; |
2564 | 0 | crv = (*handle->db->sdb_PutMetaData)(handle->db, "empty", &item1, &item2); |
2565 | 0 | goto done; |
2566 | 0 | } |
2567 | 0 | crv = (*handle->db->sdb_PutMetaData)(handle->db, "password", &item1, |
2568 | 0 | &item2); |
2569 | 0 | if (crv != CKR_OK) { |
2570 | 0 | goto done; |
2571 | 0 | } |
2572 | 0 | } |
2573 | | |
2574 | 0 | done: |
2575 | | /* finally mark this up to date db up to date */ |
2576 | | /* some one else has already updated this db */ |
2577 | 0 | if (crv == CKR_OK) { |
2578 | 0 | crv = sftkdb_putUpdate(sftkdb_TypeString(handle), |
2579 | 0 | handle->db, handle->updateID); |
2580 | 0 | } |
2581 | |
|
2582 | 0 | if (inTransaction) { |
2583 | 0 | if (crv == CKR_OK) { |
2584 | 0 | crv = (*handle->db->sdb_Commit)(handle->db); |
2585 | 0 | } else { |
2586 | 0 | (*handle->db->sdb_Abort)(handle->db); |
2587 | 0 | } |
2588 | 0 | } |
2589 | 0 | if (handle->update) { |
2590 | 0 | (*handle->update->sdb_Close)(handle->update); |
2591 | 0 | handle->update = NULL; |
2592 | 0 | } |
2593 | 0 | if (handle->updateID) { |
2594 | 0 | PORT_Free(handle->updateID); |
2595 | 0 | handle->updateID = NULL; |
2596 | 0 | } |
2597 | 0 | sftkdb_FreeUpdatePasswordKey(handle); |
2598 | 0 | if (updatePasswordKey) { |
2599 | 0 | SECITEM_ZfreeItem(updatePasswordKey, PR_TRUE); |
2600 | 0 | } |
2601 | 0 | handle->updateDBIsInit = PR_FALSE; |
2602 | 0 | return crv; |
2603 | 0 | } |
2604 | | |
2605 | | /****************************************************************** |
2606 | | * DB handle managing functions. |
2607 | | * |
2608 | | * These functions are called by softoken to initialize, acquire, |
2609 | | * and release database handles. |
2610 | | */ |
2611 | | |
2612 | | const char * |
2613 | | sftkdb_GetUpdateID(SFTKDBHandle *handle) |
2614 | 0 | { |
2615 | 0 | return handle->updateID; |
2616 | 0 | } |
2617 | | |
2618 | | /* release a database handle */ |
2619 | | void |
2620 | | sftk_freeDB(SFTKDBHandle *handle) |
2621 | 8 | { |
2622 | 8 | PRInt32 ref; |
2623 | | |
2624 | 8 | if (!handle) |
2625 | 8 | return; |
2626 | 0 | ref = PR_ATOMIC_DECREMENT(&handle->ref); |
2627 | 0 | if (ref == 0) { |
2628 | 0 | sftkdb_CloseDB(handle); |
2629 | 0 | } |
2630 | 0 | return; |
2631 | 8 | } |
2632 | | |
2633 | | /* |
2634 | | * acquire a database handle for a certificate db |
2635 | | * (database for public objects) |
2636 | | */ |
2637 | | SFTKDBHandle * |
2638 | | sftk_getCertDB(SFTKSlot *slot) |
2639 | 8 | { |
2640 | 8 | SFTKDBHandle *dbHandle; |
2641 | | |
2642 | 8 | PZ_Lock(slot->slotLock); |
2643 | 8 | dbHandle = slot->certDB; |
2644 | 8 | if (dbHandle) { |
2645 | 0 | (void)PR_ATOMIC_INCREMENT(&dbHandle->ref); |
2646 | 0 | } |
2647 | 8 | PZ_Unlock(slot->slotLock); |
2648 | 8 | return dbHandle; |
2649 | 8 | } |
2650 | | |
2651 | | /* |
2652 | | * acquire a database handle for a key database |
2653 | | * (database for private objects) |
2654 | | */ |
2655 | | SFTKDBHandle * |
2656 | | sftk_getKeyDB(SFTKSlot *slot) |
2657 | 232 | { |
2658 | 232 | SFTKDBHandle *dbHandle; |
2659 | | |
2660 | 232 | SKIP_AFTER_FORK(PZ_Lock(slot->slotLock)); |
2661 | 232 | dbHandle = slot->keyDB; |
2662 | 232 | if (dbHandle) { |
2663 | 0 | (void)PR_ATOMIC_INCREMENT(&dbHandle->ref); |
2664 | 0 | } |
2665 | 232 | SKIP_AFTER_FORK(PZ_Unlock(slot->slotLock)); |
2666 | 232 | return dbHandle; |
2667 | 232 | } |
2668 | | |
2669 | | /* |
2670 | | * acquire the database for a specific object. NOTE: objectID must point |
2671 | | * to a Token object! |
2672 | | */ |
2673 | | SFTKDBHandle * |
2674 | | sftk_getDBForTokenObject(SFTKSlot *slot, CK_OBJECT_HANDLE objectID) |
2675 | 0 | { |
2676 | 0 | SFTKDBHandle *dbHandle; |
2677 | |
|
2678 | 0 | PZ_Lock(slot->slotLock); |
2679 | 0 | dbHandle = objectID & SFTK_KEYDB_TYPE ? slot->keyDB : slot->certDB; |
2680 | 0 | if (dbHandle) { |
2681 | 0 | (void)PR_ATOMIC_INCREMENT(&dbHandle->ref); |
2682 | 0 | } |
2683 | 0 | PZ_Unlock(slot->slotLock); |
2684 | 0 | return dbHandle; |
2685 | 0 | } |
2686 | | |
2687 | | /* |
2688 | | * initialize a new database handle |
2689 | | */ |
2690 | | static SFTKDBHandle * |
2691 | | sftk_NewDBHandle(SDB *sdb, int type, PRBool legacy) |
2692 | 0 | { |
2693 | 0 | SFTKDBHandle *handle = PORT_New(SFTKDBHandle); |
2694 | 0 | handle->ref = 1; |
2695 | 0 | handle->db = sdb; |
2696 | 0 | handle->update = NULL; |
2697 | 0 | handle->peerDB = NULL; |
2698 | 0 | handle->newKey = NULL; |
2699 | 0 | handle->oldKey = NULL; |
2700 | 0 | handle->updatePasswordKey = NULL; |
2701 | 0 | handle->updateID = NULL; |
2702 | 0 | handle->type = type; |
2703 | 0 | handle->usesLegacyStorage = legacy; |
2704 | 0 | handle->passwordKey.data = NULL; |
2705 | 0 | handle->passwordKey.len = 0; |
2706 | 0 | handle->passwordLock = NULL; |
2707 | 0 | if (type == SFTK_KEYDB_TYPE) { |
2708 | 0 | handle->passwordLock = PZ_NewLock(nssILockAttribute); |
2709 | 0 | } |
2710 | 0 | sdb->app_private = handle; |
2711 | 0 | return handle; |
2712 | 0 | } |
2713 | | |
2714 | | /* |
2715 | | * reset the key database to it's uninitialized state. This call |
2716 | | * will clear all the key entried. |
2717 | | */ |
2718 | | SECStatus |
2719 | | sftkdb_ResetKeyDB(SFTKDBHandle *handle) |
2720 | 0 | { |
2721 | 0 | CK_RV crv; |
2722 | | |
2723 | | /* only rest the key db */ |
2724 | 0 | if (handle->type != SFTK_KEYDB_TYPE) { |
2725 | 0 | return SECFailure; |
2726 | 0 | } |
2727 | 0 | crv = sftkdb_ResetDB(handle); |
2728 | 0 | if (crv != CKR_OK) { |
2729 | | /* set error */ |
2730 | 0 | return SECFailure; |
2731 | 0 | } |
2732 | 0 | PZ_Lock(handle->passwordLock); |
2733 | 0 | if (handle->passwordKey.data) { |
2734 | 0 | SECITEM_ZfreeItem(&handle->passwordKey, PR_FALSE); |
2735 | 0 | handle->passwordKey.data = NULL; |
2736 | 0 | } |
2737 | 0 | PZ_Unlock(handle->passwordLock); |
2738 | 0 | return SECSuccess; |
2739 | 0 | } |
2740 | | |
2741 | | #ifndef NSS_DISABLE_DBM |
2742 | | static PRBool |
2743 | | sftk_oldVersionExists(const char *dir, int version) |
2744 | | { |
2745 | | int i; |
2746 | | PRStatus exists = PR_FAILURE; |
2747 | | char *file = NULL; |
2748 | | |
2749 | | for (i = version; i > 1; i--) { |
2750 | | file = PR_smprintf("%s%d.db", dir, i); |
2751 | | if (file == NULL) { |
2752 | | continue; |
2753 | | } |
2754 | | exists = PR_Access(file, PR_ACCESS_EXISTS); |
2755 | | PR_smprintf_free(file); |
2756 | | if (exists == PR_SUCCESS) { |
2757 | | return PR_TRUE; |
2758 | | } |
2759 | | } |
2760 | | return PR_FALSE; |
2761 | | } |
2762 | | |
2763 | | #if defined(_WIN32) |
2764 | | /* |
2765 | | * Convert an sdb path (encoded in UTF-8) to a legacy path (encoded in the |
2766 | | * current system codepage). Fails if the path contains a character outside |
2767 | | * the current system codepage. |
2768 | | */ |
2769 | | static char * |
2770 | | sftk_legacyPathFromSDBPath(const char *confdir) |
2771 | | { |
2772 | | wchar_t *confdirWide; |
2773 | | DWORD size; |
2774 | | char *nconfdir; |
2775 | | BOOL unmappable; |
2776 | | |
2777 | | if (!confdir) { |
2778 | | return NULL; |
2779 | | } |
2780 | | confdirWide = _NSSUTIL_UTF8ToWide(confdir); |
2781 | | if (!confdirWide) { |
2782 | | return NULL; |
2783 | | } |
2784 | | |
2785 | | size = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, confdirWide, -1, |
2786 | | NULL, 0, NULL, &unmappable); |
2787 | | if (size == 0 || unmappable) { |
2788 | | PORT_Free(confdirWide); |
2789 | | return NULL; |
2790 | | } |
2791 | | nconfdir = PORT_Alloc(sizeof(char) * size); |
2792 | | if (!nconfdir) { |
2793 | | PORT_Free(confdirWide); |
2794 | | return NULL; |
2795 | | } |
2796 | | size = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, confdirWide, -1, |
2797 | | nconfdir, size, NULL, &unmappable); |
2798 | | PORT_Free(confdirWide); |
2799 | | if (size == 0 || unmappable) { |
2800 | | PORT_Free(nconfdir); |
2801 | | return NULL; |
2802 | | } |
2803 | | |
2804 | | return nconfdir; |
2805 | | } |
2806 | | #else |
2807 | | #define sftk_legacyPathFromSDBPath(confdir) PORT_Strdup((confdir)) |
2808 | | #endif |
2809 | | |
2810 | | static PRBool |
2811 | | sftk_hasLegacyDB(const char *confdir, const char *certPrefix, |
2812 | | const char *keyPrefix, int certVersion, int keyVersion) |
2813 | | { |
2814 | | char *dir; |
2815 | | PRBool exists; |
2816 | | |
2817 | | if (certPrefix == NULL) { |
2818 | | certPrefix = ""; |
2819 | | } |
2820 | | |
2821 | | if (keyPrefix == NULL) { |
2822 | | keyPrefix = ""; |
2823 | | } |
2824 | | |
2825 | | dir = PR_smprintf("%s/%scert", confdir, certPrefix); |
2826 | | if (dir == NULL) { |
2827 | | return PR_FALSE; |
2828 | | } |
2829 | | |
2830 | | exists = sftk_oldVersionExists(dir, certVersion); |
2831 | | PR_smprintf_free(dir); |
2832 | | if (exists) { |
2833 | | return PR_TRUE; |
2834 | | } |
2835 | | |
2836 | | dir = PR_smprintf("%s/%skey", confdir, keyPrefix); |
2837 | | if (dir == NULL) { |
2838 | | return PR_FALSE; |
2839 | | } |
2840 | | |
2841 | | exists = sftk_oldVersionExists(dir, keyVersion); |
2842 | | PR_smprintf_free(dir); |
2843 | | return exists; |
2844 | | } |
2845 | | #endif /* NSS_DISABLE_DBM */ |
2846 | | |
2847 | | /* |
2848 | | * initialize certificate and key database handles as a pair. |
2849 | | * |
2850 | | * This function figures out what type of database we are opening and |
2851 | | * calls the appropriate low level function to open the database. |
2852 | | * It also figures out whether or not to setup up automatic update. |
2853 | | */ |
2854 | | CK_RV |
2855 | | sftk_DBInit(const char *configdir, const char *certPrefix, |
2856 | | const char *keyPrefix, const char *updatedir, |
2857 | | const char *updCertPrefix, const char *updKeyPrefix, |
2858 | | const char *updateID, PRBool readOnly, PRBool noCertDB, |
2859 | | PRBool noKeyDB, PRBool forceOpen, PRBool isFIPS, |
2860 | | SFTKDBHandle **certDB, SFTKDBHandle **keyDB) |
2861 | 0 | { |
2862 | 0 | const char *confdir; |
2863 | 0 | NSSDBType dbType = NSS_DB_TYPE_NONE; |
2864 | 0 | char *appName = NULL; |
2865 | 0 | SDB *keySDB, *certSDB; |
2866 | 0 | CK_RV crv = CKR_OK; |
2867 | 0 | int flags = SDB_RDONLY; |
2868 | 0 | PRBool newInit = PR_FALSE; |
2869 | | #ifndef NSS_DISABLE_DBM |
2870 | | PRBool needUpdate = PR_FALSE; |
2871 | | #endif /* NSS_DISABLE_DBM */ |
2872 | 0 | char *nconfdir = NULL; |
2873 | 0 | PRBool legacy = PR_TRUE; |
2874 | |
|
2875 | 0 | if (!readOnly) { |
2876 | 0 | flags = SDB_CREATE; |
2877 | 0 | } |
2878 | 0 | if (isFIPS) { |
2879 | 0 | flags |= SDB_FIPS; |
2880 | 0 | } |
2881 | |
|
2882 | 0 | *certDB = NULL; |
2883 | 0 | *keyDB = NULL; |
2884 | |
|
2885 | 0 | if (noKeyDB && noCertDB) { |
2886 | 0 | return CKR_OK; |
2887 | 0 | } |
2888 | 0 | confdir = _NSSUTIL_EvaluateConfigDir(configdir, &dbType, &appName); |
2889 | | |
2890 | | /* |
2891 | | * now initialize the appropriate database |
2892 | | */ |
2893 | 0 | switch (dbType) { |
2894 | | #ifndef NSS_DISABLE_DBM |
2895 | | case NSS_DB_TYPE_LEGACY: |
2896 | | crv = sftkdbCall_open(confdir, certPrefix, keyPrefix, 8, 3, flags, |
2897 | | noCertDB ? NULL : &certSDB, noKeyDB ? NULL : &keySDB); |
2898 | | break; |
2899 | | case NSS_DB_TYPE_MULTIACCESS: |
2900 | | crv = sftkdbCall_open(configdir, certPrefix, keyPrefix, 8, 3, flags, |
2901 | | noCertDB ? NULL : &certSDB, noKeyDB ? NULL : &keySDB); |
2902 | | break; |
2903 | | #endif /* NSS_DISABLE_DBM */ |
2904 | 0 | case NSS_DB_TYPE_SQL: |
2905 | 0 | case NSS_DB_TYPE_EXTERN: /* SHOULD open a loadable db */ |
2906 | 0 | crv = s_open(confdir, certPrefix, keyPrefix, 9, 4, flags, |
2907 | 0 | noCertDB ? NULL : &certSDB, noKeyDB ? NULL : &keySDB, &newInit); |
2908 | 0 | legacy = PR_FALSE; |
2909 | |
|
2910 | | #ifndef NSS_DISABLE_DBM |
2911 | | /* |
2912 | | * if we failed to open the DB's read only, use the old ones if |
2913 | | * the exists. |
2914 | | */ |
2915 | | if (crv != CKR_OK) { |
2916 | | legacy = PR_TRUE; |
2917 | | if ((flags & SDB_RDONLY) == SDB_RDONLY) { |
2918 | | nconfdir = sftk_legacyPathFromSDBPath(confdir); |
2919 | | } |
2920 | | if (nconfdir && |
2921 | | sftk_hasLegacyDB(nconfdir, certPrefix, keyPrefix, 8, 3)) { |
2922 | | /* we have legacy databases, if we failed to open the new format |
2923 | | * DB's read only, just use the legacy ones */ |
2924 | | crv = sftkdbCall_open(nconfdir, certPrefix, |
2925 | | keyPrefix, 8, 3, flags, |
2926 | | noCertDB ? NULL : &certSDB, noKeyDB ? NULL : &keySDB); |
2927 | | } |
2928 | | /* Handle the database merge case. |
2929 | | * |
2930 | | * For the merge case, we need help from the application. Only |
2931 | | * the application knows where the old database is, and what unique |
2932 | | * identifier it has associated with it. |
2933 | | * |
2934 | | * If the client supplies these values, we use them to determine |
2935 | | * if we need to update. |
2936 | | */ |
2937 | | } else if ( |
2938 | | /* both update params have been supplied */ |
2939 | | updatedir && *updatedir && updateID && *updateID |
2940 | | /* old dbs exist? */ |
2941 | | && sftk_hasLegacyDB(updatedir, updCertPrefix, updKeyPrefix, 8, 3) |
2942 | | /* and they have not yet been updated? */ |
2943 | | && ((noKeyDB || !sftkdb_hasUpdate("key", keySDB, updateID)) || (noCertDB || !sftkdb_hasUpdate("cert", certSDB, updateID)))) { |
2944 | | /* we need to update */ |
2945 | | confdir = updatedir; |
2946 | | certPrefix = updCertPrefix; |
2947 | | keyPrefix = updKeyPrefix; |
2948 | | needUpdate = PR_TRUE; |
2949 | | } else if (newInit) { |
2950 | | /* if the new format DB was also a newly created DB, and we |
2951 | | * succeeded, then need to update that new database with data |
2952 | | * from the existing legacy DB */ |
2953 | | nconfdir = sftk_legacyPathFromSDBPath(confdir); |
2954 | | if (nconfdir && |
2955 | | sftk_hasLegacyDB(nconfdir, certPrefix, keyPrefix, 8, 3)) { |
2956 | | confdir = nconfdir; |
2957 | | needUpdate = PR_TRUE; |
2958 | | } |
2959 | | } |
2960 | | #endif /* NSS_DISABLE_DBM */ |
2961 | 0 | break; |
2962 | 0 | default: |
2963 | 0 | crv = CKR_GENERAL_ERROR; /* can't happen, EvaluationConfigDir MUST |
2964 | | * return one of the types we already |
2965 | | * specified. */ |
2966 | 0 | } |
2967 | 0 | if (crv != CKR_OK) { |
2968 | 0 | goto done; |
2969 | 0 | } |
2970 | 0 | if (!noCertDB) { |
2971 | 0 | *certDB = sftk_NewDBHandle(certSDB, SFTK_CERTDB_TYPE, legacy); |
2972 | 0 | } else { |
2973 | 0 | *certDB = NULL; |
2974 | 0 | } |
2975 | 0 | if (!noKeyDB) { |
2976 | 0 | *keyDB = sftk_NewDBHandle(keySDB, SFTK_KEYDB_TYPE, legacy); |
2977 | 0 | } else { |
2978 | 0 | *keyDB = NULL; |
2979 | 0 | } |
2980 | | |
2981 | | /* link them together */ |
2982 | 0 | if (*certDB) { |
2983 | 0 | (*certDB)->peerDB = *keyDB; |
2984 | 0 | } |
2985 | 0 | if (*keyDB) { |
2986 | 0 | (*keyDB)->peerDB = *certDB; |
2987 | 0 | } |
2988 | |
|
2989 | | #ifndef NSS_DISABLE_DBM |
2990 | | /* |
2991 | | * if we need to update, open the legacy database and |
2992 | | * mark the handle as needing update. |
2993 | | */ |
2994 | | if (needUpdate) { |
2995 | | SDB *updateCert = NULL; |
2996 | | SDB *updateKey = NULL; |
2997 | | CK_RV crv2; |
2998 | | |
2999 | | crv2 = sftkdbCall_open(confdir, certPrefix, keyPrefix, 8, 3, flags, |
3000 | | noCertDB ? NULL : &updateCert, |
3001 | | noKeyDB ? NULL : &updateKey); |
3002 | | if (crv2 == CKR_OK) { |
3003 | | if (*certDB) { |
3004 | | (*certDB)->update = updateCert; |
3005 | | (*certDB)->updateID = updateID && *updateID |
3006 | | ? PORT_Strdup(updateID) |
3007 | | : NULL; |
3008 | | updateCert->app_private = (*certDB); |
3009 | | } |
3010 | | if (*keyDB) { |
3011 | | PRBool tokenRemoved = PR_FALSE; |
3012 | | (*keyDB)->update = updateKey; |
3013 | | (*keyDB)->updateID = updateID && *updateID ? PORT_Strdup(updateID) : NULL; |
3014 | | updateKey->app_private = (*keyDB); |
3015 | | (*keyDB)->updateDBIsInit = PR_TRUE; |
3016 | | (*keyDB)->updateDBIsInit = |
3017 | | (sftkdb_HasPasswordSet(*keyDB) == SECSuccess) ? PR_TRUE : PR_FALSE; |
3018 | | /* if the password on the key db is NULL, kick off our update |
3019 | | * chain of events */ |
3020 | | sftkdb_CheckPasswordNull((*keyDB), &tokenRemoved); |
3021 | | } else { |
3022 | | /* we don't have a key DB, update the certificate DB now */ |
3023 | | sftkdb_Update(*certDB, NULL); |
3024 | | } |
3025 | | } |
3026 | | } |
3027 | | #endif /* NSS_DISABLE_DBM */ |
3028 | |
|
3029 | 0 | done: |
3030 | 0 | if (appName) { |
3031 | 0 | PORT_Free(appName); |
3032 | 0 | } |
3033 | 0 | if (nconfdir) { |
3034 | 0 | PORT_Free(nconfdir); |
3035 | 0 | } |
3036 | 0 | return forceOpen ? CKR_OK : crv; |
3037 | 0 | } |
3038 | | |
3039 | | CK_RV |
3040 | | sftkdb_Shutdown(void) |
3041 | 0 | { |
3042 | 0 | s_shutdown(); |
3043 | | #ifndef NSS_DISABLE_DBM |
3044 | | sftkdbCall_Shutdown(); |
3045 | | #endif /* NSS_DISABLE_DBM */ |
3046 | 0 | return CKR_OK; |
3047 | 0 | } |