certdb.c

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

C
2,329
字号
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ *  * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. *  * The Original Code is the Netscape security libraries. *  * The Initial Developer of the Original Code is Netscape * Communications Corporation.  Portions created by Netscape are  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All * Rights Reserved. *  * Contributor(s): *  * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable  * instead of those above.  If you wish to allow use of your  * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL.  If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. *//* * Certificate handling code * * $Id: certdb.c,v 1.3 2000/09/06 22:10:06 relyea%netscape.com Exp $ */#include "prlock.h"#include "prmon.h"#include "prtime.h"#include "cert.h"#include "secder.h"#include "secoid.h"#include "secasn1.h"#include "blapi.h"		/* for SHA1_HashBuf */#include "genname.h"#include "keyhi.h"#include "secitem.h"#include "mcom_db.h"#include "certdb.h"#include "prprf.h"#include "sechash.h"#include "prlong.h"#include "certxutl.h"#include "portreg.h"#include "secerr.h"#include "sslerr.h"#include "nsslocks.h"#include "cdbhdl.h"/* * Certificate database handling code */const SEC_ASN1Template CERT_CertExtensionTemplate[] = {    { SEC_ASN1_SEQUENCE,	  0, NULL, sizeof(CERTCertExtension) },    { SEC_ASN1_OBJECT_ID,	  offsetof(CERTCertExtension,id) },    { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN,		/* XXX DER_DEFAULT */	  offsetof(CERTCertExtension,critical) },    { SEC_ASN1_OCTET_STRING,	  offsetof(CERTCertExtension,value) },    { 0, }};const SEC_ASN1Template CERT_SequenceOfCertExtensionTemplate[] = {    { SEC_ASN1_SEQUENCE_OF, 0, CERT_CertExtensionTemplate }};const SEC_ASN1Template CERT_CertificateTemplate[] = {    { SEC_ASN1_SEQUENCE,      0, NULL, sizeof(CERTCertificate) },    { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | 	  SEC_ASN1_CONTEXT_SPECIFIC | 0, 		/* XXX DER_DEFAULT */ 	  offsetof(CERTCertificate,version),	  SEC_IntegerTemplate },    { SEC_ASN1_INTEGER,	  offsetof(CERTCertificate,serialNumber) },    { SEC_ASN1_INLINE,	  offsetof(CERTCertificate,signature),	  SECOID_AlgorithmIDTemplate },    { SEC_ASN1_SAVE, 	  offsetof(CERTCertificate,derIssuer) },    { SEC_ASN1_INLINE,	  offsetof(CERTCertificate,issuer),	  CERT_NameTemplate },    { SEC_ASN1_INLINE,	  offsetof(CERTCertificate,validity),	  CERT_ValidityTemplate },    { SEC_ASN1_SAVE,	  offsetof(CERTCertificate,derSubject) },    { SEC_ASN1_INLINE,	  offsetof(CERTCertificate,subject),	  CERT_NameTemplate },    { SEC_ASN1_SAVE,	  offsetof(CERTCertificate,derPublicKey) },    { SEC_ASN1_INLINE,	  offsetof(CERTCertificate,subjectPublicKeyInfo),	  CERT_SubjectPublicKeyInfoTemplate },    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,	  offsetof(CERTCertificate,issuerID),	  SEC_ObjectIDTemplate },    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 2,	  offsetof(CERTCertificate,subjectID),	  SEC_ObjectIDTemplate },    { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | 	  SEC_ASN1_CONTEXT_SPECIFIC | 3,	  offsetof(CERTCertificate,extensions),	  CERT_SequenceOfCertExtensionTemplate },    { 0 }};const SEC_ASN1Template SEC_SignedCertificateTemplate[] ={    { SEC_ASN1_SEQUENCE,	  0, NULL, sizeof(CERTCertificate) },    { SEC_ASN1_SAVE, 	  offsetof(CERTCertificate,signatureWrap.data) },    { SEC_ASN1_INLINE, 	  0, CERT_CertificateTemplate },    { SEC_ASN1_INLINE,	  offsetof(CERTCertificate,signatureWrap.signatureAlgorithm),	  SECOID_AlgorithmIDTemplate },    { SEC_ASN1_BIT_STRING,	  offsetof(CERTCertificate,signatureWrap.signature) },    { 0 }};/* * Find the subjectName in a DER encoded certificate */const SEC_ASN1Template SEC_CertSubjectTemplate[] = {    { SEC_ASN1_SEQUENCE,	  0, NULL, sizeof(SECItem) },    { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | 	  SEC_ASN1_CONTEXT_SPECIFIC | 0,	  0, SEC_SkipTemplate },	/* version */    { SEC_ASN1_SKIP },		/* serial number */    { SEC_ASN1_SKIP },		/* signature algorithm */    { SEC_ASN1_SKIP },		/* issuer */    { SEC_ASN1_SKIP },		/* validity */    { SEC_ASN1_ANY, 0, NULL },		/* subject */    { SEC_ASN1_SKIP_REST },    { 0 }};/* * Find the issuerName in a DER encoded certificate */const SEC_ASN1Template SEC_CertIssuerTemplate[] = {    { SEC_ASN1_SEQUENCE,	  0, NULL, sizeof(SECItem) },    { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | 	  SEC_ASN1_CONTEXT_SPECIFIC | 0,	  0, SEC_SkipTemplate },	/* version */    { SEC_ASN1_SKIP },		/* serial number */    { SEC_ASN1_SKIP },		/* signature algorithm */    { SEC_ASN1_ANY, 0, NULL },		/* issuer */    { SEC_ASN1_SKIP_REST },    { 0 }};/* * Find the subjectName in a DER encoded certificate */const SEC_ASN1Template SEC_CertSerialNumberTemplate[] = {    { SEC_ASN1_SEQUENCE,	  0, NULL, sizeof(SECItem) },    { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | 	  SEC_ASN1_CONTEXT_SPECIFIC | 0,	  0, SEC_SkipTemplate },	/* version */    { SEC_ASN1_ANY, 0, NULL }, /* serial number */    { SEC_ASN1_SKIP_REST },    { 0 }};/* * Find the issuer and serialNumber in a DER encoded certificate. * This data is used as the database lookup key since its the unique * identifier of a certificate. */const SEC_ASN1Template CERT_CertKeyTemplate[] = {    { SEC_ASN1_SEQUENCE,	  0, NULL, sizeof(CERTCertKey) },    { SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | 	  SEC_ASN1_CONTEXT_SPECIFIC | 0,	  0, SEC_SkipTemplate },	/* version */     { SEC_ASN1_INTEGER,	  offsetof(CERTCertKey,serialNumber) },    { SEC_ASN1_SKIP },		/* signature algorithm */    { SEC_ASN1_ANY,	  offsetof(CERTCertKey,derIssuer) },    { SEC_ASN1_SKIP_REST },    { 0 }};SECStatusCERT_KeyFromIssuerAndSN(PRArenaPool *arena, SECItem *issuer, SECItem *sn,			SECItem *key){    key->len = sn->len + issuer->len;        key->data = (unsigned char*)PORT_ArenaAlloc(arena, key->len);    if ( !key->data ) {	goto loser;    }    /* copy the serialNumber */    PORT_Memcpy(key->data, sn->data, sn->len);    /* copy the issuer */    PORT_Memcpy(&key->data[sn->len], issuer->data, issuer->len);    return(SECSuccess);loser:    return(SECFailure);}/* * Extract the subject name from a DER certificate */SECStatusCERT_NameFromDERCert(SECItem *derCert, SECItem *derName){    int rv;    PRArenaPool *arena;    CERTSignedData sd;    void *tmpptr;        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);        if ( ! arena ) {	return(SECFailure);    }       PORT_Memset(&sd, 0, sizeof(CERTSignedData));    rv = SEC_ASN1DecodeItem(arena, &sd, CERT_SignedDataTemplate, derCert);        if ( rv ) {	goto loser;    }        PORT_Memset(derName, 0, sizeof(SECItem));    rv = SEC_ASN1DecodeItem(arena, derName, SEC_CertSubjectTemplate, &sd.data);    if ( rv ) {	goto loser;    }    tmpptr = derName->data;    derName->data = (unsigned char*)PORT_Alloc(derName->len);    if ( derName->data == NULL ) {	goto loser;    }        PORT_Memcpy(derName->data, tmpptr, derName->len);        PORT_FreeArena(arena, PR_FALSE);    return(SECSuccess);loser:    PORT_FreeArena(arena, PR_FALSE);    return(SECFailure);}SECStatusCERT_IssuerNameFromDERCert(SECItem *derCert, SECItem *derName){    int rv;    PRArenaPool *arena;    CERTSignedData sd;    void *tmpptr;        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);        if ( ! arena ) {	return(SECFailure);    }       PORT_Memset(&sd, 0, sizeof(CERTSignedData));    rv = SEC_ASN1DecodeItem(arena, &sd, CERT_SignedDataTemplate, derCert);        if ( rv ) {	goto loser;    }        PORT_Memset(derName, 0, sizeof(SECItem));    rv = SEC_ASN1DecodeItem(arena, derName, SEC_CertIssuerTemplate, &sd.data);    if ( rv ) {	goto loser;    }    tmpptr = derName->data;    derName->data = (unsigned char*)PORT_Alloc(derName->len);    if ( derName->data == NULL ) {	goto loser;    }        PORT_Memcpy(derName->data, tmpptr, derName->len);        PORT_FreeArena(arena, PR_FALSE);    return(SECSuccess);loser:    PORT_FreeArena(arena, PR_FALSE);    return(SECFailure);}SECStatusCERT_SerialNumberFromDERCert(SECItem *derCert, SECItem *derName){    int rv;    PRArenaPool *arena;    CERTSignedData sd;    void *tmpptr;        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);        if ( ! arena ) {	return(SECFailure);    }       PORT_Memset(&sd, 0, sizeof(CERTSignedData));    rv = SEC_ASN1DecodeItem(arena, &sd, CERT_SignedDataTemplate, derCert);        if ( rv ) {	goto loser;    }        PORT_Memset(derName, 0, sizeof(SECItem));    rv = SEC_ASN1DecodeItem(arena, derName, SEC_CertSerialNumberTemplate, &sd.data);    if ( rv ) {	goto loser;    }    tmpptr = derName->data;    derName->data = (unsigned char*)PORT_Alloc(derName->len);    if ( derName->data == NULL ) {	goto loser;    }        PORT_Memcpy(derName->data, tmpptr, derName->len);        PORT_FreeArena(arena, PR_FALSE);    return(SECSuccess);loser:    PORT_FreeArena(arena, PR_FALSE);    return(SECFailure);}/* * Generate a database key, based on serial number and issuer, from a * DER certificate. */SECStatusCERT_KeyFromDERCert(PRArenaPool *arena, SECItem *derCert, SECItem *key){    int rv;    CERTSignedData sd;    CERTCertKey certkey;    PORT_Memset(&sd, 0, sizeof(CERTSignedData));        PORT_Memset(&certkey, 0, sizeof(CERTCertKey));        PORT_Memset(&sd, 0, sizeof(CERTSignedData));    rv = SEC_ASN1DecodeItem(arena, &sd, CERT_SignedDataTemplate, derCert);        if ( rv ) {	goto loser;    }        PORT_Memset(&certkey, 0, sizeof(CERTCertKey));    rv = SEC_ASN1DecodeItem(arena, &certkey, CERT_CertKeyTemplate, &sd.data);    if ( rv ) {	goto loser;    }    return(CERT_KeyFromIssuerAndSN(arena, &certkey.derIssuer,				   &certkey.serialNumber, key));loser:    return(SECFailure);}/* * fill in keyUsage field of the cert based on the cert extension * if the extension is not critical, then we allow all uses */static SECStatusGetKeyUsage(CERTCertificate *cert){    SECStatus rv;    SECItem tmpitem;        rv = CERT_FindKeyUsageExtension(cert, &tmpitem);    if ( rv == SECSuccess ) {	/* remember the actual value of the extension */	cert->rawKeyUsage = tmpitem.data[0];	cert->keyUsagePresent = PR_TRUE;	cert->keyUsage = tmpitem.data[0];	PORT_Free(tmpitem.data);	tmpitem.data = NULL;	    } else {	/* if the extension is not present, then we allow all uses */	cert->keyUsage = KU_ALL;	cert->rawKeyUsage = KU_ALL;	cert->keyUsagePresent = PR_FALSE;    }    if ( CERT_GovtApprovedBitSet(cert) ) {	cert->keyUsage |= KU_NS_GOVT_APPROVED;	cert->rawKeyUsage |= KU_NS_GOVT_APPROVED;    }        return(SECSuccess);}/* * determine if a fortezza V1 Cert is a CA or not. */static PRBoolfortezzaIsCA( CERTCertificate *cert) {    PRBool isCA = PR_FALSE;    CERTSubjectPublicKeyInfo *spki = &cert->subjectPublicKeyInfo;    int tag;    tag = SECOID_GetAlgorithmTag(&spki->algorithm);    if ((tag == SEC_OID_MISSI_KEA_DSS_OLD) ||       (tag == SEC_OID_MISSI_KEA_DSS) ||       (tag == SEC_OID_MISSI_DSS_OLD) ||       (tag == SEC_OID_MISSI_DSS) ) {	SECItem rawkey;	unsigned char *rawptr;	unsigned char *end;	int len;        rawkey = spki->subjectPublicKey;	DER_ConvertBitString(&rawkey);	rawptr = rawkey.data;	end = rawkey.data + rawkey.len;	/* version */		rawptr += sizeof(((SECKEYPublicKey*)0)->u.fortezza.KMID)+2;	/* clearance (the string up to the first byte with the hi-bit on */	while ((rawptr < end) && (*rawptr++ & 0x80));	if (rawptr >= end) { return PR_FALSE; }	/* KEAPrivilege (the string up to the first byte with the hi-bit on */	while ((rawptr < end) && (*rawptr++ & 0x80));	if (rawptr >= end) { return PR_FALSE; }	/* skip the key */	len = (*rawptr << 8) | rawptr[1];	rawptr += 2 + len;	/* shared key */	if (rawptr >= end) { return PR_FALSE; }	/* DSS Version is next */	rawptr += 2;	/* DSSPrivilege (the string up to the first byte with the hi-bit on */	if (*rawptr & 0x30) isCA = PR_TRUE;           }   return isCA;}static SECStatusfindOIDinOIDSeqByTagNum(CERTOidSequence *seq, SECOidTag tagnum){    SECItem **oids;    SECItem *oid;    SECStatus rv = SECFailure;        if (seq != NULL) {	oids = seq->oids;	while (oids != NULL && *oids != NULL) {	    oid = *oids;	    if (SECOID_FindOIDTag(oid) == tagnum) {		rv = SECSuccess;		break;	    }	    oids++;	}    }    return rv;}/* * fill in nsCertType field of the cert based on the cert extension */SECStatusCERT_GetCertType(CERTCertificate *cert){    SECStatus rv;    SECItem tmpitem;    SECItem encodedExtKeyUsage;    CERTOidSequence *extKeyUsage = NULL;    PRBool basicConstraintPresent = PR_FALSE;    CERTBasicConstraints basicConstraint;    tmpitem.data = NULL;    CERT_FindNSCertTypeExtension(cert, &tmpitem);    rv = CERT_FindCertExtension(cert, SEC_OID_X509_EXT_KEY_USAGE, 				&encodedExtKeyUsage);    if (rv == SECSuccess) {	extKeyUsage = CERT_DecodeOidSequence(&encodedExtKeyUsage);    }    rv = CERT_FindBasicConstraintExten(cert, &basicConstraint);    if (rv == SECSuccess) {	basicConstraintPresent = PR_TRUE;    }    if (tmpitem.data != NULL || extKeyUsage != NULL) {	if (tmpitem.data == NULL) {	    cert->nsCertType = 0;	} else {	    cert->nsCertType = tmpitem.data[0];	}	/* free tmpitem data pointer to avoid memory leak */	PORT_Free(tmpitem.data);	tmpitem.data = NULL;		/*	 * for this release, we will allow SSL certs with an email address	 * to be used for email	 */	if ( ( cert->nsCertType & NS_CERT_TYPE_SSL_CLIENT ) &&	    cert->emailAddr ) {	    cert->nsCertType |= NS_CERT_TYPE_EMAIL;	}	/*	 * for this release, we will allow SSL intermediate CAs to be	 * email intermediate CAs too.	 */	if ( cert->nsCertType & NS_CERT_TYPE_SSL_CA ) {	    cert->nsCertType |= NS_CERT_TYPE_EMAIL_CA;	}	/*	 * allow a cert with the extended key usage of EMail Protect	 * to be used for email or as an email CA, if basic constraints	 * indicates that it is a CA.	 */	if (findOIDinOIDSeqByTagNum(extKeyUsage, 				    SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT) ==	    SECSuccess) {	    if (basicConstraintPresent == PR_TRUE &&		(basicConstraint.isCA)) {		cert->nsCertType |= NS_CERT_TYPE_EMAIL_CA;	    } else {		cert->nsCertType |= NS_CERT_TYPE_EMAIL;	    }	}	if (findOIDinOIDSeqByTagNum(extKeyUsage, 				    SEC_OID_EXT_KEY_USAGE_SERVER_AUTH) ==	    SECSuccess){	    if (basicConstraintPresent == PR_TRUE &&		(basicConstraint.isCA)) {		cert->nsCertType |= NS_CERT_TYPE_SSL_CA;

⌨️ 快捷键说明

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