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