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, ¬BeforeA, ¬AfterA); if ( rv != SECSuccess ) { return(PR_FALSE); } rv = CERT_GetCertTimes(certb, ¬BeforeB, ¬AfterB); 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 + -
显示快捷键?