Mercurial > trustbridge > nss-cmake-static
comparison nss/lib/softoken/legacydb/lgcreate.c @ 3:150b72113545
Add DBM and legacydb support
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Tue, 05 Aug 2014 18:32:02 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
2:a945361df361 | 3:150b72113545 |
---|---|
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 #include "secitem.h" | |
5 #include "pkcs11.h" | |
6 #include "lgdb.h" | |
7 #include "pcert.h" | |
8 #include "lowkeyi.h" | |
9 #include "blapi.h" | |
10 #include "secder.h" | |
11 #include "secasn1.h" | |
12 | |
13 #include "keydbi.h" | |
14 | |
15 /* | |
16 * ******************** Object Creation Utilities *************************** | |
17 */ | |
18 | |
19 /* | |
20 * check the consistancy and initialize a Certificate Object | |
21 */ | |
22 static CK_RV | |
23 lg_createCertObject(SDB *sdb, CK_OBJECT_HANDLE *handle, | |
24 const CK_ATTRIBUTE *templ, CK_ULONG count) | |
25 { | |
26 SECItem derCert; | |
27 NSSLOWCERTCertificate *cert; | |
28 NSSLOWCERTCertTrust *trust = NULL; | |
29 NSSLOWCERTCertTrust userTrust = | |
30 { CERTDB_USER, CERTDB_USER, CERTDB_USER }; | |
31 NSSLOWCERTCertTrust defTrust = | |
32 { CERTDB_TRUSTED_UNKNOWN, | |
33 CERTDB_TRUSTED_UNKNOWN, CERTDB_TRUSTED_UNKNOWN }; | |
34 char *label = NULL; | |
35 char *email = NULL; | |
36 SECStatus rv; | |
37 CK_RV crv; | |
38 PRBool inDB = PR_TRUE; | |
39 NSSLOWCERTCertDBHandle *certHandle = lg_getCertDB(sdb); | |
40 NSSLOWKEYDBHandle *keyHandle = NULL; | |
41 CK_CERTIFICATE_TYPE type; | |
42 const CK_ATTRIBUTE *attribute; | |
43 | |
44 /* we can't store any certs private */ | |
45 if (lg_isTrue(CKA_PRIVATE, templ, count)) { | |
46 return CKR_ATTRIBUTE_VALUE_INVALID; | |
47 } | |
48 | |
49 /* We only support X.509 Certs for now */ | |
50 crv = lg_GetULongAttribute(CKA_CERTIFICATE_TYPE, templ, count, &type); | |
51 if (crv != CKR_OK) { | |
52 return crv; | |
53 } | |
54 | |
55 if (type != CKC_X_509) { | |
56 return CKR_ATTRIBUTE_VALUE_INVALID; | |
57 } | |
58 | |
59 /* X.509 Certificate */ | |
60 | |
61 | |
62 if (certHandle == NULL) { | |
63 return CKR_TOKEN_WRITE_PROTECTED; | |
64 } | |
65 | |
66 /* get the der cert */ | |
67 attribute = lg_FindAttribute(CKA_VALUE, templ, count); | |
68 if (!attribute) { | |
69 return CKR_ATTRIBUTE_VALUE_INVALID; | |
70 } | |
71 | |
72 derCert.type = 0; | |
73 derCert.data = (unsigned char *)attribute->pValue; | |
74 derCert.len = attribute->ulValueLen ; | |
75 | |
76 label = lg_getString(CKA_LABEL, templ, count); | |
77 | |
78 cert = nsslowcert_FindCertByDERCert(certHandle, &derCert); | |
79 if (cert == NULL) { | |
80 cert = nsslowcert_DecodeDERCertificate(&derCert, label); | |
81 inDB = PR_FALSE; | |
82 } | |
83 if (cert == NULL) { | |
84 if (label) PORT_Free(label); | |
85 return CKR_ATTRIBUTE_VALUE_INVALID; | |
86 } | |
87 | |
88 keyHandle = lg_getKeyDB(sdb); | |
89 if (keyHandle) { | |
90 if (nsslowkey_KeyForCertExists(keyHandle,cert)) { | |
91 trust = &userTrust; | |
92 } | |
93 } | |
94 | |
95 if (!inDB) { | |
96 if (!trust) trust = &defTrust; | |
97 rv = nsslowcert_AddPermCert(certHandle, cert, label, trust); | |
98 } else { | |
99 rv = trust ? nsslowcert_ChangeCertTrust(certHandle,cert,trust) : | |
100 SECSuccess; | |
101 } | |
102 | |
103 if (label) PORT_Free(label); | |
104 | |
105 if (rv != SECSuccess) { | |
106 nsslowcert_DestroyCertificate(cert); | |
107 return CKR_DEVICE_ERROR; | |
108 } | |
109 | |
110 /* | |
111 * Add a NULL S/MIME profile if necessary. | |
112 */ | |
113 email = lg_getString(CKA_NSS_EMAIL, templ, count); | |
114 if (email) { | |
115 certDBEntrySMime *entry; | |
116 | |
117 entry = nsslowcert_ReadDBSMimeEntry(certHandle,email); | |
118 if (!entry) { | |
119 nsslowcert_SaveSMimeProfile(certHandle, email, | |
120 &cert->derSubject, NULL, NULL); | |
121 } else { | |
122 nsslowcert_DestroyDBEntry((certDBEntry *)entry); | |
123 } | |
124 PORT_Free(email); | |
125 } | |
126 *handle=lg_mkHandle(sdb,&cert->certKey,LG_TOKEN_TYPE_CERT); | |
127 nsslowcert_DestroyCertificate(cert); | |
128 | |
129 return CKR_OK; | |
130 } | |
131 | |
132 unsigned int | |
133 lg_MapTrust(CK_TRUST trust, PRBool clientAuth) | |
134 { | |
135 unsigned int trustCA = clientAuth ? CERTDB_TRUSTED_CLIENT_CA : | |
136 CERTDB_TRUSTED_CA; | |
137 switch (trust) { | |
138 case CKT_NSS_TRUSTED: | |
139 return CERTDB_TERMINAL_RECORD|CERTDB_TRUSTED; | |
140 case CKT_NSS_TRUSTED_DELEGATOR: | |
141 return CERTDB_VALID_CA|trustCA; | |
142 case CKT_NSS_MUST_VERIFY_TRUST: | |
143 return CERTDB_MUST_VERIFY; | |
144 case CKT_NSS_NOT_TRUSTED: | |
145 return CERTDB_TERMINAL_RECORD; | |
146 case CKT_NSS_VALID_DELEGATOR: /* implies must verify */ | |
147 return CERTDB_VALID_CA; | |
148 default: | |
149 break; | |
150 } | |
151 return CERTDB_TRUSTED_UNKNOWN; | |
152 } | |
153 | |
154 | |
155 /* | |
156 * check the consistancy and initialize a Trust Object | |
157 */ | |
158 static CK_RV | |
159 lg_createTrustObject(SDB *sdb, CK_OBJECT_HANDLE *handle, | |
160 const CK_ATTRIBUTE *templ, CK_ULONG count) | |
161 { | |
162 const CK_ATTRIBUTE *issuer = NULL; | |
163 const CK_ATTRIBUTE *serial = NULL; | |
164 NSSLOWCERTCertificate *cert = NULL; | |
165 const CK_ATTRIBUTE *trust; | |
166 CK_TRUST sslTrust = CKT_NSS_TRUST_UNKNOWN; | |
167 CK_TRUST clientTrust = CKT_NSS_TRUST_UNKNOWN; | |
168 CK_TRUST emailTrust = CKT_NSS_TRUST_UNKNOWN; | |
169 CK_TRUST signTrust = CKT_NSS_TRUST_UNKNOWN; | |
170 CK_BBOOL stepUp; | |
171 NSSLOWCERTCertTrust dbTrust = { 0 }; | |
172 SECStatus rv; | |
173 NSSLOWCERTCertDBHandle *certHandle = lg_getCertDB(sdb); | |
174 NSSLOWCERTIssuerAndSN issuerSN; | |
175 | |
176 /* we can't store any certs private */ | |
177 if (lg_isTrue(CKA_PRIVATE, templ, count)) { | |
178 return CKR_ATTRIBUTE_VALUE_INVALID; | |
179 } | |
180 | |
181 if (certHandle == NULL) { | |
182 return CKR_TOKEN_WRITE_PROTECTED; | |
183 } | |
184 | |
185 issuer = lg_FindAttribute(CKA_ISSUER, templ, count); | |
186 serial = lg_FindAttribute(CKA_SERIAL_NUMBER, templ, count); | |
187 | |
188 if (issuer && serial) { | |
189 issuerSN.derIssuer.data = (unsigned char *)issuer->pValue; | |
190 issuerSN.derIssuer.len = issuer->ulValueLen ; | |
191 | |
192 issuerSN.serialNumber.data = (unsigned char *)serial->pValue; | |
193 issuerSN.serialNumber.len = serial->ulValueLen ; | |
194 | |
195 cert = nsslowcert_FindCertByIssuerAndSN(certHandle,&issuerSN); | |
196 } | |
197 | |
198 if (cert == NULL) { | |
199 return CKR_ATTRIBUTE_VALUE_INVALID; | |
200 } | |
201 | |
202 lg_GetULongAttribute(CKA_TRUST_SERVER_AUTH, templ, count, &sslTrust); | |
203 lg_GetULongAttribute(CKA_TRUST_CLIENT_AUTH, templ, count, &clientTrust); | |
204 lg_GetULongAttribute(CKA_TRUST_EMAIL_PROTECTION, templ, count, &emailTrust); | |
205 lg_GetULongAttribute(CKA_TRUST_CODE_SIGNING, templ, count, &signTrust); | |
206 stepUp = CK_FALSE; | |
207 trust = lg_FindAttribute(CKA_TRUST_STEP_UP_APPROVED, templ, count); | |
208 if (trust) { | |
209 if (trust->ulValueLen == sizeof(CK_BBOOL)) { | |
210 stepUp = *(CK_BBOOL*)trust->pValue; | |
211 } | |
212 } | |
213 | |
214 /* preserve certain old fields */ | |
215 if (cert->trust) { | |
216 dbTrust.sslFlags = cert->trust->sslFlags & CERTDB_PRESERVE_TRUST_BITS; | |
217 dbTrust.emailFlags= | |
218 cert->trust->emailFlags & CERTDB_PRESERVE_TRUST_BITS; | |
219 dbTrust.objectSigningFlags = | |
220 cert->trust->objectSigningFlags & CERTDB_PRESERVE_TRUST_BITS; | |
221 } | |
222 | |
223 dbTrust.sslFlags |= lg_MapTrust(sslTrust,PR_FALSE); | |
224 dbTrust.sslFlags |= lg_MapTrust(clientTrust,PR_TRUE); | |
225 dbTrust.emailFlags |= lg_MapTrust(emailTrust,PR_FALSE); | |
226 dbTrust.objectSigningFlags |= lg_MapTrust(signTrust,PR_FALSE); | |
227 if (stepUp) { | |
228 dbTrust.sslFlags |= CERTDB_GOVT_APPROVED_CA; | |
229 } | |
230 | |
231 rv = nsslowcert_ChangeCertTrust(certHandle,cert,&dbTrust); | |
232 *handle=lg_mkHandle(sdb,&cert->certKey,LG_TOKEN_TYPE_TRUST); | |
233 nsslowcert_DestroyCertificate(cert); | |
234 if (rv != SECSuccess) { | |
235 return CKR_DEVICE_ERROR; | |
236 } | |
237 | |
238 return CKR_OK; | |
239 } | |
240 | |
241 /* | |
242 * check the consistancy and initialize a Trust Object | |
243 */ | |
244 static CK_RV | |
245 lg_createSMimeObject(SDB *sdb, CK_OBJECT_HANDLE *handle, | |
246 const CK_ATTRIBUTE *templ, CK_ULONG count) | |
247 { | |
248 SECItem derSubj,rawProfile,rawTime,emailKey; | |
249 SECItem *pRawProfile = NULL; | |
250 SECItem *pRawTime = NULL; | |
251 char *email = NULL; | |
252 const CK_ATTRIBUTE *subject = NULL, | |
253 *profile = NULL, | |
254 *time = NULL; | |
255 SECStatus rv; | |
256 NSSLOWCERTCertDBHandle *certHandle; | |
257 CK_RV ck_rv = CKR_OK; | |
258 | |
259 /* we can't store any certs private */ | |
260 if (lg_isTrue(CKA_PRIVATE,templ,count)) { | |
261 return CKR_ATTRIBUTE_VALUE_INVALID; | |
262 } | |
263 | |
264 certHandle = lg_getCertDB(sdb); | |
265 if (certHandle == NULL) { | |
266 return CKR_TOKEN_WRITE_PROTECTED; | |
267 } | |
268 | |
269 /* lookup SUBJECT */ | |
270 subject = lg_FindAttribute(CKA_SUBJECT,templ,count); | |
271 PORT_Assert(subject); | |
272 if (!subject) { | |
273 ck_rv = CKR_ATTRIBUTE_VALUE_INVALID; | |
274 goto loser; | |
275 } | |
276 | |
277 derSubj.data = (unsigned char *)subject->pValue; | |
278 derSubj.len = subject->ulValueLen ; | |
279 derSubj.type = 0; | |
280 | |
281 /* lookup VALUE */ | |
282 profile = lg_FindAttribute(CKA_VALUE,templ,count); | |
283 if (profile) { | |
284 rawProfile.data = (unsigned char *)profile->pValue; | |
285 rawProfile.len = profile->ulValueLen ; | |
286 rawProfile.type = siBuffer; | |
287 pRawProfile = &rawProfile; | |
288 } | |
289 | |
290 /* lookup Time */ | |
291 time = lg_FindAttribute(CKA_NSS_SMIME_TIMESTAMP,templ,count); | |
292 if (time) { | |
293 rawTime.data = (unsigned char *)time->pValue; | |
294 rawTime.len = time->ulValueLen ; | |
295 rawTime.type = siBuffer; | |
296 pRawTime = &rawTime; | |
297 } | |
298 | |
299 | |
300 email = lg_getString(CKA_NSS_EMAIL,templ,count); | |
301 if (!email) { | |
302 ck_rv = CKR_ATTRIBUTE_VALUE_INVALID; | |
303 goto loser; | |
304 } | |
305 | |
306 /* Store S/MIME Profile by SUBJECT */ | |
307 rv = nsslowcert_SaveSMimeProfile(certHandle, email, &derSubj, | |
308 pRawProfile,pRawTime); | |
309 if (rv != SECSuccess) { | |
310 ck_rv = CKR_DEVICE_ERROR; | |
311 goto loser; | |
312 } | |
313 emailKey.data = (unsigned char *)email; | |
314 emailKey.len = PORT_Strlen(email)+1; | |
315 | |
316 *handle = lg_mkHandle(sdb, &emailKey, LG_TOKEN_TYPE_SMIME); | |
317 | |
318 loser: | |
319 if (email) PORT_Free(email); | |
320 | |
321 return ck_rv; | |
322 } | |
323 | |
324 /* | |
325 * check the consistancy and initialize a Trust Object | |
326 */ | |
327 static CK_RV | |
328 lg_createCrlObject(SDB *sdb, CK_OBJECT_HANDLE *handle, | |
329 const CK_ATTRIBUTE *templ, CK_ULONG count) | |
330 { | |
331 PRBool isKRL = PR_FALSE; | |
332 SECItem derSubj,derCrl; | |
333 char *url = NULL; | |
334 const CK_ATTRIBUTE *subject,*crl; | |
335 SECStatus rv; | |
336 NSSLOWCERTCertDBHandle *certHandle; | |
337 | |
338 certHandle = lg_getCertDB(sdb); | |
339 | |
340 /* we can't store any private crls */ | |
341 if (lg_isTrue(CKA_PRIVATE,templ,count)) { | |
342 return CKR_ATTRIBUTE_VALUE_INVALID; | |
343 } | |
344 | |
345 if (certHandle == NULL) { | |
346 return CKR_TOKEN_WRITE_PROTECTED; | |
347 } | |
348 | |
349 /* lookup SUBJECT */ | |
350 subject = lg_FindAttribute(CKA_SUBJECT,templ,count); | |
351 if (!subject) { | |
352 return CKR_ATTRIBUTE_VALUE_INVALID; | |
353 } | |
354 | |
355 derSubj.data = (unsigned char *)subject->pValue; | |
356 derSubj.len = subject->ulValueLen ; | |
357 | |
358 /* lookup VALUE */ | |
359 crl = lg_FindAttribute(CKA_VALUE,templ,count); | |
360 PORT_Assert(crl); | |
361 if (!crl) { | |
362 return CKR_ATTRIBUTE_VALUE_INVALID; | |
363 } | |
364 derCrl.data = (unsigned char *)crl->pValue; | |
365 derCrl.len = crl->ulValueLen ; | |
366 | |
367 url = lg_getString(CKA_NSS_URL,templ,count); | |
368 isKRL = lg_isTrue(CKA_NSS_KRL,templ,count); | |
369 | |
370 /* Store CRL by SUBJECT */ | |
371 rv = nsslowcert_AddCrl(certHandle, &derCrl, &derSubj, url, isKRL); | |
372 | |
373 if (url) { | |
374 PORT_Free(url); | |
375 } | |
376 if (rv != SECSuccess) { | |
377 return CKR_DEVICE_ERROR; | |
378 } | |
379 | |
380 /* if we overwrote the existing CRL, poison the handle entry so we get | |
381 * a new object handle */ | |
382 (void) lg_poisonHandle(sdb, &derSubj, | |
383 isKRL ? LG_TOKEN_KRL_HANDLE : LG_TOKEN_TYPE_CRL); | |
384 *handle = lg_mkHandle(sdb, &derSubj, | |
385 isKRL ? LG_TOKEN_KRL_HANDLE : LG_TOKEN_TYPE_CRL); | |
386 | |
387 return CKR_OK; | |
388 } | |
389 | |
390 /* | |
391 * check the consistancy and initialize a Public Key Object | |
392 */ | |
393 static CK_RV | |
394 lg_createPublicKeyObject(SDB *sdb, CK_KEY_TYPE key_type, | |
395 CK_OBJECT_HANDLE *handle, const CK_ATTRIBUTE *templ, CK_ULONG count) | |
396 { | |
397 CK_ATTRIBUTE_TYPE pubKeyAttr = CKA_VALUE; | |
398 CK_RV crv = CKR_OK; | |
399 NSSLOWKEYPrivateKey *priv; | |
400 SECItem pubKeySpace = {siBuffer, NULL, 0}; | |
401 SECItem *pubKey; | |
402 #ifndef NSS_DISABLE_ECC | |
403 SECItem pubKey2Space = {siBuffer, NULL, 0}; | |
404 PLArenaPool *arena = NULL; | |
405 #endif /* NSS_DISABLE_ECC */ | |
406 NSSLOWKEYDBHandle *keyHandle = NULL; | |
407 | |
408 | |
409 switch (key_type) { | |
410 case CKK_RSA: | |
411 pubKeyAttr = CKA_MODULUS; | |
412 break; | |
413 #ifndef NSS_DISABLE_ECC | |
414 case CKK_EC: | |
415 pubKeyAttr = CKA_EC_POINT; | |
416 break; | |
417 #endif /* NSS_DISABLE_ECC */ | |
418 case CKK_DSA: | |
419 case CKK_DH: | |
420 break; | |
421 default: | |
422 return CKR_ATTRIBUTE_VALUE_INVALID; | |
423 } | |
424 | |
425 | |
426 pubKey = &pubKeySpace; | |
427 crv = lg_Attribute2SSecItem(NULL,pubKeyAttr,templ,count,pubKey); | |
428 if (crv != CKR_OK) return crv; | |
429 | |
430 #ifndef NSS_DISABLE_ECC | |
431 if (key_type == CKK_EC) { | |
432 SECStatus rv; | |
433 /* | |
434 * for ECC, use the decoded key first. | |
435 */ | |
436 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | |
437 if (arena == NULL) { | |
438 crv = CKR_HOST_MEMORY; | |
439 goto done; | |
440 } | |
441 rv= SEC_QuickDERDecodeItem(arena, &pubKey2Space, | |
442 SEC_ASN1_GET(SEC_OctetStringTemplate), | |
443 pubKey); | |
444 if (rv != SECSuccess) { | |
445 /* decode didn't work, just try the pubKey */ | |
446 PORT_FreeArena(arena, PR_FALSE); | |
447 arena = NULL; | |
448 } else { | |
449 /* try the decoded pub key first */ | |
450 pubKey = &pubKey2Space; | |
451 } | |
452 } | |
453 #endif /* NSS_DISABLE_ECC */ | |
454 | |
455 PORT_Assert(pubKey->data); | |
456 if (pubKey->data == NULL) { | |
457 crv = CKR_ATTRIBUTE_VALUE_INVALID; | |
458 goto done; | |
459 } | |
460 keyHandle = lg_getKeyDB(sdb); | |
461 if (keyHandle == NULL) { | |
462 crv = CKR_TOKEN_WRITE_PROTECTED; | |
463 goto done; | |
464 } | |
465 if (keyHandle->version != 3) { | |
466 unsigned char buf[SHA1_LENGTH]; | |
467 SHA1_HashBuf(buf,pubKey->data,pubKey->len); | |
468 PORT_Memcpy(pubKey->data,buf,sizeof(buf)); | |
469 pubKey->len = sizeof(buf); | |
470 } | |
471 /* make sure the associated private key already exists */ | |
472 /* only works if we are logged in */ | |
473 priv = nsslowkey_FindKeyByPublicKey(keyHandle, pubKey, sdb /*password*/); | |
474 #ifndef NSS_DISABLE_ECC | |
475 if (priv == NULL && pubKey == &pubKey2Space) { | |
476 /* no match on the decoded key, match the original pubkey */ | |
477 pubKey = &pubKeySpace; | |
478 priv = nsslowkey_FindKeyByPublicKey(keyHandle, pubKey, | |
479 sdb /*password*/); | |
480 } | |
481 #endif | |
482 if (priv == NULL) { | |
483 /* the legacy database can only 'store' public keys which already | |
484 * have their corresponding private keys in the database */ | |
485 crv = CKR_ATTRIBUTE_VALUE_INVALID; | |
486 goto done; | |
487 } | |
488 lg_nsslowkey_DestroyPrivateKey(priv); | |
489 crv = CKR_OK; | |
490 | |
491 *handle = lg_mkHandle(sdb, pubKey, LG_TOKEN_TYPE_PUB); | |
492 | |
493 done: | |
494 PORT_Free(pubKeySpace.data); | |
495 #ifndef NSS_DISABLE_ECC | |
496 if (arena) | |
497 PORT_FreeArena(arena, PR_FALSE); | |
498 #endif | |
499 | |
500 return crv; | |
501 } | |
502 | |
503 /* make a private key from a verified object */ | |
504 static NSSLOWKEYPrivateKey * | |
505 lg_mkPrivKey(SDB *sdb, const CK_ATTRIBUTE *templ, CK_ULONG count, | |
506 CK_KEY_TYPE key_type, CK_RV *crvp) | |
507 { | |
508 NSSLOWKEYPrivateKey *privKey; | |
509 PLArenaPool *arena; | |
510 CK_RV crv = CKR_OK; | |
511 SECStatus rv; | |
512 | |
513 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | |
514 if (arena == NULL) { | |
515 *crvp = CKR_HOST_MEMORY; | |
516 return NULL; | |
517 } | |
518 | |
519 privKey = (NSSLOWKEYPrivateKey *) | |
520 PORT_ArenaZAlloc(arena,sizeof(NSSLOWKEYPrivateKey)); | |
521 if (privKey == NULL) { | |
522 PORT_FreeArena(arena,PR_FALSE); | |
523 *crvp = CKR_HOST_MEMORY; | |
524 return NULL; | |
525 } | |
526 | |
527 /* in future this would be a switch on key_type */ | |
528 privKey->arena = arena; | |
529 switch (key_type) { | |
530 case CKK_RSA: | |
531 privKey->keyType = NSSLOWKEYRSAKey; | |
532 crv=lg_Attribute2SSecItem(arena,CKA_MODULUS,templ,count, | |
533 &privKey->u.rsa.modulus); | |
534 if (crv != CKR_OK) break; | |
535 crv=lg_Attribute2SSecItem(arena,CKA_PUBLIC_EXPONENT,templ,count, | |
536 &privKey->u.rsa.publicExponent); | |
537 if (crv != CKR_OK) break; | |
538 crv=lg_PrivAttr2SSecItem(arena,CKA_PRIVATE_EXPONENT,templ,count, | |
539 &privKey->u.rsa.privateExponent, sdb); | |
540 if (crv != CKR_OK) break; | |
541 crv=lg_PrivAttr2SSecItem(arena,CKA_PRIME_1,templ,count, | |
542 &privKey->u.rsa.prime1, sdb); | |
543 if (crv != CKR_OK) break; | |
544 crv=lg_PrivAttr2SSecItem(arena,CKA_PRIME_2,templ,count, | |
545 &privKey->u.rsa.prime2, sdb); | |
546 if (crv != CKR_OK) break; | |
547 crv=lg_PrivAttr2SSecItem(arena,CKA_EXPONENT_1,templ,count, | |
548 &privKey->u.rsa.exponent1, sdb); | |
549 if (crv != CKR_OK) break; | |
550 crv=lg_PrivAttr2SSecItem(arena,CKA_EXPONENT_2,templ,count, | |
551 &privKey->u.rsa.exponent2, sdb); | |
552 if (crv != CKR_OK) break; | |
553 crv=lg_PrivAttr2SSecItem(arena,CKA_COEFFICIENT,templ,count, | |
554 &privKey->u.rsa.coefficient, sdb); | |
555 if (crv != CKR_OK) break; | |
556 rv = DER_SetUInteger(privKey->arena, &privKey->u.rsa.version, | |
557 NSSLOWKEY_VERSION); | |
558 if (rv != SECSuccess) crv = CKR_HOST_MEMORY; | |
559 break; | |
560 | |
561 case CKK_DSA: | |
562 privKey->keyType = NSSLOWKEYDSAKey; | |
563 crv = lg_Attribute2SSecItem(arena,CKA_PRIME,templ,count, | |
564 &privKey->u.dsa.params.prime); | |
565 if (crv != CKR_OK) break; | |
566 crv = lg_Attribute2SSecItem(arena,CKA_SUBPRIME,templ,count, | |
567 &privKey->u.dsa.params.subPrime); | |
568 if (crv != CKR_OK) break; | |
569 crv = lg_Attribute2SSecItem(arena,CKA_BASE,templ,count, | |
570 &privKey->u.dsa.params.base); | |
571 if (crv != CKR_OK) break; | |
572 crv = lg_PrivAttr2SSecItem(arena,CKA_VALUE,templ,count, | |
573 &privKey->u.dsa.privateValue, sdb); | |
574 if (crv != CKR_OK) break; | |
575 if (lg_hasAttribute(CKA_NETSCAPE_DB, templ,count)) { | |
576 crv = lg_Attribute2SSecItem(arena, CKA_NETSCAPE_DB,templ,count, | |
577 &privKey->u.dsa.publicValue); | |
578 /* privKey was zero'd so public value is already set to NULL, 0 | |
579 * if we don't set it explicitly */ | |
580 } | |
581 break; | |
582 | |
583 case CKK_DH: | |
584 privKey->keyType = NSSLOWKEYDHKey; | |
585 crv = lg_Attribute2SSecItem(arena,CKA_PRIME,templ,count, | |
586 &privKey->u.dh.prime); | |
587 if (crv != CKR_OK) break; | |
588 crv = lg_Attribute2SSecItem(arena,CKA_BASE,templ,count, | |
589 &privKey->u.dh.base); | |
590 if (crv != CKR_OK) break; | |
591 crv = lg_PrivAttr2SSecItem(arena,CKA_VALUE,templ,count, | |
592 &privKey->u.dh.privateValue, sdb); | |
593 if (crv != CKR_OK) break; | |
594 if (lg_hasAttribute(CKA_NETSCAPE_DB, templ, count)) { | |
595 crv = lg_Attribute2SSecItem(arena, CKA_NETSCAPE_DB,templ,count, | |
596 &privKey->u.dh.publicValue); | |
597 /* privKey was zero'd so public value is already set to NULL, 0 | |
598 * if we don't set it explicitly */ | |
599 } | |
600 break; | |
601 | |
602 #ifndef NSS_DISABLE_ECC | |
603 case CKK_EC: | |
604 privKey->keyType = NSSLOWKEYECKey; | |
605 crv = lg_Attribute2SSecItem(arena, CKA_EC_PARAMS,templ,count, | |
606 &privKey->u.ec.ecParams.DEREncoding); | |
607 if (crv != CKR_OK) break; | |
608 | |
609 /* Fill out the rest of the ecParams structure | |
610 * based on the encoded params | |
611 */ | |
612 if (LGEC_FillParams(arena, &privKey->u.ec.ecParams.DEREncoding, | |
613 &privKey->u.ec.ecParams) != SECSuccess) { | |
614 crv = CKR_DOMAIN_PARAMS_INVALID; | |
615 break; | |
616 } | |
617 crv = lg_PrivAttr2SSecItem(arena,CKA_VALUE,templ,count, | |
618 &privKey->u.ec.privateValue, sdb); | |
619 if (crv != CKR_OK) break; | |
620 if (lg_hasAttribute(CKA_NETSCAPE_DB,templ,count)) { | |
621 crv = lg_Attribute2SSecItem(arena, CKA_NETSCAPE_DB,templ,count, | |
622 &privKey->u.ec.publicValue); | |
623 if (crv != CKR_OK) break; | |
624 /* privKey was zero'd so public value is already set to NULL, 0 | |
625 * if we don't set it explicitly */ | |
626 } | |
627 rv = DER_SetUInteger(privKey->arena, &privKey->u.ec.version, | |
628 NSSLOWKEY_EC_PRIVATE_KEY_VERSION); | |
629 if (rv != SECSuccess) crv = CKR_HOST_MEMORY; | |
630 break; | |
631 #endif /* NSS_DISABLE_ECC */ | |
632 | |
633 default: | |
634 crv = CKR_KEY_TYPE_INCONSISTENT; | |
635 break; | |
636 } | |
637 *crvp = crv; | |
638 if (crv != CKR_OK) { | |
639 PORT_FreeArena(arena,PR_FALSE); | |
640 return NULL; | |
641 } | |
642 return privKey; | |
643 } | |
644 | |
645 /* | |
646 * check the consistancy and initialize a Private Key Object | |
647 */ | |
648 static CK_RV | |
649 lg_createPrivateKeyObject(SDB *sdb, CK_KEY_TYPE key_type, | |
650 CK_OBJECT_HANDLE *handle, const CK_ATTRIBUTE *templ, CK_ULONG count) | |
651 { | |
652 NSSLOWKEYPrivateKey *privKey; | |
653 char *label; | |
654 SECStatus rv = SECSuccess; | |
655 CK_RV crv = CKR_DEVICE_ERROR; | |
656 SECItem pubKey; | |
657 NSSLOWKEYDBHandle *keyHandle = lg_getKeyDB(sdb); | |
658 | |
659 if (keyHandle == NULL) { | |
660 return CKR_TOKEN_WRITE_PROTECTED; | |
661 } | |
662 | |
663 privKey=lg_mkPrivKey(sdb, templ,count,key_type,&crv); | |
664 if (privKey == NULL) return crv; | |
665 label = lg_getString(CKA_LABEL,templ,count); | |
666 | |
667 crv = lg_Attribute2SSecItem(NULL,CKA_NETSCAPE_DB,templ,count,&pubKey); | |
668 if (crv != CKR_OK) { | |
669 crv = CKR_TEMPLATE_INCOMPLETE; | |
670 rv = SECFailure; | |
671 goto fail; | |
672 } | |
673 #ifdef notdef | |
674 if (keyHandle->version != 3) { | |
675 unsigned char buf[SHA1_LENGTH]; | |
676 SHA1_HashBuf(buf,pubKey.data,pubKey.len); | |
677 PORT_Memcpy(pubKey.data,buf,sizeof(buf)); | |
678 pubKey.len = sizeof(buf); | |
679 } | |
680 #endif | |
681 /* get the key type */ | |
682 if (key_type == CKK_RSA) { | |
683 rv = RSA_PrivateKeyCheck(&privKey->u.rsa); | |
684 if (rv == SECFailure) { | |
685 goto fail; | |
686 } | |
687 } | |
688 rv = nsslowkey_StoreKeyByPublicKey(keyHandle, privKey, &pubKey, | |
689 label, sdb /*->password*/); | |
690 | |
691 fail: | |
692 if (label) PORT_Free(label); | |
693 *handle = lg_mkHandle(sdb,&pubKey,LG_TOKEN_TYPE_PRIV); | |
694 if (pubKey.data) PORT_Free(pubKey.data); | |
695 lg_nsslowkey_DestroyPrivateKey(privKey); | |
696 if (rv != SECSuccess) return crv; | |
697 | |
698 return CKR_OK; | |
699 } | |
700 | |
701 | |
702 #define LG_KEY_MAX_RETRIES 10 /* don't hang if we are having problems with the rng */ | |
703 #define LG_KEY_ID_SIZE 18 /* don't use either SHA1 or MD5 sizes */ | |
704 /* | |
705 * Secret keys must have a CKA_ID value to be stored in the database. This code | |
706 * will generate one if there wasn't one already. | |
707 */ | |
708 static CK_RV | |
709 lg_GenerateSecretCKA_ID(NSSLOWKEYDBHandle *handle, SECItem *id, char *label) | |
710 { | |
711 unsigned int retries; | |
712 SECStatus rv = SECSuccess; | |
713 CK_RV crv = CKR_OK; | |
714 | |
715 id->data = NULL; | |
716 if (label) { | |
717 id->data = (unsigned char *)PORT_Strdup(label); | |
718 if (id->data == NULL) { | |
719 return CKR_HOST_MEMORY; | |
720 } | |
721 id->len = PORT_Strlen(label)+1; | |
722 if (!nsslowkey_KeyForIDExists(handle,id)) { | |
723 return CKR_OK; | |
724 } | |
725 PORT_Free(id->data); | |
726 id->data = NULL; | |
727 id->len = 0; | |
728 } | |
729 id->data = (unsigned char *)PORT_Alloc(LG_KEY_ID_SIZE); | |
730 if (id->data == NULL) { | |
731 return CKR_HOST_MEMORY; | |
732 } | |
733 id->len = LG_KEY_ID_SIZE; | |
734 | |
735 retries = 0; | |
736 do { | |
737 rv = RNG_GenerateGlobalRandomBytes(id->data,id->len); | |
738 } while (rv == SECSuccess && nsslowkey_KeyForIDExists(handle,id) && | |
739 (++retries <= LG_KEY_MAX_RETRIES)); | |
740 | |
741 if ((rv != SECSuccess) || (retries > LG_KEY_MAX_RETRIES)) { | |
742 crv = CKR_DEVICE_ERROR; /* random number generator is bad */ | |
743 PORT_Free(id->data); | |
744 id->data = NULL; | |
745 id->len = 0; | |
746 } | |
747 return crv; | |
748 } | |
749 | |
750 | |
751 static NSSLOWKEYPrivateKey *lg_mkSecretKeyRep(const CK_ATTRIBUTE *templ, | |
752 CK_ULONG count, CK_KEY_TYPE key_type, | |
753 SECItem *pubkey, SDB *sdbpw) | |
754 { | |
755 NSSLOWKEYPrivateKey *privKey = 0; | |
756 PLArenaPool *arena = 0; | |
757 CK_KEY_TYPE keyType; | |
758 PRUint32 keyTypeStorage; | |
759 SECItem keyTypeItem; | |
760 CK_RV crv; | |
761 SECStatus rv; | |
762 static unsigned char derZero[1] = { 0 }; | |
763 | |
764 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | |
765 if (arena == NULL) { crv = CKR_HOST_MEMORY; goto loser; } | |
766 | |
767 privKey = (NSSLOWKEYPrivateKey *) | |
768 PORT_ArenaZAlloc(arena,sizeof(NSSLOWKEYPrivateKey)); | |
769 if (privKey == NULL) { crv = CKR_HOST_MEMORY; goto loser; } | |
770 | |
771 privKey->arena = arena; | |
772 | |
773 /* Secret keys are represented in the database as "fake" RSA keys. | |
774 * The RSA key is marked as a secret key representation by setting the | |
775 * public exponent field to 0, which is an invalid RSA exponent. | |
776 * The other fields are set as follows: | |
777 * modulus - CKA_ID value for the secret key | |
778 * private exponent - CKA_VALUE (the key itself) | |
779 * coefficient - CKA_KEY_TYPE, which indicates what encryption algorithm | |
780 * is used for the key. | |
781 * all others - set to integer 0 | |
782 */ | |
783 privKey->keyType = NSSLOWKEYRSAKey; | |
784 | |
785 /* The modulus is set to the key id of the symmetric key */ | |
786 privKey->u.rsa.modulus.data = | |
787 (unsigned char *) PORT_ArenaAlloc(arena, pubkey->len); | |
788 if (privKey->u.rsa.modulus.data == NULL) { | |
789 crv = CKR_HOST_MEMORY; | |
790 goto loser; | |
791 } | |
792 privKey->u.rsa.modulus.len = pubkey->len; | |
793 PORT_Memcpy(privKey->u.rsa.modulus.data, pubkey->data, pubkey->len); | |
794 | |
795 /* The public exponent is set to 0 to indicate a special key */ | |
796 privKey->u.rsa.publicExponent.len = sizeof derZero; | |
797 privKey->u.rsa.publicExponent.data = derZero; | |
798 | |
799 /* The private exponent is the actual key value */ | |
800 crv = lg_PrivAttr2SecItem(arena, CKA_VALUE, templ, count, | |
801 &privKey->u.rsa.privateExponent, sdbpw); | |
802 if (crv != CKR_OK) goto loser; | |
803 | |
804 /* All other fields empty - needs testing */ | |
805 privKey->u.rsa.prime1.len = sizeof derZero; | |
806 privKey->u.rsa.prime1.data = derZero; | |
807 | |
808 privKey->u.rsa.prime2.len = sizeof derZero; | |
809 privKey->u.rsa.prime2.data = derZero; | |
810 | |
811 privKey->u.rsa.exponent1.len = sizeof derZero; | |
812 privKey->u.rsa.exponent1.data = derZero; | |
813 | |
814 privKey->u.rsa.exponent2.len = sizeof derZero; | |
815 privKey->u.rsa.exponent2.data = derZero; | |
816 | |
817 /* Coeficient set to KEY_TYPE */ | |
818 crv = lg_GetULongAttribute(CKA_KEY_TYPE, templ, count, &keyType); | |
819 if (crv != CKR_OK) goto loser; | |
820 /* on 64 bit platforms, we still want to store 32 bits of keyType (This is | |
821 * safe since the PKCS #11 defines for all types are 32 bits or less). */ | |
822 keyTypeStorage = (PRUint32) keyType; | |
823 keyTypeStorage = PR_htonl(keyTypeStorage); | |
824 keyTypeItem.data = (unsigned char *)&keyTypeStorage; | |
825 keyTypeItem.len = sizeof (keyTypeStorage); | |
826 rv = SECITEM_CopyItem(arena, &privKey->u.rsa.coefficient, &keyTypeItem); | |
827 if (rv != SECSuccess) { | |
828 crv = CKR_HOST_MEMORY; | |
829 goto loser; | |
830 } | |
831 | |
832 /* Private key version field set normally for compatibility */ | |
833 rv = DER_SetUInteger(privKey->arena, | |
834 &privKey->u.rsa.version, NSSLOWKEY_VERSION); | |
835 if (rv != SECSuccess) { crv = CKR_HOST_MEMORY; goto loser; } | |
836 | |
837 loser: | |
838 if (crv != CKR_OK) { | |
839 PORT_FreeArena(arena,PR_FALSE); | |
840 privKey = 0; | |
841 } | |
842 | |
843 return privKey; | |
844 } | |
845 | |
846 /* | |
847 * check the consistancy and initialize a Secret Key Object | |
848 */ | |
849 static CK_RV | |
850 lg_createSecretKeyObject(SDB *sdb, CK_KEY_TYPE key_type, | |
851 CK_OBJECT_HANDLE *handle, const CK_ATTRIBUTE *templ, CK_ULONG count) | |
852 { | |
853 CK_RV crv; | |
854 NSSLOWKEYPrivateKey *privKey = NULL; | |
855 NSSLOWKEYDBHandle *keyHandle = NULL; | |
856 SECItem pubKey; | |
857 char *label = NULL; | |
858 SECStatus rv = SECSuccess; | |
859 | |
860 pubKey.data = 0; | |
861 | |
862 /* If the object is a TOKEN object, store in the database */ | |
863 keyHandle = lg_getKeyDB(sdb); | |
864 | |
865 if (keyHandle == NULL) { | |
866 return CKR_TOKEN_WRITE_PROTECTED; | |
867 } | |
868 | |
869 label = lg_getString(CKA_LABEL,templ,count); | |
870 | |
871 crv = lg_Attribute2SecItem(NULL,CKA_ID,templ,count,&pubKey); | |
872 /* Should this be ID? */ | |
873 if (crv != CKR_OK) goto loser; | |
874 | |
875 /* if we don't have an ID, generate one */ | |
876 if (pubKey.len == 0) { | |
877 if (pubKey.data) { | |
878 PORT_Free(pubKey.data); | |
879 pubKey.data = NULL; | |
880 } | |
881 crv = lg_GenerateSecretCKA_ID(keyHandle, &pubKey, label); | |
882 if (crv != CKR_OK) goto loser; | |
883 } | |
884 | |
885 privKey = lg_mkSecretKeyRep(templ, count, key_type, &pubKey, sdb); | |
886 if (privKey == NULL) { | |
887 crv = CKR_HOST_MEMORY; | |
888 goto loser; | |
889 } | |
890 | |
891 rv = nsslowkey_StoreKeyByPublicKey(keyHandle, | |
892 privKey, &pubKey, label, sdb /*->password*/); | |
893 if (rv != SECSuccess) { | |
894 crv = CKR_DEVICE_ERROR; | |
895 goto loser; | |
896 } | |
897 | |
898 *handle = lg_mkHandle(sdb, &pubKey, LG_TOKEN_TYPE_KEY); | |
899 | |
900 loser: | |
901 if (label) PORT_Free(label); | |
902 if (privKey) lg_nsslowkey_DestroyPrivateKey(privKey); | |
903 if (pubKey.data) PORT_Free(pubKey.data); | |
904 | |
905 return crv; | |
906 } | |
907 | |
908 /* | |
909 * check the consistancy and initialize a Key Object | |
910 */ | |
911 static CK_RV | |
912 lg_createKeyObject(SDB *sdb, CK_OBJECT_CLASS objclass, | |
913 CK_OBJECT_HANDLE *handle, const CK_ATTRIBUTE *templ, CK_ULONG count) | |
914 { | |
915 CK_RV crv; | |
916 CK_KEY_TYPE key_type; | |
917 | |
918 /* get the key type */ | |
919 crv = lg_GetULongAttribute(CKA_KEY_TYPE, templ, count, &key_type); | |
920 if (crv != CKR_OK) { | |
921 return crv; | |
922 } | |
923 | |
924 switch (objclass) { | |
925 case CKO_PUBLIC_KEY: | |
926 return lg_createPublicKeyObject(sdb,key_type,handle,templ,count); | |
927 case CKO_PRIVATE_KEY: | |
928 return lg_createPrivateKeyObject(sdb,key_type,handle,templ,count); | |
929 case CKO_SECRET_KEY: | |
930 return lg_createSecretKeyObject(sdb,key_type,handle,templ,count); | |
931 default: | |
932 break; | |
933 } | |
934 return CKR_ATTRIBUTE_VALUE_INVALID; | |
935 } | |
936 | |
937 /* | |
938 * Parse the template and create an object stored in the DB that reflects. | |
939 * the object specified in the database. | |
940 */ | |
941 CK_RV | |
942 lg_CreateObject(SDB *sdb, CK_OBJECT_HANDLE *handle, | |
943 const CK_ATTRIBUTE *templ, CK_ULONG count) | |
944 { | |
945 CK_RV crv; | |
946 CK_OBJECT_CLASS objclass; | |
947 | |
948 /* get the object class */ | |
949 crv = lg_GetULongAttribute(CKA_CLASS, templ, count, &objclass); | |
950 if (crv != CKR_OK) { | |
951 return crv; | |
952 } | |
953 | |
954 /* Now handle the specific object class. | |
955 */ | |
956 switch (objclass) { | |
957 case CKO_CERTIFICATE: | |
958 crv = lg_createCertObject(sdb,handle,templ,count); | |
959 break; | |
960 case CKO_NSS_TRUST: | |
961 crv = lg_createTrustObject(sdb,handle,templ,count); | |
962 break; | |
963 case CKO_NSS_CRL: | |
964 crv = lg_createCrlObject(sdb,handle,templ,count); | |
965 break; | |
966 case CKO_NSS_SMIME: | |
967 crv = lg_createSMimeObject(sdb,handle,templ,count); | |
968 break; | |
969 case CKO_PRIVATE_KEY: | |
970 case CKO_PUBLIC_KEY: | |
971 case CKO_SECRET_KEY: | |
972 crv = lg_createKeyObject(sdb,objclass,handle,templ,count); | |
973 break; | |
974 default: | |
975 crv = CKR_ATTRIBUTE_VALUE_INVALID; | |
976 break; | |
977 } | |
978 | |
979 return crv; | |
980 } | |
981 |