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