⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 x509.c

📁 PeerSec Networks MatrixSSL?is an embedded SSL implementation designed for small footprint applicatio
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 *	x509.c
 *	Release $Name: MATRIXSSL_1_7_3_OPEN $
 *
 *	DER/BER coding
 */
/*
 *	Copyright (c) PeerSec Networks, 2002-2005. All Rights Reserved.
 *	The latest version of this code is available at http://www.matrixssl.org
 *
 *	This software is open source; you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License as published by
 *	the Free Software Foundation; either version 2 of the License, or
 *	(at your option) any later version.
 *
 *	This General Public License does NOT permit incorporating this software 
 *	into proprietary programs.  If you are unable to comply with the GPL, a 
 *	commercial license for this software may be purchased from PeerSec Networks
 *	at http://www.peersec.com
 *	
 *	This program is distributed in WITHOUT ANY WARRANTY; without even the 
 *	implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 *	See the GNU General Public License for more details.
 *	
 *	You should have received a copy of the GNU General Public License
 *	along with this program; if not, write to the Free Software
 *	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *	http://www.gnu.org/copyleft/gpl.html
 */
/******************************************************************************/

#include "pkiInternal.h"

/*
	X509 is wrapped in USE_RSA until more key types are added
*/
#ifdef USE_RSA
#ifdef USE_X509

#define IMPLICIT_ISSUER_ID		1
#define IMPLICIT_SUBJECT_ID		2
#define EXPLICIT_EXTENSION		3

#define OID_SHA1				88
#define OID_MD2					646
#define OID_MD5					649

/*
	Certificate extension hash mappings
*/
#define EXT_BASIC_CONSTRAINTS	1
#define	EXT_KEY_USAGE			2
#define EXT_SUBJ_KEY_ID			3
#define EXT_AUTH_KEY_ID			4
#define EXT_ALT_SUBJECT_NAME	5

static const struct {
		unsigned char	hash[16];
		int32			id;
} extTable[] = {
	{ { 0xa5, 0xc4, 0x5e, 0x9a, 0xa3, 0xbb, 0x71, 0x2f, 0x07,
		0xf7, 0x4c, 0xd0, 0xcd, 0x95, 0x65, 0xda }, EXT_BASIC_CONSTRAINTS },
	{ { 0xf5, 0xab, 0x88, 0x49, 0xc4, 0xfd, 0xa2, 0x64, 0x6d,
		0x06, 0xa2, 0x3e, 0x83, 0x9b, 0xef, 0xbb }, EXT_KEY_USAGE },
	{ { 0x91, 0x54, 0x28, 0xcc, 0x81, 0x59, 0x8c, 0x71, 0x8c,
		0x53, 0xa8, 0x4d, 0xeb, 0xd3, 0xc2, 0x18 }, EXT_SUBJ_KEY_ID },
	{ { 0x48, 0x2d, 0xff, 0x49, 0xf7, 0xab, 0x93, 0xe8, 0x1f,
		0x57, 0xb5, 0xaf, 0x7f, 0xaa, 0x31, 0xbb }, EXT_AUTH_KEY_ID },
	{ { 0x5c, 0x70, 0xcb, 0xf5, 0xa4, 0x07, 0x5a, 0xcc, 0xd1,
		0x55, 0xd2, 0x44, 0xdd, 0x62, 0x2c, 0x0c }, EXT_ALT_SUBJECT_NAME },
	{ { 0 }, -1 } /* Must be last for proper termination */
};


#define MAX_CHAIN_LENGTH		8

static int32 getExplicitExtensions(psPool_t *pool, unsigned char **pp, 
								 int32 len, int32 expVal,
								 v3extensions_t *extensions);
static int32 parseList(psPool_t *pool, char *list, const char *sep,
					   char **item);
static int32 readCertChain(psPool_t *pool, char *certFiles, sslKeys_t *lkeys);
static int32 matrixX509ValidateCertInternal(psPool_t *pool, 
						sslRsaCert_t *subjectCert, 
						sslRsaCert_t *issuerCert, int32 chain);

