win_cert_handler.c

来自「linux 下通过802.1认证的安装包」· C语言 代码 · 共 580 行 · 第 1/2 页

C
580
字号

/**
 * \brief Free the memory that was allocated to store the certificate enumeration.
 *
 * @param[in] numcas   The number of CAs that are represented in the enumeration.
 * @param[in] cas   The array of CA names.
 **/
void cert_handler_free_cert_enum(int numcas, cert_enum **cas)
{
	cert_enum *casa = NULL;
	int i = 0;

	casa = (*cas);

	for (i = 0; i < numcas; i++)
	{
		if (casa[i].certname != NULL) FREE(casa[i].certname);
		if (casa[i].friendlyname != NULL) FREE(casa[i].friendlyname);
		if (casa[i].issuer != NULL) FREE(casa[i].issuer);
	}

	free((*cas));
	(*cas) = NULL;
}

char *do_sha1(char *tohash, int size)
{
  EVP_MD_CTX ctx;
  char *hash_ret;
  int evp_ret_len;

  if (!xsup_assert((tohash != NULL), "tohash != NULL", FALSE))
    return NULL;

  if (!xsup_assert((size > 0), "size > 0", FALSE))
    return NULL;

  hash_ret = (char *)Malloc(21);  // We should get 20 bytes returned.
  if (hash_ret == NULL)
    {
      debug_printf(DEBUG_NORMAL, "Couldn't allocate memory for 'hash_ret' in "
		   "%s().\n", __FUNCTION__);
      return NULL;
    }
 
  EVP_DigestInit(&ctx, EVP_sha1());
  EVP_DigestUpdate(&ctx, tohash, size);
  EVP_DigestFinal(&ctx, hash_ret, (int *)&evp_ret_len);

  if (evp_ret_len != 20)
    {
      debug_printf(DEBUG_NORMAL, "Invalid result from OpenSSL SHA calls! "
		   "(%s:%d)\n", __FUNCTION__, __LINE__);
      return NULL;
    }

  return hash_ret;
}


/**
 * \brief Enumerate root CA certificates that are in the store that
 *        can be used for server authentication.
 *
 * @param[in] numcas   An integer the specifies the number of CA certificates we are expected to
 *                     return.  This value should come from the cert_handler_num_root_ca_certs().
 *                     On return, this will contain the number of certificates that are actually in
 *                     the array.
 *
 * @param[in,out] cas   An array of certificates that contains the number of certificates defined
 *                      by numcas.
 *
 * \retval -1 on error
 * \retval 0 on success
 **/
int cert_handler_enum_root_ca_certs(int *numcas, cert_enum **cas)
{
	PCCERT_CONTEXT  pCertContext = NULL;
	int certidx = 0;
	int i = 0;
	char pszNameString[256];
	char pszSubjectString[1024];
	DWORD size = 0;
	CERT_ENHKEY_USAGE *enhkey = NULL;
	cert_enum *casa = NULL;
	SYSTEMTIME systime;
	uint8_t *sha1hash = NULL;
	char *temp = NULL;

	if (hCertStore != NULL)
	{
		cert_handler_deinit();
		cert_handler_init();
	}

	casa = Malloc((sizeof(cert_enum) * ((*numcas)+1)));
	if (casa == NULL)
	{
		debug_printf(DEBUG_NORMAL, "Couldn't allocate memory to store certificate enumeration.\n");
		return -1;
	}

	// Enumerate all of the certificates, and count only the ones that have the
	// server authentication EKU set.
	while ((hCertStore != NULL) && (pCertContext = CertEnumCertificatesInStore(hCertStore, pCertContext)) &&
		(pCertContext != NULL))
	{
		// We only check this certificate if we can get it's name.  If not, it is ignored.
		if (!CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, pszNameString, sizeof(pszNameString)))
		{
			debug_printf(DEBUG_NORMAL, "Unable to determine certificate name.\n");
		}
		else
		{
			// Everything in this enum is out of the windows cert store.
			casa[certidx].storetype = _strdup("WINDOWS");

			sha1hash = do_sha1(pCertContext->pbCertEncoded, pCertContext->cbCertEncoded);
			temp = convert_hex_to_str(sha1hash, 20);
			casa[certidx].location = temp;
			FREE(sha1hash);

#ifdef CHECK_EKU
			if (CertGetEnhancedKeyUsage(pCertContext, 0, NULL, &size))
			{
				enhkey = malloc(size);
				if (enhkey == NULL)
				{
					debug_printf(DEBUG_NORMAL, "Unable to allocate memory to get EKU data!\n");
					return -1;
				}

				if (CertGetEnhancedKeyUsage(pCertContext, 0, enhkey, &size))
				{
					for (i = 0; i < enhkey->cUsageIdentifier; i++)
					{
						if (strcmp(enhkey->rgpszUsageIdentifier[i], szOID_PKIX_KP_SERVER_AUTH) == 0)
						{
#endif
							casa[certidx].certname = _strdup(pszNameString);
							
							// Get the subject name for this certificate.

							if (CertGetNameString(pCertContext, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, pszSubjectString, sizeof(pszSubjectString)) > 0)
							{
								casa[certidx].friendlyname = _strdup(pszSubjectString);
							}

							memset(&pszSubjectString, 0x00, sizeof(pszSubjectString));

							if (CertGetNameString(pCertContext, CERT_NAME_DNS_TYPE, 0, NULL, pszSubjectString, sizeof(pszSubjectString)) > 0)
							{
								casa[certidx].commonname = _strdup(pszSubjectString);
							}

							// Get the issuer name for this certificate.
							if (CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, NULL, pszSubjectString, sizeof(pszSubjectString)) > 0)
							{
								casa[certidx].issuer = _strdup(pszSubjectString);
							}

							memset(&systime, 0x00, sizeof(systime));

							if (FileTimeToSystemTime(&pCertContext->pCertInfo->NotAfter, &systime) != 0)
							{
								casa[certidx].day = systime.wDay;
								casa[certidx].month = systime.wMonth;
								casa[certidx].year = systime.wYear;
							}

							certidx++;
#ifdef CHECK_EKU
						}
					}
				}

				FREE(enhkey);
			}
			else
			{
				debug_printf(DEBUG_NORMAL, "Unable to determine EKU data size!\n");
				return -1;
			}
#endif
		}
	}

	debug_printf(DEBUG_CERTS, "There were %d cert(s) that can be used for server authentication.\n", certidx);
	(*cas) = casa;

	return certidx;
}

