certdb.c

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

C
2,329
字号
	goto loser;    }    /*     * Open the memory resident decoded cert database.     */    handle->tempCertDB = dbopen( 0, O_RDWR | O_CREAT, 0600, DB_HASH, 0 );    if ( !handle->tempCertDB ) {	goto loser;    }    handle->dbMon = PR_NewMonitor();    PORT_Assert(handle->dbMon != NULL);    handle->spkDigestInfo = NULL;    handle->statusConfig = NULL;    /* initialize the cert database */    (void) CERT_InitCertDB(handle);    return (SECSuccess);    loser:    PORT_SetError(SEC_ERROR_BAD_DATABASE);    if ( handle->permCertDB ) {	(* handle->permCertDB->close)(handle->permCertDB);	handle->permCertDB = 0;    }    if ( handle->tempCertDB ) {	(* handle->tempCertDB->close)(handle->tempCertDB);	handle->tempCertDB = 0;    }    return(SECFailure);}/* XXX this would probably be okay/better as an xp routine? */static voidsec_lower_string(char *s){    if ( s == NULL ) {	return;    }        while ( *s ) {	*s = PORT_Tolower(*s);	s++;    }        return;}/*** Add a domain name to the list of names that the user has explicitly** allowed (despite cert name mismatches) for use with a server cert.*/SECStatusCERT_AddOKDomainName(CERTCertificate *cert, const char *hn){    CERTOKDomainName *domainOK;    int               newNameLen;    if (!hn || !(newNameLen = strlen(hn))) {    	PORT_SetError(SEC_ERROR_INVALID_ARGS);	return SECFailure;    }    domainOK = (CERTOKDomainName *)PORT_ArenaZAlloc(cert->arena,                                   (sizeof *domainOK) + newNameLen);    if (!domainOK)     	return SECFailure;	/* error code is already set. */    PORT_Strcpy(domainOK->name, hn);    sec_lower_string(domainOK->name);    /* put at head of list. */    domainOK->next = cert->domainOK;    cert->domainOK = domainOK;    return SECSuccess;}/* Make sure that the name of the host we are connecting to matches the * name that is incoded in the common-name component of the certificate * that they are using. */SECStatusCERT_VerifyCertName(CERTCertificate *cert, const char *hn){    char *    cn;    char *    domain;    char *    hndomain;    char *    hostname;    int       regvalid;    int       match;    SECStatus rv;    CERTOKDomainName *domainOK;    if (!hn || !strlen(hn)) {    	PORT_SetError(SEC_ERROR_INVALID_ARGS);	return SECFailure;    }    hostname = PORT_Strdup(hn);    if ( hostname == NULL ) {	return(SECFailure);    }    sec_lower_string(hostname);    /* if the name is one that the user has already approved, it's OK. */    for (domainOK = cert->domainOK; domainOK; domainOK = domainOK->next) {	if (0 == PORT_Strcmp(hostname, domainOK->name)) {	    PORT_Free(hostname);	    return SECSuccess;    	}    }    /* try the cert extension first, then the common name */    cn = CERT_FindNSStringExtension(cert, SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME);    if ( cn == NULL ) {	cn = CERT_GetCommonName(&cert->subject);    }        sec_lower_string(cn);    if ( cn ) {	if ( ( hndomain = PORT_Strchr(hostname, '.') ) == NULL ) {	    /* No domain in server name */	    if ( ( domain = PORT_Strchr(cn, '.') ) != NULL ) {		/* there is a domain in the cn string, so chop it off */		*domain = '\0';	    }	}	regvalid = PORT_RegExpValid(cn);		if ( regvalid == NON_SXP ) {	    /* compare entire hostname with cert name */	    if ( PORT_Strcmp(hostname, cn) == 0 ) {		rv = SECSuccess;		goto done;	    }	    	    if ( hndomain ) {		/* compare just domain name with cert name */		if ( PORT_Strcmp(hndomain+1, cn) == 0 ) {		    rv = SECSuccess;		    goto done;		}	    }	    PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);	    rv = SECFailure;	    goto done;	    	} else {	    /* try to match the shexp */	    match = PORT_RegExpCaseSearch(hostname, cn);	    if ( match == 0 ) {		rv = SECSuccess;	    } else {		PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);		rv = SECFailure;	    }	    goto done;	}    }    PORT_SetError(SEC_ERROR_NO_MEMORY);    rv = SECFailure;done:    /* free the common name */    if ( cn ) {	PORT_Free(cn);    }        if ( hostname ) {	PORT_Free(hostname);    }        return(rv);}PRBoolCERT_CompareCerts(CERTCertificate *c1, CERTCertificate *c2){    SECComparison comp;        comp = SECITEM_CompareItem(&c1->derCert, &c2->derCert);    if ( comp == SECEqual ) { /* certs are the same */	return(PR_TRUE);    } else {	return(PR_FALSE);    }}static SECStatusStringsEqual(char *s1, char *s2) {    if ( ( s1 == NULL ) || ( s2 == NULL ) ) {	if ( s1 != s2 ) { /* only one is null */	    return(SECFailure);	}	return(SECSuccess); /* both are null */    }	    if ( PORT_Strcmp( s1, s2 ) != 0 ) {	return(SECFailure); /* not equal */    }    return(SECSuccess); /* strings are equal */}PRBoolCERT_CompareCertsForRedirection(CERTCertificate *c1, CERTCertificate *c2){    SECComparison comp;    char *c1str, *c2str;    SECStatus eq;        comp = SECITEM_CompareItem(&c1->derCert, &c2->derCert);    if ( comp == SECEqual ) { /* certs are the same */	return(PR_TRUE);    }	    /* check if they are issued by the same CA */    comp = SECITEM_CompareItem(&c1->derIssuer, &c2->derIssuer);    if ( comp != SECEqual ) { /* different issuer */	return(PR_FALSE);    }    /* check country name */    c1str = CERT_GetCountryName(&c1->subject);    c2str = CERT_GetCountryName(&c2->subject);    eq = StringsEqual(c1str, c2str);    PORT_Free(c1str);    PORT_Free(c2str);    if ( eq != SECSuccess ) {	return(PR_FALSE);    }    /* check locality name */    c1str = CERT_GetLocalityName(&c1->subject);    c2str = CERT_GetLocalityName(&c2->subject);    eq = StringsEqual(c1str, c2str);    PORT_Free(c1str);    PORT_Free(c2str);    if ( eq != SECSuccess ) {	return(PR_FALSE);    }	    /* check state name */    c1str = CERT_GetStateName(&c1->subject);    c2str = CERT_GetStateName(&c2->subject);    eq = StringsEqual(c1str, c2str);    PORT_Free(c1str);    PORT_Free(c2str);    if ( eq != SECSuccess ) {	return(PR_FALSE);    }    /* check org name */    c1str = CERT_GetOrgName(&c1->subject);    c2str = CERT_GetOrgName(&c2->subject);    eq = StringsEqual(c1str, c2str);    PORT_Free(c1str);    PORT_Free(c2str);    if ( eq != SECSuccess ) {	return(PR_FALSE);    }#ifdef NOTDEF	    /* check orgUnit name */    /*     * We need to revisit this and decide which fields should be allowed to be     * different     */    c1str = CERT_GetOrgUnitName(&c1->subject);    c2str = CERT_GetOrgUnitName(&c2->subject);    eq = StringsEqual(c1str, c2str);    PORT_Free(c1str);    PORT_Free(c2str);    if ( eq != SECSuccess ) {	return(PR_FALSE);    }#endif    return(PR_TRUE); /* all fields but common name are the same */}/* CERT_CertChainFromCert and CERT_DestroyCertificateList moved   to certhigh.c */CERTIssuerAndSN *CERT_GetCertIssuerAndSN(PRArenaPool *arena, CERTCertificate *cert){    CERTIssuerAndSN *result;    SECStatus rv;    if ( arena == NULL ) {	arena = cert->arena;    }        result = (CERTIssuerAndSN*)PORT_ArenaZAlloc(arena, sizeof(*result));    if (result == NULL) {	PORT_SetError (SEC_ERROR_NO_MEMORY);	return NULL;    }    rv = SECITEM_CopyItem(arena, &result->derIssuer, &cert->derIssuer);    if (rv != SECSuccess)	return NULL;    rv = CERT_CopyName(arena, &result->issuer, &cert->issuer);    if (rv != SECSuccess)	return NULL;    rv = SECITEM_CopyItem(arena, &result->serialNumber, &cert->serialNumber);    if (rv != SECSuccess)	return NULL;    return result;}char *CERT_MakeCANickname(CERTCertificate *cert){    char *firstname = NULL;    char *org = NULL;    char *nickname = NULL;    int count;    CERTCertificate *dummycert;    CERTCertDBHandle *handle;        handle = cert->dbhandle;        nickname = CERT_GetNickName(cert, handle, cert->arena);    if (nickname == NULL) {	firstname = CERT_GetCommonName(&cert->subject);	if ( firstname == NULL ) {	    firstname = CERT_GetOrgUnitName(&cert->subject);	}	org = CERT_GetOrgName(&cert->issuer);	if ( org == NULL ) {	    goto loser;	}    	count = 1;	while ( 1 ) {	    if ( firstname ) {		if ( count == 1 ) {		    nickname = PR_smprintf("%s - %s", firstname, org);		} else {		    nickname = PR_smprintf("%s - %s #%d", firstname, org, count);		}	    } else {		if ( count == 1 ) {		    nickname = PR_smprintf("%s", org);		} else {		    nickname = PR_smprintf("%s #%d", org, count);		}	    }	    if ( nickname == NULL ) {		goto loser;	    }	    /* look up the nickname to make sure it isn't in use already */	    dummycert = CERT_FindCertByNickname(handle, nickname);	    if ( dummycert == NULL ) {		goto done;	    }		    /* found a cert, destroy it and loop */	    CERT_DestroyCertificate(dummycert);	    /* free the nickname */	    PORT_Free(nickname);	    count++;	}    }loser:    if ( nickname ) {	PORT_Free(nickname);    }    nickname = "";    done:    if ( firstname ) {	PORT_Free(firstname);    }    if ( org ) {	PORT_Free(org);    }        return(nickname);}/* CERT_Import_CAChain moved to certhigh.c */voidCERT_DestroyCrl (CERTSignedCrl *crl){    SEC_DestroyCrl (crl);}/* * Does a cert belong to a CA?  We decide based on perm database trust * flags, Netscape Cert Type Extension, and KeyUsage Extension. */PRBoolCERT_IsCACert(CERTCertificate *cert, unsigned int *rettype){    CERTCertTrust *trust;    SECStatus rv;    unsigned int type;    PRBool ret;    ret = PR_FALSE;    type = 0;        if ( cert->isperm ) {	trust = cert->trust;	if ( ( trust->sslFlags & CERTDB_VALID_CA ) == CERTDB_VALID_CA ) {	    ret = PR_TRUE;	    type |= NS_CERT_TYPE_SSL_CA;	}		if ( ( trust->emailFlags & CERTDB_VALID_CA ) == CERTDB_VALID_CA ) {	    ret = PR_TRUE;	    type |= NS_CERT_TYPE_EMAIL_CA;	}		if ( ( trust->objectSigningFlags & CERTDB_VALID_CA ) ==	    CERTDB_VALID_CA ) {	    ret = PR_TRUE;	    type |= NS_CERT_TYPE_OBJECT_SIGNING_CA;	}    } else {	if ( cert->nsCertType &	    ( NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA |	     NS_CERT_TYPE_OBJECT_SIGNING_CA ) ) {	    ret = PR_TRUE;	    type = (cert->nsCertType & NS_CERT_TYPE_CA);	} else {	    CERTBasicConstraints constraints;	    rv = CERT_FindBasicConstraintExten(cert, &constraints);	    if ( rv == SECSuccess ) {		if ( constraints.isCA ) {		    ret = PR_TRUE;		    type = (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA);		}	    } 	} 	/* finally check if it's a FORTEZZA V1 CA */	if (ret == PR_FALSE) {	    if (fortezzaIsCA(cert)) {		ret = PR_TRUE;		type = (NS_CERT_TYPE_SSL_CA | NS_CERT_TYPE_EMAIL_CA);	    }	}    }    if ( rettype != NULL ) {	*rettype = type;    }        return(ret);}/* * is certa newer than certb?  If one is expired, pick the other one. */PRBoolCERT_IsNewer(CERTCertificate *certa, CERTCertificate *certb){    int64 notBeforeA, notAfterA, notBeforeB, notAfterB, now;    SECStatus rv;    PRBool newerbefore, newerafter;        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;    }        if ( newerbefore && newerafter ) {	return(PR_TRUE);    }        if ( ( !newerbefore ) && ( !newerafter ) ) {	return(PR_FALSE);    }    /* get current UTC time */    now = PR_Now();    if ( newerbefore ) {	/* cert A was issued after cert B, but expires sooner */	/* if A is expired, then pick B */	if ( LL_CMP(notAfterA, <, now ) ) {	    return(PR_FALSE);	}	return(PR_TRUE);    } else {	/* cert B was issued after cert A, but expires sooner */	/* if B is expired, then pick A */	if ( LL_CMP(notAfterB, <, now ) ) {	    return(PR_TRUE);	}	return(PR_FALSE);    }}voidCERT_DestroyCertArray(CERTCertificate **certs, unsigned int ncerts){    unsigned int i;        if ( certs ) {	for ( i = 0; i < ncerts; i++ ) {	    if ( certs[i] ) {		CERT_DestroyCertificate(certs[i]);	    }	}	PORT_Free(certs);    }        return;}char *CERT_FixupEmailAddr(char *emailAddr){    char *retaddr;    char *str;    if ( emailAddr == NULL ) {	return(NULL);    }        /* copy the string */    str = retaddr = PORT_Strdup(emailAddr);    if ( str == NULL ) {	return(NULL);    }        /* make it lower case */    while ( *str ) {	*str = tolower( *str );	str++;    }        return(retaddr);}/*

⌨️ 快捷键说明

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