Leaked source code of windows server 2003
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.

303 lines
8.1 KiB

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