/**
 * \brief Add a certificate to our certificate store.
 *
 * @param[in] path_to_cert  The full path name to the certificate we want to add to our store.
 *
 * \retval 0 on success
 **/
int cert_handler_add_cert_to_store(char *path_to_cert)
{
	HANDLE hFile;
	PCCERT_CONTEXT	pCertContext;
	BYTE			pbBuffer[8096];
	DWORD			cbBuffer;
	DWORD			dwErr;
	LPVOID			lastErrStr;
	int				retval = 0;

	if ((hFile = CreateFile( path_to_cert,
							GENERIC_READ,
							0,
							NULL,
							OPEN_EXISTING,
							FILE_ATTRIBUTE_NORMAL,
							NULL ) ) != INVALID_HANDLE_VALUE )
	{
		cbBuffer = 0;

		memset( pbBuffer, 0, sizeof( pbBuffer ) );

		if (ReadFile( hFile,
						pbBuffer,
						sizeof( pbBuffer ),
						&cbBuffer,
						NULL ) )
		{

			if ((pCertContext = CertCreateCertificateContext( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 
															pbBuffer, 
															cbBuffer) ) )
			{
				if (hCertStore)
				{
					if (!CertAddCertificateContextToStore( hCertStore, 
															pCertContext, 
															CERT_STORE_ADD_NEW, 
															NULL ) )
					{
						dwErr = GetLastError();

						if (dwErr ==  CRYPT_E_EXISTS )
						{
							//
							// Certificate already exists
							//
						}
						else
						{
							lastErrStr = GetLastErrorStr(dwErr);
							debug_printf(DEBUG_NORMAL, "Unable to add certificate to store.  Windows error was '%d'.\n", lastErrStr);
							LocalFree(lastErrStr);
							retval = IPC_EVENT_ERROR_CANT_ADD_CERT_TO_STORE;
						}
					}
				}
				else
				{
					debug_printf(DEBUG_NORMAL, "Certificate store isn't open!\n");
					retval = IPC_EVENT_ERROR_FAILED_ROOT_CA_LOAD;
				}

				CertFreeCertificateContext( pCertContext );

				pCertContext = NULL;
			}
			else
			{
				debug_printf(DEBUG_NORMAL, "Unable to read certificate file!\n");
				retval = IPC_EVENT_ERROR_CANT_READ_FILE;
			}
		}
		else
		{
			debug_printf(DEBUG_NORMAL, "Unable to open certificate file!\n");
			retval = IPC_EVENT_ERROR_CANT_READ_FILE;
		}

		CloseHandle( hFile );
	}
	else
	{
		retval = IPC_EVENT_ERROR_CANT_READ_FILE;
	}

	return retval;
}

⌨️ 快捷键说明

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