/******************************************************************************/
/*
	Read in the certificate and private keys from the given files
	If privPass is non-NULL, it will be used to decode an encrypted private
	key file.

	The certificate is stored internally as a pointer to DER encoded X.509
	The private key is stored in a crypto provider specific structure
*/
#ifdef USE_FILE_SYSTEM
int32 matrixRsaReadKeys(sslKeys_t **keys, char *certFile, char *privFile,
					  char *privPass, char *trustedCAFiles)
{
	return matrixRsaReadKeysEx(PEERSEC_BASE_POOL, keys, certFile, privFile,
		privPass, trustedCAFiles);
}
#else /* USE_FILE_SYSTEM */
int32 matrixRsaReadKeys(sslKeys_t **keys, char *certFile, char *privFile,
					 char *privPass, char *trustedCAFile)
{
	matrixStrDebugMsg("Error: Calling matrixRsaReadKeys against a library " \
					  "built without USE_FILE_SYSTEM defined\n", NULL);
	return -1;
}
#endif /* USE_FILE_SYSTEM */

/******************************************************************************/
/*
	In memory version of matrixRsaReadKeys.  The buffers are the ASN.1 raw
	stream (ie. not base64 PEM encoded)

	API CHANGE: 1.7 changed this protoype and buffer formats (ASN.1 now) but
	this function was never properly	documented.  Users who may have found
	this function on their own and are using it will need to convert to this
	new	version.
*/
int32 matrixRsaReadKeysMem(sslKeys_t **keys, char *certBuf,
			int32 certLen, char *privBuf, int32 privLen, char *trustedCABuf,
			int32 trustedCALen)
{
	return matrixRsaParseKeysMem(PEERSEC_BASE_POOL, keys, certBuf, certLen,
		privBuf, privLen, trustedCABuf, trustedCALen);
}

/******************************************************************************/
/*
	Free private key and cert and zero memory allocated by matrixSslReadKeys.
*/
void matrixRsaFreeKeys(sslKeys_t *keys)
{
	sslLocalCert_t	*current, *next;
	int32			i = 0;

	if (keys) {
		current = &keys->cert;
		while (current) {
			if (current->certBin) {
				memset(current->certBin, 0x0, current->certLen);
				psFree(current->certBin);
			}
			if (current->privKey) {
				matrixRsaFreeKey(current->privKey);
			}
			next = current->next;
			if (i++ > 0) {
				psFree(current);
			}
			current = next;
		}
#ifdef USE_CLIENT_SIDE_SSL
		if (keys->caCerts) {
			matrixX509FreeCert(keys->caCerts);
		}
#endif /* USE_CLIENT_SIDE_SSL */
		psFree(keys);
	}
}

#ifdef USE_FILE_SYSTEM
/******************************************************************************/
/*
	Preferred version for commercial users who make use of memory pools.

	This use of the sslKeys_t param implies this is for use in the MatrixSSL
	product (input to matrixSslNewSession).  However, we didn't want to
	expose this API at the matrixSsl.h level due to the pool parameter. This
	is strictly an API that commerical users will have access to.  The result
	of this placement is that the matrixSslFreeKeys is not prototyped yet
	at compile time. The extern below is to prevent compiler warnings.
*/
int32 matrixRsaReadKeysEx(psPool_t *pool, sslKeys_t **keys, char *certFile,
				char *privFile, char *privPass, char *trustedCAFiles)
{
	sslKeys_t		*lkeys;
	char			*privKeyMem;
	int32			rc, privKeyMemLen;
#ifdef USE_CLIENT_SIDE_SSL
	sslRsaCert_t	*currCert, *prevCert = NULL;
	const char		sep[] = ";";
	unsigned char	*caCert;
	char			*caFile, *origList;
	int32			caCertLen, i;
#endif /* USE_CLIENT_SIDE_SSL */

	*keys = lkeys = psMalloc(pool, sizeof(sslKeys_t));
	if (lkeys == NULL) {
		return -8; /* SSL_MEM_ERROR */
	}
	memset(lkeys, 0x0, sizeof(sslKeys_t));
/*
	Load certificate files.  Any additional certificate files should chain
	to the root CA held on the other side.
*/
	rc = readCertChain(pool, certFile, lkeys);
	if (rc < 0 ) {
		matrixRsaFreeKeys(lkeys);
		return rc;
	}
/*
	The first cert in certFile must be associated with the provided
	private key. 
*/
	if (privFile) {
		rc = matrixRsaReadPrivKey(pool, privFile, privPass, &privKeyMem,
			&privKeyMemLen);
		if (rc < 0) {
			matrixStrDebugMsg("Error reading private key file: %s\n", privFile);
			matrixRsaFreeKeys(lkeys);
			return rc;
		}
		rc = matrixRsaParsePrivKey(pool, privKeyMem, privKeyMemLen,
			&lkeys->cert.privKey);
		if (rc < 0) {
			matrixStrDebugMsg("Error parsing private key file: %s\n", privFile);
			psFree(privKeyMem);
			matrixRsaFreeKeys(lkeys);
			return rc;
		}
		psFree(privKeyMem);
	}
/*
	Now deal with Certificate Authorities
*/
#ifdef USE_CLIENT_SIDE_SSL
	caFile = NULL;
	origList = trustedCAFiles;
	if (trustedCAFiles != NULL) {
		trustedCAFiles += parseList(pool, trustedCAFiles, sep, &caFile);
	}
	i = 0;
	while (caFile != NULL) {
		caCert = NULL;
		currCert = NULL;
		if (matrixX509ReadCert(pool, caFile, &caCert, &caCertLen) < 0 ||
				caCert == NULL) {
			matrixStrDebugMsg("Error reading CA cert file %s\n", caFile);
			psFree(caFile);
			trustedCAFiles += parseList(pool, trustedCAFiles, sep, &caFile);
			continue;
		}
		psFree(caFile);
		if (matrixX509ParseCert(pool, caCert, caCertLen,
				&currCert) < 0) {
			matrixStrDebugMsg("Error parsing CA cert %s\n", caFile);
			psFree(caCert);
			trustedCAFiles += parseList(pool, trustedCAFiles, sep, &caFile);
			continue;
		}
		psFree(caCert);
		if (i++ == 0) {
			lkeys->caCerts = currCert;
		} else {
			prevCert->next = currCert;
		}
		prevCert = currCert;
		currCert = NULL;
		trustedCAFiles += parseList(pool, trustedCAFiles, sep, &caFile);
	}
/*
	Check to see that if a set of CAs were passed in at least
	one ended up being valid.
*/
	if (trustedCAFiles != NULL && lkeys->caCerts == NULL) {
		matrixStrDebugMsg("No valid CA certs in %s\n", trustedCAFiles);
		matrixRsaFreeKeys(lkeys);
		return -1;
	}
#endif /* USE_CLIENT_SIDE_SSL */
	return 0; 
}

