Source code

Revision control

Other Tools

1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
* License, v. 2.0. If a copy of the MPL was not distributed with this
3
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
#include "prtime.h"
6
7
#include "cert.h"
8
#include "certi.h"
9
#include "certdb.h"
10
#include "secitem.h"
11
#include "secder.h"
12
13
/* Call to PK11_FreeSlot below */
14
15
#include "secasn1.h"
16
#include "secerr.h"
17
#include "nssilock.h"
18
#include "prmon.h"
19
#include "base64.h"
20
#include "sechash.h"
21
#include "plhash.h"
22
#include "pk11func.h" /* sigh */
23
24
#include "nsspki.h"
25
#include "pki.h"
26
#include "pkim.h"
27
#include "pki3hack.h"
28
#include "ckhelper.h"
29
#include "base.h"
30
#include "pkistore.h"
31
#include "dev3hack.h"
32
#include "dev.h"
33
#include "secmodi.h"
34
35
PRBool
36
SEC_CertNicknameConflict(const char *nickname, const SECItem *derSubject,
37
CERTCertDBHandle *handle)
38
{
39
CERTCertificate *cert;
40
PRBool conflict = PR_FALSE;
41
42
cert = CERT_FindCertByNickname(handle, nickname);
43
44
if (!cert) {
45
return conflict;
46
}
47
48
conflict = !SECITEM_ItemsAreEqual(derSubject, &cert->derSubject);
49
CERT_DestroyCertificate(cert);
50
return conflict;
51
}
52
53
SECStatus
54
SEC_DeletePermCertificate(CERTCertificate *cert)
55
{
56
PRStatus nssrv;
57
NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
58
NSSCertificate *c = STAN_GetNSSCertificate(cert);
59
CERTCertTrust *certTrust;
60
61
if (c == NULL) {
62
/* error code is set */
63
return SECFailure;
64
}
65
66
certTrust = nssTrust_GetCERTCertTrustForCert(c, cert);
67
if (certTrust) {
68
NSSTrust *nssTrust = nssTrustDomain_FindTrustForCertificate(td, c);
69
if (nssTrust) {
70
nssrv = STAN_DeleteCertTrustMatchingSlot(c);
71
if (nssrv != PR_SUCCESS) {
72
CERT_MapStanError();
73
}
74
/* This call always returns PR_SUCCESS! */
75
(void)nssTrust_Destroy(nssTrust);
76
}
77
}
78
79
/* get rid of the token instances */
80
nssrv = NSSCertificate_DeleteStoredObject(c, NULL);
81
82
/* get rid of the cache entry */
83
nssTrustDomain_LockCertCache(td);
84
nssTrustDomain_RemoveCertFromCacheLOCKED(td, c);
85
nssTrustDomain_UnlockCertCache(td);
86
87
return (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
88
}
89
90
SECStatus
91
CERT_GetCertTrust(const CERTCertificate *cert, CERTCertTrust *trust)
92
{
93
SECStatus rv;
94
CERT_LockCertTrust(cert);
95
if (!cert || cert->trust == NULL) {
96
rv = SECFailure;
97
} else {
98
*trust = *cert->trust;
99
rv = SECSuccess;
100
}
101
CERT_UnlockCertTrust(cert);
102
return (rv);
103
}
104
105
extern const NSSError NSS_ERROR_NO_ERROR;
106
extern const NSSError NSS_ERROR_INTERNAL_ERROR;
107
extern const NSSError NSS_ERROR_NO_MEMORY;
108
extern const NSSError NSS_ERROR_INVALID_POINTER;
109
extern const NSSError NSS_ERROR_INVALID_ARENA;
110
extern const NSSError NSS_ERROR_INVALID_ARENA_MARK;
111
extern const NSSError NSS_ERROR_DUPLICATE_POINTER;
112
extern const NSSError NSS_ERROR_POINTER_NOT_REGISTERED;
113
extern const NSSError NSS_ERROR_TRACKER_NOT_EMPTY;
114
extern const NSSError NSS_ERROR_TRACKER_NOT_INITIALIZED;
115
extern const NSSError NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD;
116
extern const NSSError NSS_ERROR_VALUE_TOO_LARGE;
117
extern const NSSError NSS_ERROR_UNSUPPORTED_TYPE;
118
extern const NSSError NSS_ERROR_BUFFER_TOO_SHORT;
119
extern const NSSError NSS_ERROR_INVALID_ATOB_CONTEXT;
120
extern const NSSError NSS_ERROR_INVALID_BASE64;
121
extern const NSSError NSS_ERROR_INVALID_BTOA_CONTEXT;
122
extern const NSSError NSS_ERROR_INVALID_ITEM;
123
extern const NSSError NSS_ERROR_INVALID_STRING;
124
extern const NSSError NSS_ERROR_INVALID_ASN1ENCODER;
125
extern const NSSError NSS_ERROR_INVALID_ASN1DECODER;
126
extern const NSSError NSS_ERROR_INVALID_BER;
127
extern const NSSError NSS_ERROR_INVALID_ATAV;
128
extern const NSSError NSS_ERROR_INVALID_ARGUMENT;
129
extern const NSSError NSS_ERROR_INVALID_UTF8;
130
extern const NSSError NSS_ERROR_INVALID_NSSOID;
131
extern const NSSError NSS_ERROR_UNKNOWN_ATTRIBUTE;
132
extern const NSSError NSS_ERROR_NOT_FOUND;
133
extern const NSSError NSS_ERROR_INVALID_PASSWORD;
134
extern const NSSError NSS_ERROR_USER_CANCELED;
135
extern const NSSError NSS_ERROR_MAXIMUM_FOUND;
136
extern const NSSError NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND;
137
extern const NSSError NSS_ERROR_CERTIFICATE_IN_CACHE;
138
extern const NSSError NSS_ERROR_HASH_COLLISION;
139
extern const NSSError NSS_ERROR_DEVICE_ERROR;
140
extern const NSSError NSS_ERROR_INVALID_CERTIFICATE;
141
extern const NSSError NSS_ERROR_BUSY;
142
extern const NSSError NSS_ERROR_ALREADY_INITIALIZED;
143
extern const NSSError NSS_ERROR_PKCS11;
144
145
/* Look at the stan error stack and map it to NSS 3 errors */
146
#define STAN_MAP_ERROR(x, y) \
147
else if (error == (x)) { secError = y; }
148
149
/*
150
* map Stan errors into NSS errors
151
* This function examines the stan error stack and automatically sets
152
* PORT_SetError(); to the appropriate SEC_ERROR value.
153
*/
154
void
155
CERT_MapStanError()
156
{
157
PRInt32 *errorStack;
158
NSSError error, prevError;
159
int secError;
160
int i;
161
162
errorStack = NSS_GetErrorStack();
163
if (errorStack == 0) {
164
PORT_SetError(0);
165
return;
166
}
167
error = prevError = CKR_GENERAL_ERROR;
168
/* get the 'top 2' error codes from the stack */
169
for (i = 0; errorStack[i]; i++) {
170
prevError = error;
171
error = errorStack[i];
172
}
173
if (error == NSS_ERROR_PKCS11) {
174
/* map it */
175
secError = PK11_MapError(prevError);
176
}
177
STAN_MAP_ERROR(NSS_ERROR_NO_ERROR, 0)
178
STAN_MAP_ERROR(NSS_ERROR_NO_MEMORY, SEC_ERROR_NO_MEMORY)
179
STAN_MAP_ERROR(NSS_ERROR_INVALID_BASE64, SEC_ERROR_BAD_DATA)
180
STAN_MAP_ERROR(NSS_ERROR_INVALID_BER, SEC_ERROR_BAD_DER)
181
STAN_MAP_ERROR(NSS_ERROR_INVALID_ATAV, SEC_ERROR_INVALID_AVA)
182
STAN_MAP_ERROR(NSS_ERROR_INVALID_PASSWORD, SEC_ERROR_BAD_PASSWORD)
183
STAN_MAP_ERROR(NSS_ERROR_BUSY, SEC_ERROR_BUSY)
184
STAN_MAP_ERROR(NSS_ERROR_DEVICE_ERROR, SEC_ERROR_IO)
185
STAN_MAP_ERROR(NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND,
186
SEC_ERROR_UNKNOWN_ISSUER)
187
STAN_MAP_ERROR(NSS_ERROR_INVALID_CERTIFICATE, SEC_ERROR_CERT_NOT_VALID)
188
STAN_MAP_ERROR(NSS_ERROR_INVALID_UTF8, SEC_ERROR_BAD_DATA)
189
STAN_MAP_ERROR(NSS_ERROR_INVALID_NSSOID, SEC_ERROR_BAD_DATA)
190
191
/* these are library failure for lack of a better error code */
192
STAN_MAP_ERROR(NSS_ERROR_NOT_FOUND, SEC_ERROR_LIBRARY_FAILURE)
193
STAN_MAP_ERROR(NSS_ERROR_CERTIFICATE_IN_CACHE, SEC_ERROR_LIBRARY_FAILURE)
194
STAN_MAP_ERROR(NSS_ERROR_MAXIMUM_FOUND, SEC_ERROR_LIBRARY_FAILURE)
195
STAN_MAP_ERROR(NSS_ERROR_USER_CANCELED, SEC_ERROR_LIBRARY_FAILURE)
196
STAN_MAP_ERROR(NSS_ERROR_TRACKER_NOT_INITIALIZED, SEC_ERROR_LIBRARY_FAILURE)
197
STAN_MAP_ERROR(NSS_ERROR_ALREADY_INITIALIZED, SEC_ERROR_LIBRARY_FAILURE)
198
STAN_MAP_ERROR(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD,
199
SEC_ERROR_LIBRARY_FAILURE)
200
STAN_MAP_ERROR(NSS_ERROR_HASH_COLLISION, SEC_ERROR_LIBRARY_FAILURE)
201
202
STAN_MAP_ERROR(NSS_ERROR_INTERNAL_ERROR, SEC_ERROR_LIBRARY_FAILURE)
203
204
/* these are all invalid arguments */
205
STAN_MAP_ERROR(NSS_ERROR_INVALID_ARGUMENT, SEC_ERROR_INVALID_ARGS)
206
STAN_MAP_ERROR(NSS_ERROR_INVALID_POINTER, SEC_ERROR_INVALID_ARGS)
207
STAN_MAP_ERROR(NSS_ERROR_INVALID_ARENA, SEC_ERROR_INVALID_ARGS)
208
STAN_MAP_ERROR(NSS_ERROR_INVALID_ARENA_MARK, SEC_ERROR_INVALID_ARGS)
209
STAN_MAP_ERROR(NSS_ERROR_DUPLICATE_POINTER, SEC_ERROR_INVALID_ARGS)
210
STAN_MAP_ERROR(NSS_ERROR_POINTER_NOT_REGISTERED, SEC_ERROR_INVALID_ARGS)
211
STAN_MAP_ERROR(NSS_ERROR_TRACKER_NOT_EMPTY, SEC_ERROR_INVALID_ARGS)
212
STAN_MAP_ERROR(NSS_ERROR_VALUE_TOO_LARGE, SEC_ERROR_INVALID_ARGS)
213
STAN_MAP_ERROR(NSS_ERROR_UNSUPPORTED_TYPE, SEC_ERROR_INVALID_ARGS)
214
STAN_MAP_ERROR(NSS_ERROR_BUFFER_TOO_SHORT, SEC_ERROR_INVALID_ARGS)
215
STAN_MAP_ERROR(NSS_ERROR_INVALID_ATOB_CONTEXT, SEC_ERROR_INVALID_ARGS)
216
STAN_MAP_ERROR(NSS_ERROR_INVALID_BTOA_CONTEXT, SEC_ERROR_INVALID_ARGS)
217
STAN_MAP_ERROR(NSS_ERROR_INVALID_ITEM, SEC_ERROR_INVALID_ARGS)
218
STAN_MAP_ERROR(NSS_ERROR_INVALID_STRING, SEC_ERROR_INVALID_ARGS)
219
STAN_MAP_ERROR(NSS_ERROR_INVALID_ASN1ENCODER, SEC_ERROR_INVALID_ARGS)
220
STAN_MAP_ERROR(NSS_ERROR_INVALID_ASN1DECODER, SEC_ERROR_INVALID_ARGS)
221
STAN_MAP_ERROR(NSS_ERROR_UNKNOWN_ATTRIBUTE, SEC_ERROR_INVALID_ARGS)
222
else { secError = SEC_ERROR_LIBRARY_FAILURE; }
223
PORT_SetError(secError);
224
}
225
226
SECStatus
227
CERT_ChangeCertTrust(CERTCertDBHandle *handle, CERTCertificate *cert,
228
CERTCertTrust *trust)
229
{
230
SECStatus rv = SECSuccess;
231
PRStatus ret;
232
233
ret = STAN_ChangeCertTrust(cert, trust);
234
if (ret != PR_SUCCESS) {
235
rv = SECFailure;
236
CERT_MapStanError();
237
}
238
return rv;
239
}
240
241
extern const NSSError NSS_ERROR_INVALID_CERTIFICATE;
242
243
SECStatus
244
__CERT_AddTempCertToPerm(CERTCertificate *cert, char *nickname,
245
CERTCertTrust *trust)
246
{
247
NSSUTF8 *stanNick;
248
PK11SlotInfo *slot;
249
NSSToken *internal;
250
NSSCryptoContext *context;
251
nssCryptokiObject *permInstance;
252
NSSCertificate *c = STAN_GetNSSCertificate(cert);
253
nssCertificateStoreTrace lockTrace = { NULL, NULL, PR_FALSE, PR_FALSE };
254
nssCertificateStoreTrace unlockTrace = { NULL, NULL, PR_FALSE, PR_FALSE };
255
SECStatus rv;
256
PRStatus ret;
257
258
if (c == NULL) {
259
CERT_MapStanError();
260
return SECFailure;
261
}
262
263
context = c->object.cryptoContext;
264
if (!context) {
265
PORT_SetError(SEC_ERROR_ADDING_CERT);
266
return SECFailure; /* wasn't a temp cert */
267
}
268
stanNick = nssCertificate_GetNickname(c, NULL);
269
if (stanNick && nickname && strcmp(nickname, stanNick) != 0) {
270
/* different: take the new nickname */
271
cert->nickname = NULL;
272
nss_ZFreeIf(stanNick);
273
stanNick = NULL;
274
}
275
if (!stanNick && nickname) {
276
/* Either there was no nickname yet, or we have a new nickname */
277
stanNick = nssUTF8_Duplicate((NSSUTF8 *)nickname, NULL);
278
} /* else: old stanNick is identical to new nickname */
279
/* Delete the temp instance */
280
nssCertificateStore_Lock(context->certStore, &lockTrace);
281
nssCertificateStore_RemoveCertLOCKED(context->certStore, c);
282
nssCertificateStore_Unlock(context->certStore, &lockTrace, &unlockTrace);
283
c->object.cryptoContext = NULL;
284
285
/* if the id has not been set explicitly yet, create one from the public
286
* key. */
287
if (c->id.data == NULL) {
288
SECItem *keyID = pk11_mkcertKeyID(cert);
289
if (keyID) {
290
nssItem_Create(c->object.arena, &c->id, keyID->len, keyID->data);
291
SECITEM_FreeItem(keyID, PR_TRUE);
292
}
293
/* if any of these failed, continue with our null c->id */
294
}
295
296
/* Import the perm instance onto the internal token */
297
slot = PK11_GetInternalKeySlot();
298
internal = PK11Slot_GetNSSToken(slot);
299
permInstance = nssToken_ImportCertificate(
300
internal, NULL, NSSCertificateType_PKIX, &c->id, stanNick, &c->encoding,
301
&c->issuer, &c->subject, &c->serial, cert->emailAddr, PR_TRUE);
302
nss_ZFreeIf(stanNick);
303
stanNick = NULL;
304
PK11_FreeSlot(slot);
305
if (!permInstance) {
306
if (NSS_GetError() == NSS_ERROR_INVALID_CERTIFICATE) {
307
PORT_SetError(SEC_ERROR_REUSED_ISSUER_AND_SERIAL);
308
}
309
return SECFailure;
310
}
311
nssPKIObject_AddInstance(&c->object, permInstance);
312
nssTrustDomain_AddCertsToCache(STAN_GetDefaultTrustDomain(), &c, 1);
313
/* reset the CERTCertificate fields */
314
cert->nssCertificate = NULL;
315
cert = STAN_GetCERTCertificateOrRelease(c); /* should return same pointer */
316
if (!cert) {
317
CERT_MapStanError();
318
return SECFailure;
319
}
320
CERT_LockCertTempPerm(cert);
321
cert->istemp = PR_FALSE;
322
cert->isperm = PR_TRUE;
323
CERT_UnlockCertTempPerm(cert);
324
if (!trust) {
325
return SECSuccess;
326
}
327
ret = STAN_ChangeCertTrust(cert, trust);
328
rv = SECSuccess;
329
if (ret != PR_SUCCESS) {
330
rv = SECFailure;
331
CERT_MapStanError();
332
}
333
return rv;
334
}
335
336
SECStatus
337
CERT_AddTempCertToPerm(CERTCertificate *cert, char *nickname,
338
CERTCertTrust *trust)
339
{
340
return __CERT_AddTempCertToPerm(cert, nickname, trust);
341
}
342
343
CERTCertificate *
344
CERT_NewTempCertificate(CERTCertDBHandle *handle, SECItem *derCert,
345
char *nickname, PRBool isperm, PRBool copyDER)
346
{
347
NSSCertificate *c;
348
CERTCertificate *cc;
349
NSSCertificate *tempCert = NULL;
350
nssPKIObject *pkio;
351
NSSCryptoContext *gCC = STAN_GetDefaultCryptoContext();
352
NSSTrustDomain *gTD = STAN_GetDefaultTrustDomain();
353
if (!isperm) {
354
NSSDER encoding;
355
NSSITEM_FROM_SECITEM(&encoding, derCert);
356
/* First, see if it is already a temp cert */
357
c = NSSCryptoContext_FindCertificateByEncodedCertificate(gCC,
358
&encoding);
359
if (!c && handle) {
360
/* Then, see if it is already a perm cert */
361
c = NSSTrustDomain_FindCertificateByEncodedCertificate(handle,
362
&encoding);
363
}
364
if (c) {
365
/* actually, that search ends up going by issuer/serial,
366
* so it is still possible to return a cert with the same
367
* issuer/serial but a different encoding, and we're
368
* going to reject that
369
*/
370
if (!nssItem_Equal(&c->encoding, &encoding, NULL)) {
371
nssCertificate_Destroy(c);
372
PORT_SetError(SEC_ERROR_REUSED_ISSUER_AND_SERIAL);
373
cc = NULL;
374
} else {
375
cc = STAN_GetCERTCertificateOrRelease(c);
376
if (cc == NULL) {
377
CERT_MapStanError();
378
}
379
}
380
return cc;
381
}
382
}
383
pkio = nssPKIObject_Create(NULL, NULL, gTD, gCC, nssPKIMonitor);
384
if (!pkio) {
385
CERT_MapStanError();
386
return NULL;
387
}
388
c = nss_ZNEW(pkio->arena, NSSCertificate);
389
if (!c) {
390
CERT_MapStanError();
391
nssPKIObject_Destroy(pkio);
392
return NULL;
393
}
394
c->object = *pkio;
395
if (copyDER) {
396
nssItem_Create(c->object.arena, &c->encoding, derCert->len,
397
derCert->data);
398
} else {
399
NSSITEM_FROM_SECITEM(&c->encoding, derCert);
400
}
401
/* Forces a decoding of the cert in order to obtain the parts used
402
* below
403
*/
404
/* 'c' is not adopted here, if we fail loser frees what has been
405
* allocated so far for 'c' */
406
cc = STAN_GetCERTCertificate(c);
407
if (!cc) {
408
CERT_MapStanError();
409
goto loser;
410
}
411
nssItem_Create(c->object.arena, &c->issuer, cc->derIssuer.len,
412
cc->derIssuer.data);
413
nssItem_Create(c->object.arena, &c->subject, cc->derSubject.len,
414
cc->derSubject.data);
415
/* CERTCertificate stores serial numbers decoded. I need the DER
416
* here. sigh.
417
*/
418
SECItem derSerial = { 0 };
419
CERT_SerialNumberFromDERCert(&cc->derCert, &derSerial);
420
if (!derSerial.data)
421
goto loser;
422
nssItem_Create(c->object.arena, &c->serial, derSerial.len,
423
derSerial.data);
424
PORT_Free(derSerial.data);
425
426
if (nickname) {
427
c->object.tempName =
428
nssUTF8_Create(c->object.arena, nssStringType_UTF8String,
429
(NSSUTF8 *)nickname, PORT_Strlen(nickname));
430
}
431
if (cc->emailAddr && cc->emailAddr[0]) {
432
c->email = nssUTF8_Create(
433
c->object.arena, nssStringType_PrintableString,
434
(NSSUTF8 *)cc->emailAddr, PORT_Strlen(cc->emailAddr));
435
}
436
437
tempCert = NSSCryptoContext_FindOrImportCertificate(gCC, c);
438
if (!tempCert) {
439
CERT_MapStanError();
440
goto loser;
441
}
442
/* destroy our copy */
443
NSSCertificate_Destroy(c);
444
/* and use the stored entry */
445
c = tempCert;
446
cc = STAN_GetCERTCertificateOrRelease(c);
447
if (!cc) {
448
/* STAN_GetCERTCertificateOrRelease destroys c on failure. */
449
CERT_MapStanError();
450
return NULL;
451
}
452
453
CERT_LockCertTempPerm(cc);
454
cc->istemp = PR_TRUE;
455
cc->isperm = PR_FALSE;
456
CERT_UnlockCertTempPerm(cc);
457
return cc;
458
loser:
459
/* Perhaps this should be nssCertificate_Destroy(c) */
460
nssPKIObject_Destroy(&c->object);
461
return NULL;
462
}
463
464
/* This symbol is exported for backward compatibility. */
465
CERTCertificate *
466
__CERT_NewTempCertificate(CERTCertDBHandle *handle, SECItem *derCert,
467
char *nickname, PRBool isperm, PRBool copyDER)
468
{
469
return CERT_NewTempCertificate(handle, derCert, nickname, isperm, copyDER);
470
}
471
472
static CERTCertificate *
473
common_FindCertByIssuerAndSN(CERTCertDBHandle *handle,
474
CERTIssuerAndSN *issuerAndSN,
475
void *wincx)
476
{
477
PK11SlotInfo *slot;
478
CERTCertificate *cert;
479
480
cert = PK11_FindCertByIssuerAndSN(&slot, issuerAndSN, wincx);
481
if (cert && slot) {
482
PK11_FreeSlot(slot);
483
}
484
485
return cert;
486
}
487
488
/* maybe all the wincx's should be some const for internal token login? */
489
CERTCertificate *
490
CERT_FindCertByIssuerAndSN(CERTCertDBHandle *handle,
491
CERTIssuerAndSN *issuerAndSN)
492
{
493
return common_FindCertByIssuerAndSN(handle, issuerAndSN, NULL);
494
}
495
496
/* maybe all the wincx's should be some const for internal token login? */
497
CERTCertificate *
498
CERT_FindCertByIssuerAndSNCX(CERTCertDBHandle *handle,
499
CERTIssuerAndSN *issuerAndSN,
500
void *wincx)
501
{
502
return common_FindCertByIssuerAndSN(handle, issuerAndSN, wincx);
503
}
504
505
static NSSCertificate *
506
get_best_temp_or_perm(NSSCertificate *ct, NSSCertificate *cp)
507
{
508
NSSUsage usage;
509
NSSCertificate *arr[3];
510
if (!ct) {
511
return nssCertificate_AddRef(cp);
512
} else if (!cp) {
513
return nssCertificate_AddRef(ct);
514
}
515
arr[0] = ct;
516
arr[1] = cp;
517
arr[2] = NULL;
518
usage.anyUsage = PR_TRUE;
519
return nssCertificateArray_FindBestCertificate(arr, NULL, &usage, NULL);
520
}
521
522
CERTCertificate *
523
CERT_FindCertByName(CERTCertDBHandle *handle, SECItem *name)
524
{
525
NSSCertificate *cp, *ct, *c;
526
NSSDER subject;
527
NSSUsage usage;
528
NSSCryptoContext *cc;
529
NSSITEM_FROM_SECITEM(&subject, name);
530
usage.anyUsage = PR_TRUE;
531
cc = STAN_GetDefaultCryptoContext();
532
ct = NSSCryptoContext_FindBestCertificateBySubject(cc, &subject, NULL,
533
&usage, NULL);
534
cp = NSSTrustDomain_FindBestCertificateBySubject(handle, &subject, NULL,
535
&usage, NULL);
536
c = get_best_temp_or_perm(ct, cp);
537
if (ct) {
538
CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(ct));
539
}
540
if (cp) {
541
CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(cp));
542
}
543
return c ? STAN_GetCERTCertificateOrRelease(c) : NULL;
544
}
545
546
CERTCertificate *
547
CERT_FindCertByKeyID(CERTCertDBHandle *handle, SECItem *name, SECItem *keyID)
548
{
549
CERTCertList *list;
550
CERTCertificate *cert = NULL;
551
CERTCertListNode *node;
552
553
list = CERT_CreateSubjectCertList(NULL, handle, name, 0, PR_FALSE);
554
if (list == NULL)
555
return NULL;
556
557
node = CERT_LIST_HEAD(list);
558
while (!CERT_LIST_END(node, list)) {
559
if (node->cert &&
560
SECITEM_ItemsAreEqual(&node->cert->subjectKeyID, keyID)) {
561
cert = CERT_DupCertificate(node->cert);
562
goto done;
563
}
564
node = CERT_LIST_NEXT(node);
565
}
566
PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
567
568
done:
569
CERT_DestroyCertList(list);
570
return cert;
571
}
572
573
CERTCertificate *
574
CERT_FindCertByNickname(CERTCertDBHandle *handle, const char *nickname)
575
{
576
NSSCryptoContext *cc;
577
NSSCertificate *c, *ct;
578
CERTCertificate *cert;
579
NSSUsage usage;
580
usage.anyUsage = PR_TRUE;
581
cc = STAN_GetDefaultCryptoContext();
582
ct = NSSCryptoContext_FindBestCertificateByNickname(cc, nickname, NULL,
583
&usage, NULL);
584
cert = PK11_FindCertFromNickname(nickname, NULL);
585
c = NULL;
586
if (cert) {
587
c = get_best_temp_or_perm(ct, STAN_GetNSSCertificate(cert));
588
CERT_DestroyCertificate(cert);
589
if (ct) {
590
CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(ct));
591
}
592
} else {
593
c = ct;
594
}
595
return c ? STAN_GetCERTCertificateOrRelease(c) : NULL;
596
}
597
598
CERTCertificate *
599
CERT_FindCertByDERCert(CERTCertDBHandle *handle, SECItem *derCert)
600
{
601
NSSCryptoContext *cc;
602
NSSCertificate *c;
603
NSSDER encoding;
604
NSSITEM_FROM_SECITEM(&encoding, derCert);
605
cc = STAN_GetDefaultCryptoContext();
606
c = NSSCryptoContext_FindCertificateByEncodedCertificate(cc, &encoding);
607
if (!c) {
608
c = NSSTrustDomain_FindCertificateByEncodedCertificate(handle,
609
&encoding);
610
if (!c)
611
return NULL;
612
}
613
return STAN_GetCERTCertificateOrRelease(c);
614
}
615
616
static CERTCertificate *
617
common_FindCertByNicknameOrEmailAddrForUsage(CERTCertDBHandle *handle,
618
const char *name, PRBool anyUsage,
619
SECCertUsage lookingForUsage,
620
void *wincx)
621
{
622
NSSCryptoContext *cc;
623
NSSCertificate *c, *ct;
624
CERTCertificate *cert = NULL;
625
NSSUsage usage;
626
CERTCertList *certlist;
627
628
if (NULL == name) {
629
PORT_SetError(SEC_ERROR_INVALID_ARGS);
630
return NULL;
631
}
632
633
usage.anyUsage = anyUsage;
634
635
if (!anyUsage) {
636
usage.nss3lookingForCA = PR_FALSE;
637
usage.nss3usage = lookingForUsage;
638
}
639
640
cc = STAN_GetDefaultCryptoContext();
641
ct = NSSCryptoContext_FindBestCertificateByNickname(cc, name, NULL, &usage,
642
NULL);
643
if (!ct && PORT_Strchr(name, '@') != NULL) {
644
char *lowercaseName = CERT_FixupEmailAddr(name);
645
if (lowercaseName) {
646
ct = NSSCryptoContext_FindBestCertificateByEmail(
647
cc, lowercaseName, NULL, &usage, NULL);
648
PORT_Free(lowercaseName);
649
}
650
}
651
652
if (anyUsage) {
653
cert = PK11_FindCertFromNickname(name, wincx);
654
} else {
655
if (ct) {
656
/* Does ct really have the required usage? */
657
nssDecodedCert *dc;
658
dc = nssCertificate_GetDecoding(ct);
659
if (!dc->matchUsage(dc, &usage)) {
660
CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(ct));
661
ct = NULL;
662
}
663
}
664
665
certlist = PK11_FindCertsFromNickname(name, wincx);
666
if (certlist) {
667
SECStatus rv =
668
CERT_FilterCertListByUsage(certlist, lookingForUsage, PR_FALSE);
669
if (SECSuccess == rv && !CERT_LIST_EMPTY(certlist)) {
670
cert = CERT_DupCertificate(CERT_LIST_HEAD(certlist)->cert);
671
}
672
CERT_DestroyCertList(certlist);
673
}
674
}
675
676
if (cert) {
677
c = get_best_temp_or_perm(ct, STAN_GetNSSCertificate(cert));
678
CERT_DestroyCertificate(cert);
679
if (ct) {
680
CERT_DestroyCertificate(STAN_GetCERTCertificateOrRelease(ct));
681
}
682
} else {
683
c = ct;
684
}
685
return c ? STAN_GetCERTCertificateOrRelease(c) : NULL;
686
}
687
688
CERTCertificate *
689
CERT_FindCertByNicknameOrEmailAddr(CERTCertDBHandle *handle, const char *name)
690
{
691
return common_FindCertByNicknameOrEmailAddrForUsage(handle, name, PR_TRUE,
692
0, NULL);
693
}
694
695
CERTCertificate *
696
CERT_FindCertByNicknameOrEmailAddrCX(CERTCertDBHandle *handle, const char *name,
697
void *wincx)
698
{
699
return common_FindCertByNicknameOrEmailAddrForUsage(handle, name, PR_TRUE,
700
0, wincx);
701
}
702
703
CERTCertificate *
704
CERT_FindCertByNicknameOrEmailAddrForUsage(CERTCertDBHandle *handle,
705
const char *name,
706
SECCertUsage lookingForUsage)
707
{
708
return common_FindCertByNicknameOrEmailAddrForUsage(handle, name, PR_FALSE,
709
lookingForUsage, NULL);
710
}
711
712
CERTCertificate *
713
CERT_FindCertByNicknameOrEmailAddrForUsageCX(CERTCertDBHandle *handle,
714
const char *name,
715
SECCertUsage lookingForUsage,
716
void *wincx)
717
{
718
return common_FindCertByNicknameOrEmailAddrForUsage(handle, name, PR_FALSE,
719
lookingForUsage, wincx);
720
}
721
722
static void
723
add_to_subject_list(CERTCertList *certList, CERTCertificate *cert,
724
PRBool validOnly, PRTime sorttime)
725
{
726
SECStatus secrv;
727
if (!validOnly ||
728
CERT_CheckCertValidTimes(cert, sorttime, PR_FALSE) ==
729
secCertTimeValid) {
730
secrv = CERT_AddCertToListSorted(certList, cert, CERT_SortCBValidity,
731
(void *)&sorttime);
732
if (secrv != SECSuccess) {
733
CERT_DestroyCertificate(cert);
734
}
735
} else {
736
CERT_DestroyCertificate(cert);
737
}
738
}
739
740
CERTCertList *
741
CERT_CreateSubjectCertList(CERTCertList *certList, CERTCertDBHandle *handle,
742
const SECItem *name, PRTime sorttime,
743
PRBool validOnly)
744
{
745
NSSCryptoContext *cc;
746
NSSCertificate **tSubjectCerts, **pSubjectCerts;
747
NSSCertificate **ci;
748
CERTCertificate *cert;
749
NSSDER subject;
750
PRBool myList = PR_FALSE;
751
cc = STAN_GetDefaultCryptoContext();
752
NSSITEM_FROM_SECITEM(&subject, name);
753
/* Collect both temp and perm certs for the subject */
754
tSubjectCerts =
755
NSSCryptoContext_FindCertificatesBySubject(cc, &subject, NULL, 0, NULL);
756
pSubjectCerts = NSSTrustDomain_FindCertificatesBySubject(handle, &subject,
757
NULL, 0, NULL);
758
if (!tSubjectCerts && !pSubjectCerts) {
759
return NULL;
760
}
761
if (certList == NULL) {
762
certList = CERT_NewCertList();
763
myList = PR_TRUE;
764
if (!certList)
765
goto loser;
766
}
767
/* Iterate over the matching temp certs. Add them to the list */
768
ci = tSubjectCerts;
769
while (ci && *ci) {
770
cert = STAN_GetCERTCertificateOrRelease(*ci);
771
/* *ci may be invalid at this point, don't reference it again */
772
if (cert) {
773
/* NOTE: add_to_subject_list adopts the incoming cert. */
774
add_to_subject_list(certList, cert, validOnly, sorttime);
775
}
776
ci++;
777
}
778
/* Iterate over the matching perm certs. Add them to the list */
779
ci = pSubjectCerts;
780
while (ci && *ci) {
781
cert = STAN_GetCERTCertificateOrRelease(*ci);
782
/* *ci may be invalid at this point, don't reference it again */
783
if (cert) {
784
/* NOTE: add_to_subject_list adopts the incoming cert. */
785
add_to_subject_list(certList, cert, validOnly, sorttime);
786
}
787
ci++;
788
}
789
/* all the references have been adopted or freed at this point, just
790
* free the arrays now */
791
nss_ZFreeIf(tSubjectCerts);
792
nss_ZFreeIf(pSubjectCerts);
793
return certList;
794
loser:
795
/* need to free the references in tSubjectCerts and pSubjectCerts! */
796
nssCertificateArray_Destroy(tSubjectCerts);
797
nssCertificateArray_Destroy(pSubjectCerts);
798
if (myList && certList != NULL) {
799
CERT_DestroyCertList(certList);
800
}
801
return NULL;
802
}
803
804
void
805
CERT_DestroyCertificate(CERTCertificate *cert)
806
{
807
if (cert) {
808
/* don't use STAN_GetNSSCertificate because we don't want to
809
* go to the trouble of translating the CERTCertificate into
810
* an NSSCertificate just to destroy it. If it hasn't been done
811
* yet, don't do it at all.
812
*/
813
NSSCertificate *tmp = cert->nssCertificate;
814
if (tmp) {
815
/* delete the NSSCertificate */
816
NSSCertificate_Destroy(tmp);
817
} else if (cert->arena) {
818
PORT_FreeArena(cert->arena, PR_FALSE);
819
}
820
}
821
return;
822
}
823
824
int
825
CERT_GetDBContentVersion(CERTCertDBHandle *handle)
826
{
827
/* should read the DB content version from the pkcs #11 device */
828
return 0;
829
}
830
831
SECStatus
832
certdb_SaveSingleProfile(CERTCertificate *cert, const char *emailAddr,
833
SECItem *emailProfile, SECItem *profileTime)
834
{
835
PRTime oldtime;
836
PRTime newtime;
837
SECStatus rv = SECFailure;
838
PRBool saveit;
839
SECItem oldprof, oldproftime;
840
SECItem *oldProfile = NULL;
841
SECItem *oldProfileTime = NULL;
842
PK11SlotInfo *slot = NULL;
843
NSSCertificate *c;
844
NSSCryptoContext *cc;
845
nssSMIMEProfile *stanProfile = NULL;
846
PRBool freeOldProfile = PR_FALSE;
847
848
c = STAN_GetNSSCertificate(cert);
849
if (!c)
850
return SECFailure;
851
cc = c->object.cryptoContext;
852
if (cc != NULL) {
853
stanProfile = nssCryptoContext_FindSMIMEProfileForCertificate(cc, c);
854
if (stanProfile) {
855
PORT_Assert(stanProfile->profileData);
856
SECITEM_FROM_NSSITEM(&oldprof, stanProfile->profileData);
857
oldProfile = &oldprof;
858
SECITEM_FROM_NSSITEM(&oldproftime, stanProfile->profileTime);
859
oldProfileTime = &oldproftime;
860
}
861
} else {
862
oldProfile = PK11_FindSMimeProfile(&slot, (char *)emailAddr,
863
&cert->derSubject, &oldProfileTime);
864
freeOldProfile = PR_TRUE;
865
}
866
867
saveit = PR_FALSE;
868
869
/* both profileTime and emailProfile have to exist or not exist */
870
if (emailProfile == NULL) {
871
profileTime = NULL;
872
} else if (profileTime == NULL) {
873
emailProfile = NULL;
874
}
875
876
if (oldProfileTime == NULL) {
877
saveit = PR_TRUE;
878
} else {
879
/* there was already a profile for this email addr */
880
if (profileTime) {
881
/* we have an old and new profile - save whichever is more recent*/
882
if (oldProfileTime->len == 0) {
883
/* always replace if old entry doesn't have a time */
884
oldtime = LL_MININT;
885
} else {
886
rv = DER_UTCTimeToTime(&oldtime, oldProfileTime);
887
if (rv != SECSuccess) {
888
goto loser;
889
}
890
}
891
892
rv = DER_UTCTimeToTime(&newtime, profileTime);
893
if (rv != SECSuccess) {
894
goto loser;
895
}
896
897
if (LL_CMP(newtime, >, oldtime)) {
898
/* this is a newer profile, save it and cert */
899
saveit = PR_TRUE;
900
}
901
} else {
902
saveit = PR_TRUE;
903
}
904
}
905
906
if (saveit) {
907
if (cc) {
908
if (stanProfile && profileTime && emailProfile) {
909
/* stanProfile is already stored in the crypto context,
910
* overwrite the data
911
*/
912
NSSArena *arena = stanProfile->object.arena;
913
stanProfile->profileTime = nssItem_Create(
914
arena, NULL, profileTime->len, profileTime->data);
915
stanProfile->profileData = nssItem_Create(
916
arena, NULL, emailProfile->len, emailProfile->data);
917
} else if (profileTime && emailProfile) {
918
PRStatus nssrv;
919
NSSItem profTime, profData;
920
NSSITEM_FROM_SECITEM(&profTime, profileTime);
921
NSSITEM_FROM_SECITEM(&profData, emailProfile);
922
stanProfile = nssSMIMEProfile_Create(c, &profTime, &profData);
923
if (!stanProfile)
924
goto loser;
925
nssrv = nssCryptoContext_ImportSMIMEProfile(cc, stanProfile);
926
rv = (nssrv == PR_SUCCESS) ? SECSuccess : SECFailure;
927
}
928
} else {
929
rv = PK11_SaveSMimeProfile(slot, (char *)emailAddr,
930
&cert->derSubject, emailProfile,
931
profileTime);
932
}
933
} else {
934
rv = SECSuccess;
935
}
936
937
loser:
938
if (oldProfile && freeOldProfile) {
939
SECITEM_FreeItem(oldProfile, PR_TRUE);
940
}
941
if (oldProfileTime && freeOldProfile) {
942
SECITEM_FreeItem(oldProfileTime, PR_TRUE);
943
}
944
if (stanProfile) {
945
nssSMIMEProfile_Destroy(stanProfile);
946
}
947
if (slot) {
948
PK11_FreeSlot(slot);
949
}
950
951
return (rv);
952
}
953
954
/*
955
*
956
* Manage S/MIME profiles
957
*
958
*/
959
960
SECStatus
961
CERT_SaveSMimeProfile(CERTCertificate *cert, SECItem *emailProfile,
962
SECItem *profileTime)
963
{
964
const char *emailAddr;
965
SECStatus rv;
966
PRBool isperm = PR_FALSE;
967
968
if (!cert) {
969
return SECFailure;
970
}
971
972
if (cert->slot && !PK11_IsInternal(cert->slot)) {
973
/* this cert comes from an external source, we need to add it
974
to the cert db before creating an S/MIME profile */
975
PK11SlotInfo *internalslot = PK11_GetInternalKeySlot();
976
if (!internalslot) {
977
return SECFailure;
978
}
979
rv = PK11_ImportCert(internalslot, cert, CK_INVALID_HANDLE, NULL,
980
PR_FALSE);
981
982
PK11_FreeSlot(internalslot);
983
if (rv != SECSuccess) {
984
return SECFailure;
985
}
986
}
987
988
rv = CERT_GetCertIsPerm(cert, &isperm);
989
if (rv != SECSuccess) {
990
return SECFailure;
991
}
992
if (cert->slot && isperm && CERT_IsUserCert(cert) &&
993
(!emailProfile || !emailProfile->len)) {
994
/* Don't clobber emailProfile for user certs. */
995
return SECSuccess;
996
}
997
998
for (emailAddr = CERT_GetFirstEmailAddress(cert); emailAddr != NULL;
999
emailAddr = CERT_GetNextEmailAddress(cert, emailAddr)) {
1000
rv = certdb_SaveSingleProfile(cert, emailAddr, emailProfile,
1001
profileTime);
1002
if (rv != SECSuccess) {
1003
return SECFailure;
1004
}
1005
}
1006
return SECSuccess;
1007
}
1008
1009
SECItem *
1010
CERT_FindSMimeProfile(CERTCertificate *cert)
1011
{
1012
PK11SlotInfo *slot = NULL;
1013
NSSCertificate *c;
1014
NSSCryptoContext *cc;
1015
SECItem *rvItem = NULL;
1016
1017
if (!cert || !cert->emailAddr || !cert->emailAddr[0]) {
1018
PORT_SetError(SEC_ERROR_INVALID_ARGS);
1019
return NULL;
1020
}
1021
c = STAN_GetNSSCertificate(cert);
1022
if (!c)
1023
return NULL;
1024
cc = c->object.cryptoContext;
1025
if (cc != NULL) {
1026
nssSMIMEProfile *stanProfile;
1027
stanProfile = nssCryptoContext_FindSMIMEProfileForCertificate(cc, c);
1028
if (stanProfile) {
1029
rvItem =
1030
SECITEM_AllocItem(NULL, NULL, stanProfile->profileData->size);
1031
if (rvItem) {
1032
rvItem->data = stanProfile->profileData->data;
1033
}
1034
nssSMIMEProfile_Destroy(stanProfile);
1035
}
1036
return rvItem;
1037
}
1038
rvItem =
1039
PK11_FindSMimeProfile(&slot, cert->emailAddr, &cert->derSubject, NULL);
1040
if (slot) {
1041
PK11_FreeSlot(slot);
1042
}
1043
return rvItem;
1044
}
1045
1046
SECStatus
1047
CERT_GetCertIsPerm(const CERTCertificate *cert, PRBool *isperm)
1048
{
1049
if (cert == NULL) {
1050
return SECFailure;
1051
}
1052
1053
CERT_LockCertTempPerm(cert);
1054
*isperm = cert->isperm;
1055
CERT_UnlockCertTempPerm(cert);
1056
return SECSuccess;
1057
}
1058
1059
SECStatus
1060
CERT_GetCertIsTemp(const CERTCertificate *cert, PRBool *istemp)
1061
{
1062
if (cert == NULL) {
1063
return SECFailure;
1064
}
1065
1066
CERT_LockCertTempPerm(cert);
1067
*istemp = cert->istemp;
1068
CERT_UnlockCertTempPerm(cert);
1069
return SECSuccess;
1070
}
1071
1072
/*
1073
* deprecated functions that are now just stubs.
1074
*/
1075
/*
1076
* Close the database
1077
*/
1078
void
1079
__CERT_ClosePermCertDB(CERTCertDBHandle *handle)
1080
{
1081
PORT_Assert("CERT_ClosePermCertDB is Deprecated" == NULL);
1082
return;
1083
}
1084
1085
SECStatus
1086
CERT_OpenCertDBFilename(CERTCertDBHandle *handle, char *certdbname,
1087
PRBool readOnly)
1088
{
1089
PORT_Assert("CERT_OpenCertDBFilename is Deprecated" == NULL);
1090
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
1091
return SECFailure;
1092
}
1093
1094
SECItem *
1095
SECKEY_HashPassword(char *pw, SECItem *salt)
1096
{
1097
PORT_Assert("SECKEY_HashPassword is Deprecated" == NULL);
1098
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
1099
return NULL;
1100
}
1101
1102
SECStatus
1103
__CERT_TraversePermCertsForSubject(CERTCertDBHandle *handle,
1104
SECItem *derSubject, void *cb, void *cbarg)
1105
{
1106
PORT_Assert("CERT_TraversePermCertsForSubject is Deprecated" == NULL);
1107
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
1108
return SECFailure;
1109
}
1110
1111
SECStatus
1112
__CERT_TraversePermCertsForNickname(CERTCertDBHandle *handle, char *nickname,
1113
void *cb, void *cbarg)
1114
{
1115
PORT_Assert("CERT_TraversePermCertsForNickname is Deprecated" == NULL);
1116
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
1117
return SECFailure;
1118
}