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.

254 lines
7.9 KiB

  1. // WinRegCertStore.cpp - Implementation of CWinRegCertStore class
  2. //
  3. // (c) Copyright Schlumberger Technology Corp., unpublished work, created
  4. // 2000. This computer program includes Confidential, Proprietary
  5. // Information and is a Trade Secret of Schlumberger Technology Corp. All
  6. // use, disclosure, and/or reproduction is prohibited unless authorized
  7. // in writing. All Rights Reserved.
  8. /////////////////////////////////////////////////////////////////////////////////
  9. #include <windows.h>
  10. #include "scuOsExc.h"
  11. #include "pkiWinRegCertStore.h"
  12. #include "pkiX509Cert.h"
  13. using namespace pki;
  14. using namespace std;
  15. CWinRegCertStore::CWinRegCertStore(string strCertStore) : m_hCertStore(0)
  16. {
  17. // Open certificate store
  18. scu::AutoArrayPtr<WCHAR> aapWCertStore = ToWideChar(strCertStore);
  19. HCRYPTPROV hProv = 0;
  20. m_hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, hProv,
  21. CERT_SYSTEM_STORE_CURRENT_USER, aapWCertStore.Get());
  22. if(!m_hCertStore)
  23. throw scu::OsException(GetLastError());
  24. }
  25. CWinRegCertStore::~CWinRegCertStore()
  26. {
  27. try
  28. {
  29. // Close certificate store
  30. if(m_hCertStore)
  31. CertCloseStore(m_hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
  32. }
  33. catch(...) {}
  34. }
  35. void CWinRegCertStore::StoreUserCert(string const &strCert, DWORD const dwKeySpec,
  36. string const &strContName, string const &strProvName,
  37. string const &strFriendlyName)
  38. {
  39. // Create cert context
  40. PCCERT_CONTEXT pCertContext = CertCreateCertificateContext(
  41. X509_ASN_ENCODING,(BYTE*)strCert.c_str(),strCert.size());
  42. if(!pCertContext)
  43. throw scu::OsException(GetLastError());
  44. // Set the cert context properties
  45. CRYPT_KEY_PROV_INFO KeyProvInfo;
  46. scu::AutoArrayPtr<WCHAR> aapWContainerName = ToWideChar(strContName);
  47. scu::AutoArrayPtr<WCHAR> aapWProvName = ToWideChar(strProvName);
  48. KeyProvInfo.pwszContainerName = aapWContainerName.Get();
  49. KeyProvInfo.pwszProvName = aapWProvName.Get();
  50. KeyProvInfo.dwProvType = PROV_RSA_FULL;
  51. KeyProvInfo.dwFlags = 0;
  52. KeyProvInfo.cProvParam = 0;
  53. KeyProvInfo.rgProvParam = NULL;
  54. KeyProvInfo.dwKeySpec = dwKeySpec;
  55. BOOL ok = CertSetCertificateContextProperty(pCertContext,
  56. CERT_KEY_PROV_INFO_PROP_ID,
  57. 0, (void *)&KeyProvInfo);
  58. if(!ok)
  59. throw scu::OsException(GetLastError());
  60. // Set a friendly name. If it is not specified, try to derive one
  61. string strFN;
  62. if(strFriendlyName.size())
  63. strFN = strFriendlyName;
  64. else
  65. strFN = FriendlyName(strCert);
  66. if(strFN.size()) {
  67. scu::AutoArrayPtr<WCHAR> aapWFriendlyName = ToWideChar(strFN);
  68. CRYPT_DATA_BLOB DataBlob;
  69. DataBlob.pbData = (BYTE*)aapWFriendlyName.Get();
  70. DataBlob.cbData = (wcslen(aapWFriendlyName.Get())+1)*sizeof(WCHAR);
  71. ok = CertSetCertificateContextProperty(pCertContext, CERT_FRIENDLY_NAME_PROP_ID,0,&DataBlob);
  72. if(!ok)
  73. throw scu::OsException(GetLastError());
  74. }
  75. // Store the certificate
  76. ok = CertAddCertificateContextToStore(m_hCertStore, pCertContext,
  77. CERT_STORE_ADD_REPLACE_EXISTING, NULL);
  78. if(!ok)
  79. throw scu::OsException(GetLastError());
  80. }
  81. void CWinRegCertStore::StoreCACert(string const &strCert, string const &strFriendlyName)
  82. {
  83. // Create cert context
  84. PCCERT_CONTEXT pCertContext = CertCreateCertificateContext(
  85. X509_ASN_ENCODING,(BYTE*)strCert.c_str(),strCert.size());
  86. if(!pCertContext)
  87. throw scu::OsException(GetLastError());
  88. // Set the different Enhanced Key usage flags. On one side, one could be
  89. // more conservative and set fewer flags, after all the user may set
  90. // these afterwards. On the other side, most users will not know how to
  91. // to that and if the attributes are not set, various signature verifications
  92. // will fail..... The four below are quite common.
  93. BOOL ok;
  94. CRYPT_DATA_BLOB DataBlob;
  95. CERT_ENHKEY_USAGE EnKeyUsage;
  96. LPSTR UsageOIDs[4];
  97. UsageOIDs[0] = szOID_PKIX_KP_SERVER_AUTH;
  98. UsageOIDs[1] = szOID_PKIX_KP_CLIENT_AUTH;
  99. UsageOIDs[2] = szOID_PKIX_KP_CODE_SIGNING;
  100. UsageOIDs[3] = szOID_PKIX_KP_EMAIL_PROTECTION;
  101. EnKeyUsage.rgpszUsageIdentifier = UsageOIDs;
  102. EnKeyUsage.cUsageIdentifier = sizeof(UsageOIDs)/sizeof(*UsageOIDs);
  103. DWORD cbEncoded;
  104. // First call to find size for memory allocation
  105. ok = CryptEncodeObject(CRYPT_ASN_ENCODING, X509_ENHANCED_KEY_USAGE, &EnKeyUsage,NULL, &cbEncoded);
  106. if(!ok)
  107. throw scu::OsException(GetLastError());
  108. scu::AutoArrayPtr<BYTE> aapEncoded(new BYTE[cbEncoded]);
  109. ok = CryptEncodeObject(CRYPT_ASN_ENCODING, X509_ENHANCED_KEY_USAGE, &EnKeyUsage,aapEncoded.Get(), &cbEncoded);
  110. if(!ok)
  111. throw scu::OsException(GetLastError());
  112. DataBlob.pbData = aapEncoded.Get();
  113. DataBlob.cbData = cbEncoded;
  114. ok = CertSetCertificateContextProperty(pCertContext, CERT_ENHKEY_USAGE_PROP_ID,0,&DataBlob);
  115. if(!ok)
  116. throw scu::OsException(GetLastError());
  117. // Set a friendly name. If it is not specified, try to derive one
  118. string strFN;
  119. if(strFriendlyName.size())
  120. strFN = strFriendlyName;
  121. else
  122. strFN = FriendlyName(strCert);
  123. if(strFN.size()) {
  124. scu::AutoArrayPtr<WCHAR> aapWFriendlyName = ToWideChar(strFN);
  125. CRYPT_DATA_BLOB DataBlob;
  126. DataBlob.pbData = (BYTE*)aapWFriendlyName.Get();
  127. DataBlob.cbData = (wcslen(aapWFriendlyName.Get())+1)*sizeof(WCHAR);
  128. ok = CertSetCertificateContextProperty(pCertContext,
  129. CERT_FRIENDLY_NAME_PROP_ID,0,&DataBlob);
  130. if(!ok)
  131. throw scu::OsException(GetLastError());
  132. }
  133. // Store the certificate
  134. ok = CertAddCertificateContextToStore(m_hCertStore, pCertContext,
  135. CERT_STORE_ADD_NEW, NULL);
  136. if(!ok)
  137. {
  138. DWORD err = GetLastError();
  139. if(err!=CRYPT_E_EXISTS)
  140. throw scu::OsException(GetLastError());
  141. }
  142. }
  143. scu::AutoArrayPtr<WCHAR> CWinRegCertStore::ToWideChar(string const strChar)
  144. {
  145. int nwc = MultiByteToWideChar(CP_ACP, NULL, strChar.c_str(),-1, 0, 0);
  146. if (0 == nwc)
  147. throw scu::OsException(GetLastError());
  148. scu::AutoArrayPtr<WCHAR> aapWChar(new WCHAR[nwc]);
  149. if (0 == MultiByteToWideChar(CP_ACP, NULL, strChar.c_str(),
  150. -1, aapWChar.Get(), nwc))
  151. throw scu::OsException(GetLastError());
  152. return aapWChar;
  153. }
  154. string CWinRegCertStore::FriendlyName(string const CertValue)
  155. {
  156. string strFriendlyName;
  157. // Derive a friendly name for the certificate
  158. try
  159. {
  160. bool IsCACert = false;
  161. X509Cert X509CertObject(CertValue);
  162. try
  163. {
  164. unsigned long KeyUsage = X509CertObject.KeyUsage();
  165. if(KeyUsage & (keyCertSign | cRLSign)) IsCACert = true;
  166. }
  167. catch (...) {};
  168. if(IsCACert)
  169. {
  170. vector<string> orglist = X509CertObject.IssuerOrg();
  171. if(orglist.size()>0)
  172. strFriendlyName = orglist[0];
  173. }
  174. else
  175. {
  176. vector<string> cnlist = X509CertObject.SubjectCommonName();
  177. if(cnlist.size()>0)
  178. strFriendlyName = cnlist[0] + "'s ";
  179. vector<string> orglist = X509CertObject.IssuerOrg();
  180. if(orglist.size()>0)
  181. strFriendlyName += orglist[0] + " ";
  182. strFriendlyName += "ID";
  183. }
  184. }
  185. catch (...) {};
  186. return strFriendlyName;
  187. }