void CAPICertificate::setUri (const std::string& capiUri) {
	valid_ = false;

	/* Syntax: "certstore:" <cert_store> ":" <hash> ":" <hash_of_cert> */

	if (!boost::iequals(capiUri.substr(0, 10), "certstore:")) {
		return;
	}

	/* Substring of subject: uses "storename" */
	std::string capiIdentity = capiUri.substr(10);
	std::string newCertStoreName;
	size_t pos = capiIdentity.find_first_of (':');

	if (pos == std::string::npos) {
		/* Using the default certificate store */
		newCertStoreName = "MY";
		certName_ = capiIdentity;
	}
	else {
		newCertStoreName = capiIdentity.substr(0, pos);
		certName_ = capiIdentity.substr(pos + 1);
	}

	if (certStoreHandle_ != NULL) {
		if (newCertStoreName != certStore_) {
			CertCloseStore(certStoreHandle_, 0);
			certStoreHandle_ = NULL;
		}
	}

	if (certStoreHandle_ == NULL) {
		certStoreHandle_ = CertOpenSystemStore(0, newCertStoreName.c_str());
		if (!certStoreHandle_) {
			return;
		}
	}

	certStore_ = newCertStoreName;

	PCCERT_CONTEXT certContext = findCertificateInStore (certStoreHandle_, certName_);

	if (!certContext) {
		return;
	}


	/* Now verify that we can have access to the corresponding private key */

	DWORD len;
	CRYPT_KEY_PROV_INFO *pinfo;
	HCRYPTPROV hprov;
	HCRYPTKEY key;

	if (!CertGetCertificateContextProperty(certContext,
			CERT_KEY_PROV_INFO_PROP_ID,
			NULL,
			&len)) {
		CertFreeCertificateContext(certContext);
		return;
	}

	pinfo = static_cast<CRYPT_KEY_PROV_INFO *>(malloc(len));
	if (!pinfo) {
		CertFreeCertificateContext(certContext);
		return;
	}

	if (!CertGetCertificateContextProperty(certContext, CERT_KEY_PROV_INFO_PROP_ID, pinfo, &len)) {
		CertFreeCertificateContext(certContext);
		free(pinfo);
		return;
	}

	CertFreeCertificateContext(certContext);

	// Now verify if we have access to the private key
	if (!CryptAcquireContextW(&hprov, pinfo->pwszContainerName, pinfo->pwszProvName, pinfo->dwProvType, 0)) {
		free(pinfo);
		return;
	}


	char smartCardReader[1024];
	DWORD bufferLength = sizeof(smartCardReader);
	if (!CryptGetProvParam(hprov, PP_SMARTCARD_READER, (BYTE *)&smartCardReader, &bufferLength, 0)) {
		DWORD error = GetLastError();
		smartCardReaderName_ = "";
	}
	else {
		smartCardReaderName_ = smartCardReader;

		LONG result = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &scardContext_);
		if (SCARD_S_SUCCESS == result) {
			// Initiate monitoring for smartcard ejection
			smartCardTimer_ = timerFactory_->createTimer(SMARTCARD_EJECTION_CHECK_FREQUENCY_MILLISECONDS);
		}
		else {
			///Need to handle an error here
		}
	}

	if (!CryptGetUserKey(hprov, pinfo->dwKeySpec, &key)) {
		CryptReleaseContext(hprov, 0);
		free(pinfo);
		return;
	}

	CryptDestroyKey(key);
	CryptReleaseContext(hprov, 0);
	free(pinfo);

	if (smartCardTimer_) {
		smartCardTimer_->onTick.connect(boost::bind(&CAPICertificate::handleSmartCardTimerTick, this));
		smartCardTimer_->start();
	}

	valid_ = true;
}
Exemplo n.º 2
0
void SchannelContext::connect() 
{
	ScopedCertContext pCertContext;

	m_state = Connecting;

	// If a user name is specified, then attempt to find a client
	// certificate. Otherwise, just create a NULL credential.
	if (!m_cert_name.empty())
	{
		if (m_my_cert_store == NULL)
		{
			m_my_cert_store = CertOpenSystemStore(0, m_cert_store_name.c_str());
			if (!m_my_cert_store)
			{
/////			printf( "**** Error 0x%x returned by CertOpenSystemStore\n", GetLastError() );
				indicateError();
				return;
			}
		}

		pCertContext = findCertificateInStore( m_my_cert_store, m_cert_name );
		if (pCertContext == NULL)
		{
/////		printf("**** Error 0x%x returned by CertFindCertificateInStore\n", GetLastError());
			indicateError();
			return;
		}
	}

	// We use an empty list for client certificates
	PCCERT_CONTEXT clientCerts[1] = {0};

	SCHANNEL_CRED sc = {0};
	sc.dwVersion = SCHANNEL_CRED_VERSION;

/////SSL3?
	sc.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT | SP_PROT_TLS1_CLIENT | SP_PROT_TLS1_1_CLIENT | SP_PROT_TLS1_2_CLIENT;
	sc.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION;

	if (pCertContext)
	{
		sc.cCreds = 1;
		sc.paCred = pCertContext.GetPointer();
		sc.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
	}
	else
	{
		sc.cCreds = 0; // Let Crypto API find the appropriate certificate for us
		sc.paCred = clientCerts;
		sc.dwFlags |= SCH_CRED_USE_DEFAULT_CREDS;
	}

	// Swiften performs the server name check for us
	sc.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;

	SECURITY_STATUS status = AcquireCredentialsHandle(
		NULL,
		UNISP_NAME,
		SECPKG_CRED_OUTBOUND,
		NULL,
		&sc,
		NULL,
		NULL,
		m_credHandle.Reset(),
		NULL);
	
	if (status != SEC_E_OK) 
	{
		// We failed to obtain the credentials handle
		indicateError();
		return;
	}

	SecBuffer outBuffers[2];

	// We let Schannel allocate the output buffer for us
	outBuffers[0].pvBuffer   = NULL;
	outBuffers[0].cbBuffer   = 0;
	outBuffers[0].BufferType = SECBUFFER_TOKEN;

	// Contains alert data if an alert is generated
	outBuffers[1].pvBuffer   = NULL;
	outBuffers[1].cbBuffer   = 0;
	outBuffers[1].BufferType = SECBUFFER_ALERT;

	// Make sure the output buffers are freed
	ScopedSecBuffer scopedOutputData(&outBuffers[0]);
	ScopedSecBuffer scopedOutputAlertData(&outBuffers[1]);

	SecBufferDesc outBufferDesc = {0};
	outBufferDesc.cBuffers   = 2;
	outBufferDesc.pBuffers   = outBuffers;
	outBufferDesc.ulVersion  = SECBUFFER_VERSION;

	// Create the initial security context
	status = InitializeSecurityContext(
		m_credHandle,
		NULL,
		NULL,
		m_ctxtFlags,
		0,
		0,
		NULL,
		0,
		m_ctxtHandle.Reset(),
		&outBufferDesc,
		&m_secContext,
		NULL);

	if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) 
	{
		// We failed to initialize the security context
		handleCertError(status);
		indicateError();
		return;
	}

	// Start the handshake
	sendDataOnNetwork(outBuffers[0].pvBuffer, outBuffers[0].cbBuffer);

	if (status == SEC_E_OK) 
	{
		status = validateServerCertificate();
		if (status != SEC_E_OK)
			handleCertError(status);

		m_state = Connected;
		determineStreamSizes();

		onConnected();
	}
}