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.

312 lines
6.9 KiB

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. Abstract:
  5. History:
  6. --*/
  7. #include "precomp.h"
  8. #include <ntsecapi.h>
  9. #include <wbemcli.h>
  10. #include "msgsig.h"
  11. CSignMessage::CSignMessage() : m_bSign(FALSE), CUnk(NULL) { }
  12. CSignMessage::CSignMessage( HCRYPTKEY hKey, HCRYPTHASH hProv )
  13. : m_hKey( hKey ), m_hProv( hProv ), m_bSign( TRUE ), CUnk(NULL)
  14. {
  15. }
  16. CSignMessage::~CSignMessage()
  17. {
  18. if ( !m_bSign )
  19. {
  20. return;
  21. }
  22. CryptDestroyKey( m_hKey );
  23. CryptReleaseContext( m_hProv, 0 );
  24. }
  25. HRESULT CSignMessage::Sign( BYTE* pMsg, DWORD cMsg, BYTE* pSig, DWORD& rcSig )
  26. {
  27. BOOL bRes;
  28. HCRYPTHASH hHash;
  29. if ( !m_bSign )
  30. {
  31. rcSig = 0;
  32. return S_OK;
  33. }
  34. HMAC_INFO hmac;
  35. ZeroMemory( &hmac, sizeof(HMAC_INFO) );
  36. hmac.HashAlgid = CALG_MD5;
  37. bRes = CryptCreateHash( m_hProv, CALG_HMAC, m_hKey, 0, &hHash );
  38. if ( !bRes )
  39. {
  40. return HRESULT_FROM_WIN32( GetLastError() );
  41. }
  42. bRes = CryptSetHashParam( hHash, HP_HMAC_INFO, LPBYTE(&hmac), 0 );
  43. if ( !bRes )
  44. {
  45. return HRESULT_FROM_WIN32( GetLastError() );
  46. }
  47. bRes = CryptHashData( hHash, pMsg, cMsg, 0 );
  48. if ( !bRes )
  49. {
  50. return HRESULT_FROM_WIN32( GetLastError() );
  51. }
  52. bRes = CryptGetHashParam( hHash, HP_HASHVAL, pSig, &rcSig, 0 );
  53. if ( !bRes )
  54. {
  55. return HRESULT_FROM_WIN32( GetLastError() );
  56. }
  57. CryptDestroyHash( hHash );
  58. return S_OK;
  59. }
  60. HRESULT CSignMessage::Verify( BYTE* pMsg, DWORD cMsg, BYTE* pSig, DWORD cSig )
  61. {
  62. HRESULT hr;
  63. if ( !m_bSign )
  64. {
  65. return cSig == 0 ? S_OK : S_FALSE;
  66. }
  67. BYTE achCheckSig[256];
  68. DWORD cCheckSig = 256;
  69. hr = Sign( pMsg, cMsg, achCheckSig, cCheckSig );
  70. if ( FAILED(hr) )
  71. {
  72. return hr;
  73. }
  74. if ( cSig != cCheckSig )
  75. {
  76. return S_FALSE;
  77. }
  78. return memcmp( achCheckSig, pSig, cSig ) == 0 ? S_OK : S_FALSE;
  79. }
  80. #define PRIV_DATA_SZ 256
  81. HRESULT CSignMessage::Create( LPCWSTR wszName, CSignMessage** ppSignMsg )
  82. {
  83. BOOL bRes;
  84. HCRYPTHASH hHash;
  85. HCRYPTPROV hProv;
  86. HCRYPTKEY hKey;
  87. *ppSignMsg = NULL;
  88. //
  89. // First get OS version. If win9x, no signing will actually be done.
  90. // Only thing keeping from doing win9x is we need a place to securely
  91. // store private data. For NT, we use an LSA secret.
  92. //
  93. OSVERSIONINFO os;
  94. os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  95. bRes = GetVersionEx(&os);
  96. if ( !bRes )
  97. {
  98. return HRESULT_FROM_WIN32( GetLastError() );
  99. }
  100. if ( os.dwPlatformId != VER_PLATFORM_WIN32_NT )
  101. {
  102. *ppSignMsg = new CSignMessage();
  103. if ( *ppSignMsg == NULL )
  104. {
  105. return WBEM_E_OUT_OF_MEMORY;
  106. }
  107. (*ppSignMsg)->AddRef();
  108. return S_OK;
  109. }
  110. //
  111. // Now obtain (or create) the secret data to derive private signing key
  112. //
  113. bRes = CryptAcquireContext( &hProv,
  114. NULL,
  115. NULL,
  116. PROV_RSA_FULL,
  117. CRYPT_VERIFYCONTEXT );
  118. if ( !bRes )
  119. {
  120. return HRESULT_FROM_WIN32( GetLastError() );
  121. }
  122. //
  123. // need to create a hash object. This will be used for deriving
  124. // keys for encryption/decryption. The hash object will be initialized
  125. // with the 'secret' random bytes.
  126. //
  127. bRes = CryptCreateHash( hProv, CALG_MD5, 0, 0, &hHash );
  128. if ( !bRes )
  129. {
  130. CryptReleaseContext( hProv, 0 );
  131. return HRESULT_FROM_WIN32( GetLastError() );
  132. }
  133. //
  134. // Open lsa policy. This is where we store our 'secret' bytes.
  135. //
  136. NTSTATUS stat;
  137. PLSA_UNICODE_STRING pPrivateData;
  138. LSA_OBJECT_ATTRIBUTES ObjectAttr;
  139. LSA_HANDLE hPolicy;
  140. ZeroMemory( &ObjectAttr, sizeof(LSA_OBJECT_ATTRIBUTES) );
  141. stat = LsaOpenPolicy( NULL, &ObjectAttr, POLICY_ALL_ACCESS, &hPolicy );
  142. if ( !NT_SUCCESS(stat) )
  143. {
  144. CryptDestroyHash( hHash );
  145. CryptReleaseContext( hProv, 0 );
  146. return stat;
  147. }
  148. //
  149. // now need to get Private Data, which is just stored random bytes.
  150. //
  151. LSA_UNICODE_STRING PrivateKeyName;
  152. PrivateKeyName.Length = wcslen(wszName)*2;
  153. PrivateKeyName.MaximumLength = PrivateKeyName.Length + 2;
  154. PrivateKeyName.Buffer = (WCHAR*)wszName;
  155. stat = LsaRetrievePrivateData( hPolicy,
  156. &PrivateKeyName,
  157. &pPrivateData );
  158. if ( NT_SUCCESS(stat) )
  159. {
  160. //
  161. // we've obtained the private data, fill the hash obj with it.
  162. //
  163. bRes = CryptHashData( hHash,
  164. PBYTE(pPrivateData->Buffer),
  165. pPrivateData->Length,
  166. 0 );
  167. if ( !bRes )
  168. {
  169. stat = GetLastError();
  170. }
  171. ZeroMemory( PBYTE(pPrivateData->Buffer), pPrivateData->Length );
  172. LsaFreeMemory( pPrivateData );
  173. }
  174. else if ( stat == STATUS_OBJECT_NAME_NOT_FOUND )
  175. {
  176. BYTE achPrivateData[PRIV_DATA_SZ];
  177. //
  178. // generate the private data and fill the hash obj with it.
  179. //
  180. if ( CryptGenRandom( hProv, PRIV_DATA_SZ, achPrivateData ) )
  181. {
  182. if ( CryptHashData( hHash, achPrivateData, PRIV_DATA_SZ, 0 ) )
  183. {
  184. //
  185. // now store the randomly generated bytes as private data ...
  186. //
  187. LSA_UNICODE_STRING PrivateData;
  188. PrivateData.Length = PRIV_DATA_SZ;
  189. PrivateData.MaximumLength = PRIV_DATA_SZ;
  190. PrivateData.Buffer = (WCHAR*)achPrivateData;
  191. stat = LsaStorePrivateData( hPolicy,
  192. &PrivateKeyName,
  193. &PrivateData );
  194. ZeroMemory( achPrivateData, sizeof(achPrivateData) );
  195. }
  196. else
  197. {
  198. stat = GetLastError();
  199. }
  200. }
  201. else
  202. {
  203. stat = GetLastError();
  204. }
  205. }
  206. LsaClose( hPolicy );
  207. if ( !NT_SUCCESS(stat) )
  208. {
  209. CryptDestroyHash( hHash );
  210. CryptReleaseContext( hProv, 0 );
  211. return HRESULT_FROM_WIN32( stat );
  212. }
  213. //
  214. // now derive the key from the hash object. for MAC, key must use
  215. // RC2 with a CBC mode (default for RC2).
  216. //
  217. bRes = CryptDeriveKey( hProv, CALG_RC2, hHash, 0, &hKey );
  218. CryptDestroyHash( hHash );
  219. if ( !bRes )
  220. {
  221. CryptReleaseContext( hProv, 0 );
  222. return HRESULT_FROM_WIN32( GetLastError() );
  223. }
  224. //
  225. // we have successfully derived our private signing key.
  226. //
  227. *ppSignMsg = new CSignMessage( hKey, hProv );
  228. if ( *ppSignMsg == NULL )
  229. {
  230. return WBEM_E_OUT_OF_MEMORY;
  231. }
  232. (*ppSignMsg)->AddRef();
  233. return S_OK;
  234. }