Пример #1
0
static int vfy_chain_pkix(CERTCertificate **chain, int chain_len,
						   CERTCertificate **end_out,
						   bool *rev_opts)
{
	CERTCertificate *end_cert = NULL;
	CERTCertList *trustcl = get_all_root_certs();

	if (trustcl == NULL) {
		DBG(DBG_X509, DBG_log("X509: no trust anchor available for verification"));
		return VERIFY_RET_SKIP;
	}

	int i;

	for (i = 0; i < chain_len; i++) {
		if (!CERT_IsCACert(chain[i], NULL)) {
			end_cert = chain[i];
			break;
		}
	}

	if (end_cert == NULL) {
		libreswan_log("X509: no EE-cert in chain!");
		return VERIFY_RET_FAIL;
	}


	CERTVerifyLog *cur_log = NULL;
	CERTVerifyLog vfy_log;
	CERTVerifyLog vfy_log2;

	new_vfy_log(&vfy_log);
	new_vfy_log(&vfy_log2);

	CERTRevocationFlags rev;
	zero(&rev);	/* ??? are there pointer fields? */

	PRUint64 revFlagsLeaf[2] = { 0, 0 };
	PRUint64 revFlagsChain[2] = { 0, 0 };

	set_rev_per_meth(&rev, revFlagsLeaf, revFlagsChain);
	set_rev_params(&rev, rev_opts[RO_CRL_S], rev_opts[RO_OCSP],
						 rev_opts[RO_OCSP_S]);
	int in_idx = 0;
	CERTValInParam cvin[7];
	CERTValOutParam cvout[3];
	zero(&cvin);	/* ??? are there pointer fields? */
	zero(&cvout);	/* ??? are there pointer fields? */

	cvin[in_idx].type = cert_pi_revocationFlags;
	cvin[in_idx++].value.pointer.revocation = &rev;

	cvin[in_idx].type = cert_pi_useAIACertFetch;
	cvin[in_idx++].value.scalar.b = rev_opts[RO_OCSP];

	cvin[in_idx].type = cert_pi_trustAnchors;
	cvin[in_idx++].value.pointer.chain = trustcl;

	cvin[in_idx].type = cert_pi_useOnlyTrustAnchors;
	cvin[in_idx++].value.scalar.b = PR_TRUE;

	cvin[in_idx].type = cert_pi_end;

	cvout[0].type = cert_po_errorLog;
	cvout[0].value.pointer.log = cur_log = &vfy_log;
	cvout[1].type = cert_po_certList;
	cvout[1].value.pointer.chain = NULL;
	cvout[2].type = cert_po_end;

	/* kludge alert!!
	 * verification may be performed twice: once with the
	 * 'client' usage and once with 'server', which is an NSS
	 * detail and not related to IKE. In the absence of a real
	 * IKE profile being available for NSS, this covers more
	 * KU/EKU combinations
	 */

	int fin;
	SECCertificateUsage usage;

	for (usage = certificateUsageSSLClient; ; usage = certificateUsageSSLServer) {
		SECStatus rv = CERT_PKIXVerifyCert(end_cert, usage, cvin, cvout, NULL);

		if (rv != SECSuccess || cur_log->count > 0) {
			if (cur_log->count > 0 && cur_log->head != NULL) {
				if (usage == certificateUsageSSLClient &&
				    RETRYABLE_TYPE(cur_log->head->error)) {
					/* try again, after some adjustments */
					DBG(DBG_X509,
					    DBG_log("retrying verification with the NSS serverAuth profile"));
					/* ??? since we are about to overwrite cvout[1],
					 * should we be doing:
					 * if (cvout[1].value.pointer.chain != NULL)
					 *	CERT_DestroyCertList(cvout[1].value.pointer.chain);
					 */
					cvout[0].value.pointer.log = cur_log = &vfy_log2;
					cvout[1].value.pointer.chain = NULL;
					continue;
				} else {
					fin = nss_err_to_revfail(cur_log->head);
				}
			} else {
				/*
				 * An rv != SECSuccess without CERTVerifyLog results should not
				 * happen, but catch it anyway
				 */
				libreswan_log("X509: unspecified NSS verification failure");
				fin = VERIFY_RET_FAIL;
			}
		} else {
			DBG(DBG_X509, DBG_log("certificate is valid"));
			*end_out = end_cert;
			fin = VERIFY_RET_OK;
		}
		break;
	}

	CERT_DestroyCertList(trustcl);
	PORT_FreeArena(vfy_log.arena, PR_FALSE);
	PORT_FreeArena(vfy_log2.arena, PR_FALSE);

	if (cvout[1].value.pointer.chain != NULL) {
		CERT_DestroyCertList(cvout[1].value.pointer.chain);
	}

	return fin;
}
Пример #2
0
int main(int argc, char *argv[])
{
	int opt;
	long fin = 0;
	int use_pkix = 0;
	SECStatus rv;
	char pbuf[1024];
	PRBool crlcheck = PR_FALSE;
	PRBool ocspcheck = PR_FALSE;
	PRBool strict = PR_FALSE;
	CERTCertDBHandle *handle = NULL;
	CERTCertificate **certout = NULL;
	CERTVerifyLog vfy_log;
	CERTVerifyLog vfy_log2;
	CERTVerifyLog *cur_log;
	CERTValOutParam *pkixout = NULL;

	SECItem c1;
	SECItem c2;
	SECItem *certs[2];
	certs[0] = &c1;
	certs[1] = &c2;

	int numcerts = 0;
	while ((opt = getopt(argc, argv, "u:d:e:pn:s:coSr")) != -1) {
		switch(opt) {
			/* usage type */
		case 'u':
			set_usage(optarg);
			break;
		case 'd':
			db_dir = optarg;
			break;
		case 's':
			sub_file = optarg;
			break;
		case 'c':
			crlcheck = PR_TRUE;
			break;
		case 'o':
			ocspcheck = PR_TRUE;
			break;
		case 'S':
			strict = PR_TRUE;
			break;
		case 'e':
			end_file = optarg;
			break;
		case 'p':
			use_pkix = 1;
			break;
		case 'n':
			rightca_nick = optarg;
			break;
		case 'r':
			retry_verify = PR_TRUE;
			break;
		default:
			print_usage();
			break;
		}
	}

	if (db_dir == NULL)
		db_dir = "testfiles/";
	if (end_file == NULL)
		end_file = "testfiles/end.pem";

	get_file(certs[numcerts++], end_file);

	if (sub_file != NULL) {
		get_file(certs[numcerts++], sub_file);
	}

	snprintf(pbuf, sizeof(pbuf), "sql:%s", db_dir);
	if (NSS_Initialize(pbuf, "", "", "secmod.db", 0x1) != SECSuccess) {
		printf("NSS_Initialize failed %d\n", PORT_GetError());
		exit(-1);
	}

	if ((handle = CERT_GetDefaultCertDB()) == NULL) {
		printf("NULL handle\n");
		exit(-1);
	}
	if (ocspcheck) {
		CERT_EnableOCSPChecking(handle);
		CERT_DisableOCSPDefaultResponder(handle);
		if (strict)
			CERT_SetOCSPFailureMode(ocspMode_FailureIsNotAVerificationFailure);
	}

	rv = CERT_ImportCerts(handle, 0, numcerts, certs, &certout, PR_FALSE,
							 PR_FALSE, NULL);
	if (rv != SECSuccess) {
		printf("CERT_ImportCerts failed %d\n", PORT_GetError());
		exit(-1);
	}
	vfy_log.count = 0;
	vfy_log.head = NULL;
	vfy_log.tail = NULL;
	vfy_log.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);

	vfy_log2.count = 0;
	vfy_log2.head = NULL;
	vfy_log2.tail = NULL;
	vfy_log2.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);

	if (use_pkix) {
		int in_idx = 0;
		CERTValInParam cvin[7];
		CERTValOutParam cvout[3];
		CERTCertList *trustcl = NULL;
		CERTRevocationFlags rev;
		PRUint64 revFlagsLeaf[2] = { 0, 0 };
		PRUint64 revFlagsChain[2] = { 0, 0 };

		zero(&cvin);	/* ??? is this reasonable? */
		zero(&cvout);	/* ??? is this reasonable? */
		zero(&rev);	/* ??? is this reasonable? */

		if (rightca_nick == NULL)
			rightca_nick = "root";

		if ((trustcl = get_trust_certlist(handle, rightca_nick)) == NULL) {
			printf("Couldn't find trust anchor\n");
			exit(-1);
		}

		cvin[in_idx].type = cert_pi_useAIACertFetch;
		cvin[in_idx++].value.scalar.b = PR_TRUE;
		cvin[in_idx].type = cert_pi_revocationFlags;
		cvin[in_idx++].value.pointer.revocation = &rev;
		cvin[in_idx].type = cert_pi_trustAnchors;
		cvin[in_idx++].value.pointer.chain = trustcl;
		cvin[in_idx].type = cert_pi_useOnlyTrustAnchors;
		cvin[in_idx++].value.scalar.b = PR_TRUE;

		set_rev_per_meth(&rev, revFlagsLeaf, revFlagsChain);
		set_rev_params(&rev, crlcheck, ocspcheck, strict);
		cvin[in_idx].type = cert_pi_end;

		cvout[0].type = cert_po_errorLog;
		cvout[0].value.pointer.log = &vfy_log;
		cur_log = &vfy_log;
		cvout[1].type = cert_po_certList;
		cvout[1].value.pointer.chain = NULL;
		cvout[2].type = cert_po_end;
		pkixout = &cvout[0];

pkixredo:
		rv = CERT_PKIXVerifyCert(*certout, pkixusage, cvin, cvout,
				NULL);

		//CERT_DestroyCertList(trustcl);

	} else {
		cur_log = &vfy_log;
vfyredo:
		rv = CERT_VerifyCert(handle, *certout, PR_TRUE, usage, PR_Now(),
								       NULL,
								       cur_log);
	}

	if (rv != SECSuccess || cur_log->count > 0) {
		if (cur_log->count > 0 && cur_log->head != NULL) {
			fin = err_stat(cur_log->head);
		} else {
			fin = PORT_GetError();
		}
		if (fin == SEC_ERROR_INADEQUATE_KEY_USAGE) {
			printf("SEC_ERROR_INADEQUATE_KEY_USAGE : Certificate key usage inadequate for attempted operation.\n"
				);
		} else if (fin == SEC_ERROR_INADEQUATE_CERT_TYPE) {
			printf("SEC_ERROR_INADEQUATE_CERT_TYPE : Certificate type not approved for application.\n"
				);
		} else {
			printf("OTHER : %ld", fin);
		}
	}
	if ((fin == SEC_ERROR_INADEQUATE_CERT_TYPE ||
			fin == SEC_ERROR_INADEQUATE_KEY_USAGE) &&
					 retry_verify && !retried) {
		printf("Retrying verification\n");
		fin = 0;
		retried = PR_TRUE;
		if (use_pkix) {
			pkixout[0].value.pointer.log = &vfy_log2;
			cur_log = &vfy_log2;
			pkixout[1].value.pointer.chain = NULL;
			if (pkixusage == certificateUsageSSLClient) {
				pkixusage = certificateUsageSSLServer;
			} else {
				pkixusage = certificateUsageSSLClient;
			}
			goto pkixredo;
		} else {
			if (usage == certUsageSSLClient) {
				usage = certUsageSSLServer;
			} else {
				usage = certUsageSSLClient;
			}
			goto vfyredo;
		}
	}

	PORT_FreeArena(vfy_log.arena, PR_FALSE);
	PORT_FreeArena(vfy_log2.arena, PR_FALSE);
	NSS_Shutdown();
	exit(fin == 0 ? 0 : 1);
}