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