security/nss/lib/certdb/stanpcertdb.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial