certdb.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 2,329 行 · 第 1/4 页

C
2,329
字号
 * NOTE - don't allow encode of govt-approved or invisible bits */SECStatusCERT_DecodeTrustString(CERTCertTrust *trust, char *trusts){    int i;    unsigned int *pflags;        trust->sslFlags = 0;    trust->emailFlags = 0;    trust->objectSigningFlags = 0;    pflags = &trust->sslFlags;        for (i=0; i < PORT_Strlen(trusts); i++) {	switch (trusts[i]) {	  case 'p':	      *pflags = *pflags | CERTDB_VALID_PEER;	      break;	  case 'P':	      *pflags = *pflags | CERTDB_TRUSTED | CERTDB_VALID_PEER;	      break;	  case 'w':	      *pflags = *pflags | CERTDB_SEND_WARN;	      break;	  case 'c':	      *pflags = *pflags | CERTDB_VALID_CA;	      break;	  case 'T':	      *pflags = *pflags | CERTDB_TRUSTED_CLIENT_CA | CERTDB_VALID_CA;	      break;	  case 'C' :	      *pflags = *pflags | CERTDB_TRUSTED_CA | CERTDB_VALID_CA;	      break;	  case 'u':	      *pflags = *pflags | CERTDB_USER;	      break;#ifdef DEBUG_NSSTEAM_ONLY	  case 'i':	      *pflags = *pflags | CERTDB_INVISIBLE_CA;	      break;	  case 'g':	      *pflags = *pflags | CERTDB_GOVT_APPROVED_CA;	      break;#endif /* DEBUG_NSSTEAM_ONLY */	  case ',':	      if ( pflags == &trust->sslFlags ) {		  pflags = &trust->emailFlags;	      } else {		  pflags = &trust->objectSigningFlags;	      }	      break;	  default:	      return SECFailure;	}    }    return SECSuccess;}static voidEncodeFlags(char *trusts, unsigned int flags){    if (flags & CERTDB_VALID_CA)	if (!(flags & CERTDB_TRUSTED_CA) &&	    !(flags & CERTDB_TRUSTED_CLIENT_CA))	    PORT_Strcat(trusts, "c");    if (flags & CERTDB_VALID_PEER)	if (!(flags & CERTDB_TRUSTED))	    PORT_Strcat(trusts, "p");    if (flags & CERTDB_TRUSTED_CA)	PORT_Strcat(trusts, "C");    if (flags & CERTDB_TRUSTED_CLIENT_CA)	PORT_Strcat(trusts, "T");    if (flags & CERTDB_TRUSTED)	PORT_Strcat(trusts, "P");    if (flags & CERTDB_USER)	PORT_Strcat(trusts, "u");    if (flags & CERTDB_SEND_WARN)	PORT_Strcat(trusts, "w");    if (flags & CERTDB_INVISIBLE_CA)	PORT_Strcat(trusts, "I");    if (flags & CERTDB_GOVT_APPROVED_CA)	PORT_Strcat(trusts, "G");    return;}char *CERT_EncodeTrustString(CERTCertTrust *trust){    char tmpTrustSSL[32];    char tmpTrustEmail[32];    char tmpTrustSigning[32];    char *retstr = NULL;    if ( trust ) {	tmpTrustSSL[0] = '\0';	tmpTrustEmail[0] = '\0';	tmpTrustSigning[0] = '\0';    	EncodeFlags(tmpTrustSSL, trust->sslFlags);	EncodeFlags(tmpTrustEmail, trust->emailFlags);	EncodeFlags(tmpTrustSigning, trust->objectSigningFlags);    	retstr = PR_smprintf("%s,%s,%s", tmpTrustSSL, tmpTrustEmail,			     tmpTrustSigning);    }        return(retstr);}SECStatusCERT_ImportCerts(CERTCertDBHandle *certdb, SECCertUsage usage,		 unsigned int ncerts, SECItem **derCerts,		 CERTCertificate ***retCerts, PRBool keepCerts,		 PRBool caOnly, char *nickname){    int i;    CERTCertificate **certs = NULL;    SECStatus rv;    int fcerts;    if ( ncerts ) {	certs = (CERTCertificate**)PORT_ZAlloc(sizeof(CERTCertificate *) * ncerts );	if ( certs == NULL ) {	    return(SECFailure);	}    	/* decode all of the certs into the temporary DB */	for ( i = 0, fcerts= 0; i < ncerts; i++) {	    certs[fcerts] = CERT_NewTempCertificate(certdb, derCerts[i], NULL,					       PR_FALSE, PR_TRUE);	    if (certs[fcerts]) fcerts++;	}	if ( keepCerts ) {	    for ( i = 0; i < fcerts; i++ ) {		SECKEY_UpdateCertPQG(certs[i]);		if(CERT_IsCACert(certs[i], NULL) && (fcerts > 1)) {		    /* if we are importing only a single cert and specifying		     * a nickname, we want to use that nickname if it a CA,		     * otherwise if there are more than one cert, we don't		     * know which cert it belongs to.		     */		    rv = CERT_SaveImportedCert(certs[i], usage, caOnly, NULL);		} else {		    rv = CERT_SaveImportedCert(certs[i], usage, caOnly,                 			       nickname);		}		/* don't care if it fails - keep going */	    }	}    }    if ( retCerts ) {	*retCerts = certs;    } else {	CERT_DestroyCertArray(certs, fcerts);    }    return(SECSuccess);    #if 0	/* dead code here - why ?? XXX */loser:    if ( retCerts ) {	*retCerts = NULL;    }    if ( certs ) {	CERT_DestroyCertArray(certs, ncerts);    }        return(SECFailure);#endif}/* * a real list of certificates - need to convert CERTCertificateList * stuff and ASN 1 encoder/decoder over to using this... */CERTCertList *CERT_NewCertList(void){    PRArenaPool *arena = NULL;    CERTCertList *ret = NULL;        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);    if ( arena == NULL ) {	goto loser;    }        ret = (CERTCertList *)PORT_ArenaZAlloc(arena, sizeof(CERTCertList));    if ( ret == NULL ) {	goto loser;    }        ret->arena = arena;        PR_INIT_CLIST(&ret->list);        return(ret);loser:    if ( arena != NULL ) {	PORT_FreeArena(arena, PR_FALSE);    }        return(NULL);}voidCERT_DestroyCertList(CERTCertList *certs){    PRCList *node;    while( !PR_CLIST_IS_EMPTY(&certs->list) ) {	node = PR_LIST_HEAD(&certs->list);	CERT_DestroyCertificate(((CERTCertListNode *)node)->cert);	PR_REMOVE_LINK(node);    }        PORT_FreeArena(certs->arena, PR_FALSE);        return;}voidCERT_RemoveCertListNode(CERTCertListNode *node){    CERT_DestroyCertificate(node->cert);    PR_REMOVE_LINK(&node->links);    return;}SECStatusCERT_AddCertToListTail(CERTCertList *certs, CERTCertificate *cert){    CERTCertListNode *node;        node = (CERTCertListNode *)PORT_ArenaZAlloc(certs->arena,						sizeof(CERTCertListNode));    if ( node == NULL ) {	goto loser;    }        PR_INSERT_BEFORE(&node->links, &certs->list);    /* certs->count++; */    node->cert = cert;    return(SECSuccess);    loser:    return(SECFailure);}/* * Sort callback function to determine if cert a is newer than cert b. * Not valid certs are considered older than valid certs. */PRBoolCERT_SortCBValidity(CERTCertificate *certa,		    CERTCertificate *certb,		    void *arg){    int64 sorttime;    int64 notBeforeA, notAfterA, notBeforeB, notAfterB;    SECStatus rv;    PRBool newerbefore, newerafter;    PRBool aNotValid = PR_FALSE, bNotValid = PR_FALSE;    sorttime = *(int64 *)arg;        rv = CERT_GetCertTimes(certa, &notBeforeA, &notAfterA);    if ( rv != SECSuccess ) {	return(PR_FALSE);    }        rv = CERT_GetCertTimes(certb, &notBeforeB, &notAfterB);    if ( rv != SECSuccess ) {	return(PR_TRUE);    }    newerbefore = PR_FALSE;    if ( LL_CMP(notBeforeA, >, notBeforeB) ) {	newerbefore = PR_TRUE;    }    newerafter = PR_FALSE;    if ( LL_CMP(notAfterA, >, notAfterB) ) {	newerafter = PR_TRUE;    }    /* check if A is valid at sorttime */    if ( CERT_CheckCertValidTimes(certa, sorttime, PR_FALSE)	!= secCertTimeValid ) {	aNotValid = PR_TRUE;    }    /* check if B is valid at sorttime */    if ( CERT_CheckCertValidTimes(certb, sorttime, PR_FALSE)	!= secCertTimeValid ) {	bNotValid = PR_TRUE;    }    /* a is valid, b is not */    if ( bNotValid && ( ! aNotValid ) ) {	return(PR_TRUE);    }    /* b is valid, a is not */    if ( aNotValid && ( ! bNotValid ) ) {	return(PR_FALSE);    }        /* a and b are either valid or not valid */    if ( newerbefore && newerafter ) {	return(PR_TRUE);    }        if ( ( !newerbefore ) && ( !newerafter ) ) {	return(PR_FALSE);    }    if ( newerbefore ) {	/* cert A was issued after cert B, but expires sooner */	return(PR_TRUE);    } else {	/* cert B was issued after cert A, but expires sooner */	return(PR_FALSE);    }}SECStatusCERT_AddCertToListSorted(CERTCertList *certs,			 CERTCertificate *cert,			 CERTSortCallback f,			 void *arg){    CERTCertListNode *node;    CERTCertListNode *head;    PRBool ret;        node = (CERTCertListNode *)PORT_ArenaZAlloc(certs->arena,						sizeof(CERTCertListNode));    if ( node == NULL ) {	goto loser;    }        head = CERT_LIST_HEAD(certs);        while ( !CERT_LIST_END(head, certs) ) {	/* if cert is already in the list, then don't add it again */	if ( cert == head->cert ) {	    /*XXX*/	    /* don't keep a reference */	    CERT_DestroyCertificate(cert);	    goto done;	}		ret = (* f)(cert, head->cert, arg);	/* if sort function succeeds, then insert before current node */	if ( ret ) {	    PR_INSERT_BEFORE(&node->links, &head->links);	    goto done;	}	head = CERT_LIST_NEXT(head);    }    /* if we get to the end, then just insert it at the tail */    PR_INSERT_BEFORE(&node->links, &certs->list);done:        /* certs->count++; */    node->cert = cert;    return(SECSuccess);    loser:    return(SECFailure);}/* This routine is here because pcertdb.c still has a call to it. * The SMIME profile code in pcertdb.c should be split into high (find * the email cert) and low (store the profile) code.  At that point, we * can move this to certhigh.c where it belongs. * * remove certs from a list that don't have keyUsage and certType * that match the given usage. */SECStatusCERT_FilterCertListByUsage(CERTCertList *certList, SECCertUsage usage,			   PRBool ca){    unsigned int requiredKeyUsage;    unsigned int requiredCertType;    CERTCertListNode *node, *savenode;    PRBool bad;    SECStatus rv;    unsigned int certType;    PRBool dummyret;        if (certList == NULL) goto loser;    rv = CERT_KeyUsageAndTypeForCertUsage(usage, ca, &requiredKeyUsage,					  &requiredCertType);    if ( rv != SECSuccess ) {	goto loser;    }    node = CERT_LIST_HEAD(certList);	    while ( !CERT_LIST_END(node, certList) ) {	bad = PR_FALSE;	/* bad key usage */	if ( CERT_CheckKeyUsage(node->cert, requiredKeyUsage )	    != SECSuccess ) {	    bad = PR_TRUE;	}	/* bad cert type */	if ( ca ) {	    /* This function returns a more comprehensive cert type that	     * takes trust flags into consideration.  Should probably	     * fix the cert decoding code to do this.	     */	    dummyret = CERT_IsCACert(node->cert, &certType);	} else {	    certType = node->cert->nsCertType;	}		if ( ! ( certType & requiredCertType ) ) {	    bad = PR_TRUE;	}	if ( bad ) {	    /* remove the node if it is bad */	    savenode = CERT_LIST_NEXT(node);	    CERT_RemoveCertListNode(node);	    node = savenode;	} else {	    node = CERT_LIST_NEXT(node);	}    }    return(SECSuccess);    loser:    return(SECFailure);}/* * Acquire the global lock on the cert database. * This lock is currently used for the following operations: *	adding or deleting a cert to either the temp or perm databases *	converting a temp to perm or perm to temp *	changing(maybe just adding????) the trust of a cert *      chaning the DB status checking Configuration */voidCERT_LockDB(CERTCertDBHandle *handle){    PR_EnterMonitor(handle->dbMon);    return;}/* * Free the global cert database lock. */voidCERT_UnlockDB(CERTCertDBHandle *handle){    PRStatus prstat;        prstat = PR_ExitMonitor(handle->dbMon);        PORT_Assert(prstat == PR_SUCCESS);        return;}static PRLock *certRefCountLock = NULL;/* * Acquire the cert reference count lock * There is currently one global lock for all certs, but I'm putting a cert * arg here so that it will be easy to make it per-cert in the future if * that turns out to be necessary. */voidCERT_LockCertRefCount(CERTCertificate *cert){    if ( certRefCountLock == NULL ) {	nss_InitLock(&certRefCountLock);	PORT_Assert(certRefCountLock != NULL);    }        PR_Lock(certRefCountLock);    return;}/* * Free the cert reference count lock */voidCERT_UnlockCertRefCount(CERTCertificate *cert){    PRStatus prstat;    PORT_Assert(certRefCountLock != NULL);        prstat = PR_Unlock(certRefCountLock);        PORT_Assert(prstat == PR_SUCCESS);    return;}static PRLock *certTrustLock = NULL;/* * Acquire the cert trust lock * There is currently one global lock for all certs, but I'm putting a cert * arg here so that it will be easy to make it per-cert in the future if * that turns out to be necessary. */voidCERT_LockCertTrust(CERTCertificate *cert){    if ( certTrustLock == NULL ) {	nss_InitLock(&certTrustLock);	PORT_Assert(certTrustLock != NULL);    }        PR_Lock(certTrustLock);    return;}/* * Free the cert trust lock */voidCERT_UnlockCertTrust(CERTCertificate *cert){    PRStatus prstat;    PORT_Assert(certTrustLock != NULL);        prstat = PR_Unlock(certTrustLock);        PORT_Assert(prstat == PR_SUCCESS);    return;}/* * Get the StatusConfig data for this handle */CERTStatusConfig *CERT_GetStatusConfig(CERTCertDBHandle *handle){  return handle->statusConfig;}/* * Set the StatusConfig data for this handle.  There * should not be another configuration set. */voidCERT_SetStatusConfig(CERTCertDBHandle *handle, CERTStatusConfig *statusConfig){  PORT_Assert(handle->statusConfig == NULL);  handle->statusConfig = statusConfig;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?