certread.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 536 行

C
536
字号
/* * 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. */#include "cert.h"#include "secpkcs7.h"#include "base64.h"#include "secitem.h"#include "secder.h"#include "secasn1.h"#include "secoid.h"SECStatusSEC_ReadPKCS7Certs(SECItem *pkcs7Item, CERTImportCertificateFunc f, void *arg){    SEC_PKCS7ContentInfo *contentInfo = NULL;    SECStatus rv;    SECItem **certs;    int count;    contentInfo = SEC_PKCS7DecodeItem(pkcs7Item, NULL, NULL, NULL, NULL, NULL, 				      NULL, NULL);    if ( contentInfo == NULL ) {	goto loser;    }    if ( SEC_PKCS7ContentType (contentInfo) != SEC_OID_PKCS7_SIGNED_DATA ) {	goto loser;    }    certs = contentInfo->content.signedData->rawCerts;    if ( certs ) {	count = 0;		while ( *certs ) {	    count++;	    certs++;	}	rv = (* f)(arg, contentInfo->content.signedData->rawCerts, count);    }        rv = SECSuccess;        goto done;loser:    rv = SECFailure;    done:    if ( contentInfo ) {	SEC_PKCS7DestroyContentInfo(contentInfo);    }    return(rv);}const SEC_ASN1Template SEC_CertSequenceTemplate[] = {    { SEC_ASN1_SEQUENCE_OF,	  0, SECAnyTemplate }};SECStatusSEC_ReadCertSequence(SECItem *certsItem, CERTImportCertificateFunc f, void *arg){    SECStatus rv;    SECItem **certs;    int count;    SECItem **rawCerts = NULL;    PRArenaPool *arena;    SEC_PKCS7ContentInfo *contentInfo = NULL;    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);    if (arena == NULL) {	return SECFailure;    }    contentInfo = SEC_PKCS7DecodeItem(certsItem, NULL, NULL, NULL, NULL, NULL, 				      NULL, NULL);    if ( contentInfo == NULL ) {	goto loser;    }    if ( SEC_PKCS7ContentType (contentInfo) != SEC_OID_NS_TYPE_CERT_SEQUENCE ) {	goto loser;    }    rv = SEC_ASN1DecodeItem(arena, &rawCerts, SEC_CertSequenceTemplate,		    contentInfo->content.data);    if (rv != SECSuccess) {	goto loser;    }    certs = rawCerts;    if ( certs ) {	count = 0;		while ( *certs ) {	    count++;	    certs++;	}	rv = (* f)(arg, rawCerts, count);    }        rv = SECSuccess;        goto done;loser:    rv = SECFailure;    done:    if ( contentInfo ) {	SEC_PKCS7DestroyContentInfo(contentInfo);    }    if ( arena ) {	PORT_FreeArena(arena, PR_FALSE);    }        return(rv);}CERTCertificate *CERT_ConvertAndDecodeCertificate(char *certstr){    CERTCertificate *cert;    SECStatus rv;    SECItem der;    rv = ATOB_ConvertAsciiToItem(&der, certstr);    if (rv != SECSuccess)	return NULL;    cert = CERT_DecodeDERCertificate(&der, PR_TRUE, NULL);    PORT_Free(der.data);    return cert;}#define NS_CERT_HEADER "-----BEGIN CERTIFICATE-----"#define NS_CERT_TRAILER "-----END CERTIFICATE-----"#define CERTIFICATE_TYPE_STRING "certificate"#define CERTIFICATE_TYPE_LEN (sizeof(CERTIFICATE_TYPE_STRING)-1)CERTPackageTypeCERT_CertPackageType(SECItem *package, SECItem *certitem){    unsigned char *cp;    int seqLen, seqLenLen;    SECItem oiditem;    SECOidData *oiddata;    CERTPackageType type = certPackageNone;        cp = package->data;    /* is a DER encoded certificate of some type? */    if ( ( *cp  & 0x1f ) == SEC_ASN1_SEQUENCE ) {	cp++;		if ( *cp & 0x80) {	    /* Multibyte length */	    seqLenLen = cp[0] & 0x7f;	    	    switch (seqLenLen) {	      case 4:		seqLen = ((unsigned long)cp[1]<<24) |		    ((unsigned long)cp[2]<<16) | (cp[3]<<8) | cp[4];		break;	      case 3:		seqLen = ((unsigned long)cp[1]<<16) | (cp[2]<<8) | cp[3];		break;	      case 2:		seqLen = (cp[1]<<8) | cp[2];		break;	      case 1:		seqLen = cp[1];		break;	      default:		/* indefinite length */		seqLen = 0;	    }	    cp += ( seqLenLen + 1 );	} else {	    seqLenLen = 0;	    seqLen = *cp;	    cp++;	}	/* check entire length if definite length */	if ( seqLen || seqLenLen ) {	    if ( package->len != ( seqLen + seqLenLen + 2 ) ) {		/* not a DER package */		return(type);	    }	}		/* check the type string */	/* netscape wrapped DER cert */	if ( ( cp[0] == SEC_ASN1_OCTET_STRING ) &&	    ( cp[1] == CERTIFICATE_TYPE_LEN ) &&	    ( PORT_Strcmp((char *)&cp[2], CERTIFICATE_TYPE_STRING) ) ) {	    	    cp += ( CERTIFICATE_TYPE_LEN + 2 );	    /* it had better be a certificate by now!! */	    if ( certitem ) {		certitem->data = cp;		certitem->len = package->len -		    ( cp - (unsigned char *)package->data );	    }	    type = certPackageNSCertWrap;	    	} else if ( cp[0] == SEC_ASN1_OBJECT_ID ) {	    /* XXX - assume DER encoding of OID len!! */	    oiditem.len = cp[1];	    oiditem.data = (unsigned char *)&cp[2];	    oiddata = SECOID_FindOID(&oiditem);	    if ( oiddata == NULL ) {		/* failure */		return(type);	    }	    if ( certitem ) {		certitem->data = package->data;		certitem->len = package->len;	    }	    	    switch ( oiddata->offset ) {	      case SEC_OID_PKCS7_SIGNED_DATA:		type = certPackagePKCS7;		break;	      case SEC_OID_NS_TYPE_CERT_SEQUENCE:		type = certPackageNSCertSeq;		break;	      default:		break;	    }	    	} else {	    /* it had better be a certificate by now!! */	    if ( certitem ) {		certitem->data = package->data;		certitem->len = package->len;	    }	    	    type = certPackageCert;	}    }    return(type);}/* * read an old style ascii or binary certificate chain */SECStatusCERT_DecodeCertPackage(char *certbuf,		       int certlen,		       CERTImportCertificateFunc f,		       void *arg){    unsigned char *cp;    int seqLen, seqLenLen;    int cl;    unsigned char *bincert = NULL, *certbegin = NULL, *certend = NULL;    unsigned int binLen;    char *ascCert = NULL;    int asciilen;    CERTCertificate *cert;    SECItem certitem, oiditem;    SECStatus rv;    SECOidData *oiddata;    SECItem *pcertitem = &certitem;        if ( certbuf == NULL ) {	return(SECFailure);    }        cert = 0;    cp = (unsigned char *)certbuf;    /* is a DER encoded certificate of some type? */    if ( ( *cp  & 0x1f ) == SEC_ASN1_SEQUENCE ) {	cp++;		if ( *cp & 0x80) {	    /* Multibyte length */	    seqLenLen = cp[0] & 0x7f;	    	    switch (seqLenLen) {	      case 4:		seqLen = ((unsigned long)cp[1]<<24) |		    ((unsigned long)cp[2]<<16) | (cp[3]<<8) | cp[4];		break;	      case 3:		seqLen = ((unsigned long)cp[1]<<16) | (cp[2]<<8) | cp[3];		break;	      case 2:		seqLen = (cp[1]<<8) | cp[2];		break;	      case 1:		seqLen = cp[1];		break;	      default:		/* indefinite length */		seqLen = 0;	    }	    cp += ( seqLenLen + 1 );	} else {	    seqLenLen = 0;	    seqLen = *cp;	    cp++;	}	/* check entire length if definite length */	if ( seqLen || seqLenLen ) {	    if ( certlen != ( seqLen + seqLenLen + 2 ) ) {		goto notder;	    }	}		/* check the type string */	/* netscape wrapped DER cert */	if ( ( cp[0] == SEC_ASN1_OCTET_STRING ) &&	    ( cp[1] == CERTIFICATE_TYPE_LEN ) &&	    ( PORT_Strcmp((char *)&cp[2], CERTIFICATE_TYPE_STRING) ) ) {	    	    cp += ( CERTIFICATE_TYPE_LEN + 2 );	    /* it had better be a certificate by now!! */	    certitem.data = cp;	    certitem.len = certlen - ( cp - (unsigned char *)certbuf );	    	    rv = (* f)(arg, &pcertitem, 1);	    	    return(rv);	} else if ( cp[0] == SEC_ASN1_OBJECT_ID ) {	    /* XXX - assume DER encoding of OID len!! */	    oiditem.len = cp[1];	    oiditem.data = (unsigned char *)&cp[2];	    oiddata = SECOID_FindOID(&oiditem);	    if ( oiddata == NULL ) {		return(SECFailure);	    }	    certitem.data = (unsigned char*)certbuf;	    certitem.len = certlen;	    	    switch ( oiddata->offset ) {	      case SEC_OID_PKCS7_SIGNED_DATA:		return(SEC_ReadPKCS7Certs(&certitem, f, arg));		break;	      case SEC_OID_NS_TYPE_CERT_SEQUENCE:		return(SEC_ReadCertSequence(&certitem, f, arg));		break;	      default:		break;	    }	    	} else {	    /* it had better be a certificate by now!! */	    certitem.data = (unsigned char*)certbuf;	    certitem.len = certlen;	    	    rv = (* f)(arg, &pcertitem, 1);	    return(rv);	}    }    /* now look for a netscape base64 ascii encoded cert */notder:    cp = (unsigned char *)certbuf;    cl = certlen;    certbegin = 0;    certend = 0;    /* find the beginning marker */    while ( cl > sizeof(NS_CERT_HEADER) ) {	if ( !PORT_Strncasecmp((char *)cp, NS_CERT_HEADER,			     sizeof(NS_CERT_HEADER)-1) ) {	    cp = cp + sizeof(NS_CERT_HEADER);	    certbegin = cp;	    break;	}		/* skip to next eol */	do {	    cp++;	    cl--;	} while ( ( *cp != '\n') && cl );	/* skip all blank lines */	while ( ( *cp == '\n') && cl ) {	    cp++;	    cl--;	}    }    if ( certbegin ) {	/* find the ending marker */	while ( cl > sizeof(NS_CERT_TRAILER) ) {	    if ( !PORT_Strncasecmp((char *)cp, NS_CERT_TRAILER,				 sizeof(NS_CERT_TRAILER)-1) ) {		certend = (unsigned char *)cp;		break;	    }	    /* skip to next eol */	    do {		cp++;		cl--;	    } while ( ( *cp != '\n') && cl );	    /* skip all blank lines */	    while ( ( *cp == '\n') && cl ) {		cp++;		cl--;	    }	}    }    if ( certbegin && certend ) {	/* Convert the ASCII data into a nul-terminated string */	asciilen = certend - certbegin;	ascCert = (char *)PORT_Alloc(asciilen+1);	if (!ascCert) {	    rv = SECFailure;	    goto loser;	}	PORT_Memcpy(ascCert, certbegin, asciilen);	ascCert[asciilen] = '\0';		/* convert to binary */	bincert = ATOB_AsciiToData(ascCert, &binLen);	if (!bincert) {	    rv = SECFailure;	    goto loser;	}	/* now recurse to decode the binary */	rv = CERT_DecodeCertPackage((char *)bincert, binLen, f, arg);	    } else {	rv = SECFailure;    }loser:    if ( bincert ) {	PORT_Free(bincert);    }    if ( ascCert ) {	PORT_Free(ascCert);    }    return(rv);}typedef struct {    PRArenaPool *arena;    SECItem cert;} collect_args;static SECStatuscollect_certs(void *arg, SECItem **certs, int numcerts){    SECStatus rv;    collect_args *collectArgs;        collectArgs = (collect_args *)arg;        rv = SECITEM_CopyItem(collectArgs->arena, &collectArgs->cert, *certs);    return(rv);}/* * read an old style ascii or binary certificate */CERTCertificate *CERT_DecodeCertFromPackage(char *certbuf, int certlen){    collect_args collectArgs;    SECStatus rv;    CERTCertificate *cert = NULL;        collectArgs.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);        rv = CERT_DecodeCertPackage(certbuf, certlen, collect_certs,				(void *)&collectArgs);    if ( rv == SECSuccess ) {	cert = CERT_DecodeDERCertificate(&collectArgs.cert, PR_TRUE, NULL);    }        PORT_FreeArena(collectArgs.arena, PR_FALSE);        return(cert);}

⌨️ 快捷键说明

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