Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

298 lines
7.7 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1998
  6. //
  7. // File: cert.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. /////////////////////////////////////////////////////////////////////
  11. // Cert.cpp
  12. //
  13. // This file is the implementation of the CCertificate object.
  14. //
  15. // GLOSSARY
  16. // - BLOB Binary Large Object
  17. // - DER Distinguished Encoding Rules
  18. // - RDN Relative Distinguished Names
  19. //
  20. // HISTORY
  21. // 19-Jun-97 t-danm Creation.
  22. /////////////////////////////////////////////////////////////////////
  23. #include "stdafx.h"
  24. #include "common.h"
  25. #include "cert.h"
  26. /////////////////////////////////////////////////////////////////////
  27. CCertificate::CCertificate()
  28. {
  29. m_paCertContext = NULL;
  30. m_blobCertData.pbData = NULL;
  31. }
  32. CCertificate::~CCertificate()
  33. {
  34. // Free the certificate
  35. ::CertFreeCertificateContext(m_paCertContext);
  36. delete m_blobCertData.pbData;
  37. }
  38. void DisplaySystemError (HWND hParent, DWORD dwErr)
  39. {
  40. AFX_MANAGE_STATE (AfxGetStaticModuleState ());
  41. LPVOID lpMsgBuf;
  42. FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  43. NULL,
  44. dwErr,
  45. MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  46. (LPTSTR) &lpMsgBuf, 0, NULL);
  47. // Display the string.
  48. CString caption;
  49. VERIFY (caption.LoadString (IDS_ADD_CERTIFICATE_MAPPING));
  50. ::MessageBox (hParent, (LPWSTR) lpMsgBuf, (LPCTSTR) caption, MB_OK | MB_ICONINFORMATION);
  51. // Free the buffer.
  52. LocalFree (lpMsgBuf);
  53. }
  54. // This code copied from CertMgr project - LOCATE.C
  55. BOOL CCertificate::FLoadCertificate (LPCTSTR szFile)
  56. {
  57. ASSERT (szFile);
  58. if ( !szFile )
  59. return FALSE;
  60. BOOL bReturn = FALSE;
  61. PVOID FileNameVoidP = (PVOID) szFile;
  62. PCCERT_CONTEXT pCertContext = NULL;
  63. DWORD dwEncodingType = 0;
  64. DWORD dwContentType = 0;
  65. DWORD dwFormatType = 0;
  66. // NB. It's possible to read in a serialized store at this point, too.
  67. // We've have to add the UI to display the certs in the file so the
  68. // user could pick one. Use CryptUIDlgSelectCertificate ().
  69. bReturn = ::CryptQueryObject (
  70. CERT_QUERY_OBJECT_FILE,
  71. FileNameVoidP,
  72. CERT_QUERY_CONTENT_FLAG_ALL, //CERT_QUERY_CONTENT_CERT | CERT_QUERY_CONTENT_SERIALIZED_CERT,
  73. CERT_QUERY_FORMAT_FLAG_ALL,
  74. 0,
  75. &dwEncodingType,
  76. &dwContentType,
  77. &dwFormatType,
  78. NULL,
  79. NULL,
  80. (const void **)&pCertContext);
  81. ASSERT (bReturn);
  82. if ( bReturn )
  83. {
  84. //
  85. // Success. See what we get back.
  86. //
  87. if ( (dwContentType != CERT_QUERY_CONTENT_CERT) || !pCertContext )
  88. {
  89. //
  90. // Not a valid cert file.
  91. //
  92. if ( pCertContext )
  93. ::CertFreeCertificateContext (pCertContext);
  94. CString text;
  95. CString caption;
  96. VERIFY (text.LoadString (IDS_CERTFILEFORMATERR));
  97. VERIFY (caption.LoadString (IDS_ADD_CERTIFICATE_MAPPING));
  98. MessageBox (NULL, text, caption, MB_OK | MB_ICONINFORMATION);
  99. bReturn = FALSE;
  100. }
  101. else
  102. {
  103. // Cert context is valid - let's save it to the global handle
  104. m_paCertContext = pCertContext;
  105. }
  106. }
  107. else
  108. {
  109. DWORD dwErr = GetLastError ();
  110. DisplaySystemError (NULL, dwErr);
  111. }
  112. return bReturn;
  113. }
  114. /////////////////////////////////////////////////////////////////////
  115. // This routine is a wrapper to API ::CertNameToStr() automatically
  116. // calculating the length of the output string and returning the data
  117. // into the CString object.
  118. void CCertificate::CertNameToCString(
  119. IN DWORD dwCertEncodingType,
  120. IN CERT_NAME_BLOB * pName,
  121. OUT CString * pstrData)
  122. {
  123. ASSERT(pstrData != NULL);
  124. // Calculate how many characters are needed
  125. int cch = ::CertNameToStr(
  126. IN dwCertEncodingType,
  127. IN pName,
  128. IN c_dwCertNameStrType,
  129. NULL, 0);
  130. TCHAR * pchT = pstrData->GetBuffer(cch);
  131. ASSERT(pchT != NULL);
  132. ASSERT(lstrlen(pchT) == 0);
  133. (void)::CertNameToStr(
  134. IN dwCertEncodingType,
  135. IN pName,
  136. IN c_dwCertNameStrType,
  137. OUT pchT, IN cch);
  138. pstrData->ReleaseBuffer();
  139. } // CCertificate::CertNameToCString()
  140. /////////////////////////////////////////////////////////////////////
  141. void CCertificate::GetIssuer(OUT CString * pstrName)
  142. {
  143. ASSERT(pstrName != NULL);
  144. ASSERT(m_paCertContext != NULL);
  145. ASSERT(m_paCertContext->pCertInfo != NULL);
  146. CERT_INFO * pCertInfo = m_paCertContext->pCertInfo;
  147. BOOL fSelfIssued = CertCompareCertificateName(
  148. m_paCertContext->dwCertEncodingType,
  149. &pCertInfo->Subject,
  150. &pCertInfo->Issuer);
  151. if (fSelfIssued)
  152. {
  153. // Self issued certificate
  154. GetSubject(OUT pstrName);
  155. return;
  156. }
  157. // Get the issuer
  158. CertNameToCString(
  159. IN m_paCertContext->dwCertEncodingType,
  160. IN &pCertInfo->Issuer,
  161. OUT pstrName);
  162. } // CCertificate::GetIssuer()
  163. /////////////////////////////////////////////////////////////////////
  164. void CCertificate::GetSubject(OUT CString * pstrName)
  165. {
  166. ASSERT(pstrName != NULL);
  167. ASSERT(m_paCertContext != NULL);
  168. ASSERT(m_paCertContext->pCertInfo != NULL);
  169. CertNameToCString(
  170. IN m_paCertContext->dwCertEncodingType,
  171. IN &m_paCertContext->pCertInfo->Subject,
  172. OUT pstrName);
  173. } // CCertificate::GetSubject()
  174. /////////////////////////////////////////////////////////////////////
  175. void CCertificate::GetAltSubject(OUT CString * pstrName)
  176. {
  177. ASSERT(pstrName != NULL);
  178. ASSERT(m_paCertContext != NULL);
  179. ASSERT(m_paCertContext->pCertInfo != NULL);
  180. pstrName->Empty();
  181. CERT_INFO * pCertInfo = m_paCertContext->pCertInfo;
  182. CERT_EXTENSION * pCertExtension;
  183. // Search for the AltSubject in the extensions
  184. pCertExtension = ::CertFindExtension(
  185. IN szOID_SUBJECT_ALT_NAME, // Same as X509_ALTERNATE_NAME
  186. IN pCertInfo->cExtension,
  187. IN pCertInfo->rgExtension);
  188. if (pCertExtension == NULL)
  189. return; // No AltSubject
  190. DWORD dwErr = ERROR_SUCCESS;
  191. BOOL fSuccess;
  192. DWORD cbData = 0;
  193. // Find out how many bytes are needed for AltSubject
  194. fSuccess = ::CryptDecodeObject(
  195. m_paCertContext->dwCertEncodingType,
  196. X509_ALTERNATE_NAME,
  197. IN pCertExtension->Value.pbData,
  198. IN pCertExtension->Value.cbData,
  199. 0, // dwFlags
  200. NULL,
  201. INOUT &cbData);
  202. if (!fSuccess)
  203. {
  204. dwErr = ::GetLastError();
  205. TRACE1("CryptDecodeObject() returned error %u", dwErr);
  206. return;
  207. }
  208. ASSERT(cbData > 0);
  209. BYTE * pbDataT = new BYTE[cbData];
  210. // Decode the AltSubject name
  211. fSuccess = ::CryptDecodeObject(
  212. m_paCertContext->dwCertEncodingType,
  213. X509_ALTERNATE_NAME,
  214. IN pCertExtension->Value.pbData,
  215. IN pCertExtension->Value.cbData,
  216. 0, // dwFlags
  217. OUT pbDataT,
  218. INOUT &cbData);
  219. if (!fSuccess)
  220. {
  221. dwErr = ::GetLastError();
  222. TRACE1("CryptDecodeObject() returned error %u", dwErr);
  223. }
  224. else
  225. {
  226. CERT_ALT_NAME_INFO * pCertAltNameInfo = (CERT_ALT_NAME_INFO *)pbDataT;
  227. CERT_ALT_NAME_ENTRY * pEntry = pCertAltNameInfo->rgAltEntry;
  228. ASSERT(pEntry != NULL);
  229. for (UINT i = 0; i < pCertAltNameInfo->cAltEntry; i++, pEntry++)
  230. {
  231. if (pEntry->dwAltNameChoice == CERT_ALT_NAME_DNS_NAME)
  232. {
  233. *pstrName = pEntry->pwszDNSName;
  234. break;
  235. }
  236. } // for
  237. } // if...else
  238. delete pbDataT;
  239. } // CCertificate::GetAltSubject()
  240. /////////////////////////////////////////////////////////////////////
  241. void CCertificate::GetSimString(OUT CString * pstrData)
  242. {
  243. ASSERT(pstrData != NULL);
  244. CString strIssuer;
  245. CString strSubject;
  246. CString strAltSubject;
  247. GetIssuer(OUT &strIssuer);
  248. GetSubject(OUT &strSubject);
  249. GetAltSubject(OUT &strAltSubject);
  250. LPTSTR * pargzpszIssuer = ParseSimString(strIssuer);
  251. LPTSTR * pargzpszSubject = ParseSimString(strSubject);
  252. LPTSTR * pargzpszAltSubject = ParseSimString(strAltSubject);
  253. // Make a "X509" string
  254. UnsplitX509String(OUT pstrData, pargzpszIssuer, pargzpszSubject, pargzpszAltSubject);
  255. delete pargzpszIssuer;
  256. delete pargzpszSubject;
  257. delete pargzpszAltSubject;
  258. } // CCertificate::GetSimString()