/******************************************************************************/
/*
 *	Public API to return a binary buffer from a cert.  Suitable to send
 *	over the wire.  Caller must free 'out' if this function returns success (0)
 *	Parse .pem files according to http://www.faqs.org/rfcs/rfc1421.html
 *	FUTURE - Support multiple certificates in a single file.
 *	FUTURE SECURITY - Make parsing of pem format more robust!
 */
int32 matrixX509ReadCert(psPool_t *pool, char *fileName, unsigned char **out,
						int32 *outLen)
{
	int32			certLen[MAX_CHAIN_LENGTH], certBufLen, rc, certChainLen, i;
	char			*oneCert[MAX_CHAIN_LENGTH];
	char			*start, *end, *certFile, *tmp;
	const char		sep[] = ";";
	unsigned char	*certBuf;

/*
	For PKI product purposes, this routine now accepts a chain of certs.
*/
	if (fileName != NULL) {
		fileName += parseList(pool, fileName, sep, &certFile);
	} else {
		return 0;
	}
/*
	Init chain array
*/
	for (i=0; i < MAX_CHAIN_LENGTH; i++) {
		oneCert[i] = NULL;
	}
	certChainLen = i = 0;
	rc = -1;
	while (certFile != NULL) {
	
		if (i == MAX_CHAIN_LENGTH) {
			matrixIntDebugMsg("Exceeded maximum cert chain length of %d\n",
				MAX_CHAIN_LENGTH);
			psFree(certFile);
			goto err;
		}
		if ((rc = psGetFileBin(pool, certFile, &certBuf, &certBufLen)) < 0) {
			matrixStrDebugMsg("Couldn't open file %s\n", certFile);
			goto err;
		}
		psFree(certFile);

		if (((start = strstr(certBuf, "-----BEGIN")) != NULL) && 
			((start = strstr(certBuf, "CERTIFICATE-----")) != NULL) &&
			(end = strstr(start, "-----END")) != NULL) {
			start += strlen("CERTIFICATE-----");
			certLen[i] = (int32)(end - start);
		} else {
			psFree(certBuf);
			goto err;
		}
		oneCert[i] = psMalloc(pool, certLen[i]);
		memset(oneCert[i], '\0', certLen[i]);

		if (ps_base64_decode((unsigned char*)start, certLen[i], oneCert[i],
				&certLen[i]) != 0) {
			psFree(certBuf);
			matrixStrDebugMsg("Unable to base64 decode certificate\n", NULL);
			goto err;
		}
		psFree(certBuf);
		certChainLen += certLen[i];
		i++;
/*
		Check for more files
*/
		fileName += parseList(pool, fileName, sep, &certFile);
	}

	*outLen = certChainLen;
/*
	Don't bother stringing them together if only one was passed in
*/
	if (i == 1) {
		sslAssert(certChainLen == certLen[0]);
		*out = oneCert[0];
		return 0;
	} else {
		*out = tmp = psMalloc(pool, certChainLen);
		for (i=0; i < MAX_CHAIN_LENGTH; i++) {
			if (oneCert[i]) {
				memcpy(tmp, oneCert[i], certLen[i]);
				tmp += certLen[i];
			}
		}
		rc = 0;
	}

err:
	for (i=0; i < MAX_CHAIN_LENGTH; i++) {
		if (oneCert[i]) psFree(oneCert[i]);
	}
	return rc;
}

