예제 #1
0
파일: x509.c 프로젝트: withwave/RT5350
/*
 *	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
 */
int32 matrixX509ReadCert(psPool_t *pool, const char *fileName,
					unsigned char **out, int32 *outLen, sslChainLen_t *chain)
{
	int32			certBufLen, rc, certChainLen, i;
	unsigned char	*oneCert[MAX_CHAIN_LENGTH];
	unsigned char	*certPtr, *tmp;
	char			*certFile, *start, *end, *certBuf;
	const char		sep[] = ";";

/*
	Init chain array and output params
*/
	for (i=0; i < MAX_CHAIN_LENGTH; i++) {
		oneCert[i] = NULL;
		(*chain)[i] = 0;
	}
	*outLen = certChainLen = i = 0;
	rc = -1;

/*
	For PKI product purposes, this routine now accepts a chain of certs.
*/
	if (fileName != NULL) {
		fileName += parseList(pool, fileName, sep, &certFile);
	} else {
		return 0;
	}

	while (certFile != NULL) {
	
		if (i == MAX_CHAIN_LENGTH) {
			matrixIntDebugMsg("Exceeded maximum cert chain length of %d\n",
				MAX_CHAIN_LENGTH);
			psFree(certFile);
			rc = -1;
			goto err;
		}
		if ((rc = psGetFileBin(pool, certFile, (unsigned char**)&certBuf,
				&certBufLen)) < 0) {
			matrixStrDebugMsg("Couldn't open file %s\n", certFile);
			goto err;
		}
		psFree(certFile);
		certPtr = (unsigned char*)certBuf;
		start = end = certBuf;

		while (certBufLen > 0) {
			if (((start = strstr(certBuf, "-----BEGIN")) != NULL) && 
					((start = strstr(certBuf, "CERTIFICATE-----")) != NULL) &&
					(end = strstr(start, "-----END")) != NULL) {
				start += strlen("CERTIFICATE-----");
				(*chain)[i] = (int32)(end - start);
				end += strlen("-----END CERTIFICATE-----");
				while (*end == '\r' || *end == '\n' || *end == '\t' || *end == ' ') {
					end++;
				}
			} else {
				psFree(certPtr);
				rc = -1;
				goto err;
			}
			oneCert[i] = psMalloc(pool, (*chain)[i]);
			certBufLen -= (int32)(end - certBuf);
			certBuf = end;
			memset(oneCert[i], '\0', (*chain)[i]);

			if (ps_base64_decode((unsigned char*)start, (*chain)[i], oneCert[i],
					&(*chain)[i]) != 0) {
				psFree(certPtr);
				matrixStrDebugMsg("Unable to base64 decode certificate\n", NULL);
				rc = -1;
				goto err;
			}
			certChainLen += (*chain)[i];
			i++;
			if (i == MAX_CHAIN_LENGTH) { 
				matrixIntDebugMsg("Exceeded maximum cert chain length of %d\n", 
					MAX_CHAIN_LENGTH); 
				psFree(certPtr); 
				rc = -1; 
				goto err; 
			} 
		}
		psFree(certPtr);
/*
		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 == (*chain)[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], (*chain)[i]);
				tmp += (*chain)[i];
			}
		}
		rc = 0;
	}

err:
	for (i=0; i < MAX_CHAIN_LENGTH; i++) {
		if (oneCert[i]) psFree(oneCert[i]);
	}
	return rc;
}
예제 #2
0
/*
 *	Public API to return an ASN.1 encoded key stream from a PEM private
 *	key file
 *
 *	If password is provided, we only deal with 3des cbc encryption
 *	Function allocates key on success.  User must free.
 */
int32 matrixRsaReadPrivKey(psPool_t *pool, const char *fileName,
				const char *password, unsigned char **keyMem, int32 *keyMemLen)
{
	unsigned char	*keyBuf, *DERout, *start, *end;
	int32			keyBufLen, rc, DERlen, PEMlen = 0;
#ifdef USE_3DES
	sslCipherContext_t	ctx;
	unsigned char	passKey[SSL_DES3_KEY_LEN];
	unsigned char	cipherIV[SSL_DES3_IV_LEN];
	int32			tmp, encrypted = 0;
#endif /* USE_3DES */

	if (fileName == NULL) {
		return 0;
	}
	*keyMem = NULL;
	if ((rc = psGetFileBin(pool, fileName, &keyBuf, &keyBufLen)) < 0) {
		return rc;
	}
	start = end = NULL;

/*
 *	Check header and encryption parameters.
 */
	if ((start = strstr(keyBuf, "-----BEGIN RSA PRIVATE KEY-----")) == NULL) {
		matrixStrDebugMsg("Error parsing private key buffer\n", NULL);
		psFree(keyBuf);
		return -1;
	}
	start += strlen("-----BEGIN RSA PRIVATE KEY-----");
	while (*start == '\r' || *start == '\n') {
		start++;
	}

	if (strstr(keyBuf, "Proc-Type:") && strstr(keyBuf, "4,ENCRYPTED")) {
#ifdef USE_3DES
		encrypted++;
		if (password == NULL) {
			matrixStrDebugMsg("No password given for encrypted private key\n",
				NULL);
			psFree(keyBuf);
			return -1;
		}
		if ((start = strstr(keyBuf, encryptHeader)) == NULL) {
			matrixStrDebugMsg("Unrecognized private key file encoding\n",
				NULL);
			psFree(keyBuf);
			return -1;
		}
		start += strlen(encryptHeader);
		/* SECURITY - we assume here that header points to at least 16 bytes of data */
		tmp = hexToBinary((unsigned char*)start, cipherIV, SSL_DES3_IV_LEN);
		if (tmp < 0) {
			matrixStrDebugMsg("Invalid private key file salt\n", NULL);
			psFree(keyBuf);
			return -1;
		}
		start += tmp;
		generate3DESKey((unsigned char*)password, (int32)strlen(password),
			cipherIV, (unsigned char*)passKey);
#else  /* !USE_3DES */
/*
 *		The private key is encrypted, but 3DES support has been turned off
 */
		matrixStrDebugMsg("3DES has been disabled for private key decrypt\n", NULL);
		psFree(keyBuf);
		return -1;  
#endif /* USE_3DES */
	}

	if ((end = strstr(keyBuf, "-----END RSA PRIVATE KEY-----")) == NULL) {
		matrixStrDebugMsg("Error parsing private key buffer\n", NULL);
		psFree(keyBuf);
		return -1;
	}
	PEMlen = (int32)(end - start);

/*
	Take the raw input and do a base64 decode
 */
	DERout = psMalloc(pool, PEMlen);
	if (DERout == NULL) {
		return -8; /* SSL_MEM_ERROR */
	}
	DERlen = PEMlen;
	if (ps_base64_decode(start, PEMlen, DERout, (uint32*)&DERlen) != 0) {
		psFree(DERout);
		psFree(keyBuf);
		matrixStrDebugMsg("Unable to base64 decode private key\n", NULL);
		return -1;
	}
	psFree(keyBuf);
#ifdef USE_3DES
/*
 *	Decode
 */
	if (encrypted == 1 && password) {
		matrix3desInit(&ctx, cipherIV, passKey, SSL_DES3_KEY_LEN);
		matrix3desDecrypt(&ctx, DERout, DERout, DERlen);
	}
#endif /* USE_3DES */
/*
	Don't parse this here.  Return the ASN.1 encoded buf to be
	consistent with the other mem APIs.  Use the ParsePrivKey 
	function if you want the structure format
*/
	*keyMem = DERout;
	*keyMemLen = DERlen;
	return rc;
}