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