/******************************************************************************/
/*
	This function was written strictly for clarity in the PeerSec crypto API
	product.  It extracts only the public key from a certificate file for use
	in the lower level encrypt/decrypt RSA routines
*/
int32 matrixX509ReadPubKey(psPool_t *pool, char *certFile, sslRsaKey_t **key)
{
	unsigned char	*certBuf;
	int32			certBufLen;

	certBuf = NULL;
	if (matrixX509ReadCert(pool, certFile, &certBuf, &certBufLen) < 0) {
		matrixStrDebugMsg("Unable to read certificate file %s\n", certFile);
		if (certBuf) psFree(certBuf);
		return -1;
	}
	if (matrixX509ParsePubKey(pool, certBuf, certBufLen, key) < 0) {
		psFree(certBuf);
		return -1;
	}
	psFree(certBuf);
	return 0;
}

/******************************************************************************/
/*
	Allows for semi-colon delimited list of certificates for cert chaining.
	The first in the list must be the identifying cert of the application.
	Each subsequent cert is the next parent.
*/
static int32 readCertChain(psPool_t *pool, char *certFiles, sslKeys_t *lkeys)
{
	sslLocalCert_t	*currCert;
	const char		sep[] = ";";
	char			*cert, *origList;
	unsigned char	*certBin;
	int32			certLen, i;

	if (certFiles == NULL) {
		return 0;
	}

	cert = NULL;
	origList = certFiles;
	certFiles += parseList(pool, certFiles, sep, &cert);

	i = 0;
	while (cert != NULL) {
		if (matrixX509ReadCert(pool, cert, &certBin, &certLen) < 0) {
			matrixStrDebugMsg("Error reading cert file %s\n", cert);
			psFree(cert);
			return -1;
		}
		psFree(cert);
/*
		The first cert is allocated in the keys struct.  All others in
		linked list are allocated here.
*/
		if (i++ == 0) {
			currCert = &lkeys->cert;
		} else {
			currCert->next = psMalloc(pool, sizeof(sslLocalCert_t));
			if (currCert->next == NULL) {
				return -8; /* SSL_MEM_ERROR */
			}
			memset(currCert->next, 0x0, sizeof(sslLocalCert_t));
			currCert = currCert->next;
		}
		currCert->certBin = certBin;
		currCert->certLen = certLen;
		certFiles += parseList(pool, certFiles, sep, &cert);
	}
	return 0;
}

/******************************************************************************/
/*
 *	Strtok substitute
 */
static int32 parseList(psPool_t *pool, char *list, const char *sep, char **item)
{
	int32	start, listLen;
	char	*tmp;

	start = listLen = (int32)strlen(list) + 1;
	if (start == 1) {
		*item = NULL;
		return 0;
	}
	tmp = *item = psMalloc(pool, listLen);
	if (tmp == NULL) {
		return -8; /* SSL_MEM_ERROR */
	}
	memset(*item, 0, listLen);
	while (listLen > 0) {
		if (*list == sep[0]) {
			list++;
			listLen--;
			break;
		}
		if (*list == 0) {
			break;
		}
		*tmp++ = *list++;
		listLen--;
	}
	return start - listLen;
}
#endif /* USE_FILE_SYSTEM */


/******************************************************************************/
/*
	Preferred version for commercial users who make use of memory pools.

	This use of the sslKeys_t param implies this is for use in the MatrixSSL
	product (input to matrixSslNewSession).  However, we didn't want to
	expose this API at the matrixSsl.h level due to the pool parameter. This
	is strictly an API that commerical users will have access to.
*/
int32 matrixRsaParseKeysMem(psPool_t *pool, sslKeys_t **keys, char *certBuf,
			int32 certLen, char *privBuf, int32 privLen, char *trustedCABuf,
			int32 trustedCALen)
{
	sslKeys_t		*lkeys;

⌨️ 快捷键说明

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