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 + -
显示快捷键?