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.

1103 lines
36 KiB

  1. #include "pch.hxx"
  2. #include "demand.h"
  3. #include <shlwapi.h>
  4. #include "resource.h"
  5. #include "dllmain.h"
  6. #ifdef WIN16
  7. #define CRYPT_ACQUIRE_CONTEXT CryptAcquireContextA
  8. #else
  9. #define CRYPT_ACQUIRE_CONTEXT CryptAcquireContextW
  10. #endif
  11. ////////////////////////////////////////////////////////////////////////////////
  12. const BYTE RgbRc2_40bit[] = {0x2, 0x01, 40};
  13. const BYTE RgbRc2_64bit[] = {0x2, 0x01, 64};
  14. const BYTE RgbRc2_128bit[] = {0x2, 0x02, 0, 128};
  15. const char SzRc2_128[] = "RC2 (128-bit)";
  16. const char SzRc2_64[] = "RC2 (64-bit)";
  17. const char SzRc2_40[] = "RC2 (40-bit)";
  18. const char SzRc2[] = "RC2";
  19. const char SzDES[] = "DES";
  20. const char Sz3DES[] = "3DES";
  21. const char SzSHA1[] = "SHA1";
  22. const char SzSHA_1[] = "SHA-1";
  23. const char SzMD5[] = "MD5";
  24. const char SzSkipjack[] = "SKIPJACK";
  25. static char RgchUnknown[256];
  26. static char Rgch[256];
  27. // encryption bits
  28. const DWORD cdwBits_3DES = 3 * 56;
  29. const DWORD cdwBits_RC2_128bit = 128;
  30. const DWORD cdwBits_RC2_64bit = 64;
  31. const DWORD cdwBits_DES = 56;
  32. const DWORD cdwBits_RC2_40bit = 40;
  33. // signing
  34. const DWORD cdwBits_SHA1RSA = 160;
  35. const DWORD cdwBits_OIWSEC_sha1 = 160;
  36. const DWORD cdwBits_MD5 = 128;
  37. #define flEncryption 1
  38. #define flSigning 2
  39. #define flOther 3
  40. struct {
  41. DWORD dwFlags;
  42. char * pszObjId; // OID for the alg
  43. DWORD cbData; // size of parameters
  44. const BYTE * pbData;
  45. DWORD dwBits; // size in bits
  46. const char * szCSPAlgName;
  47. const char * szAlgName; // Name of algorithm
  48. } const RgAlgsDesc[] = {
  49. {flEncryption, szOID_RSA_DES_EDE3_CBC, 0, NULL,
  50. cdwBits_3DES, Sz3DES, Sz3DES},
  51. {flEncryption, szOID_RSA_RC2CBC, sizeof(RgbRc2_128bit), RgbRc2_128bit,
  52. cdwBits_RC2_128bit, SzRc2, SzRc2_128},
  53. {flEncryption, szOID_RSA_RC2CBC, sizeof(RgbRc2_64bit), RgbRc2_64bit,
  54. cdwBits_RC2_64bit, SzRc2, SzRc2_64},
  55. {flEncryption, szOID_OIWSEC_desCBC, 0, NULL,
  56. cdwBits_DES, SzDES, SzDES},
  57. {flEncryption, szOID_RSA_RC2CBC, sizeof(RgbRc2_40bit), RgbRc2_40bit,
  58. cdwBits_RC2_40bit, SzRc2, SzRc2_40},
  59. {flEncryption, szOID_INFOSEC_mosaicConfidentiality, 0, NULL,
  60. 80, SzSkipjack, SzSkipjack},
  61. {flSigning, szOID_OIWSEC_sha1, 0, NULL,
  62. cdwBits_OIWSEC_sha1,SzSHA_1, SzSHA1},
  63. {flSigning, szOID_RSA_MD5, 0, NULL,
  64. cdwBits_MD5, SzMD5, SzMD5},
  65. {flOther, szOID_RSA_preferSignedData, 0, NULL,
  66. 0, NULL, NULL}
  67. };
  68. const DWORD CEncAlgs = sizeof(RgAlgsDesc)/sizeof(RgAlgsDesc[0]);
  69. const int ISignDef = 5; // Must be updated whend RgAlgsDesc modified
  70. const int IRC240 = 4;
  71. HRESULT GetAlgorithmsFromCert(PCCERT_CONTEXT pcCert, BOOL * rgfShow, ULONG CEncAlgs) {
  72. HCRYPTPROV hprov;
  73. PCRYPT_KEY_PROV_INFO pkeyinfo = NULL;
  74. LPWSTR pwszContainer = NULL;
  75. LPWSTR pwszProvName = NULL; // use default provider
  76. DWORD dwProvType = PROV_RSA_FULL;
  77. HRESULT hr = S_OK;
  78. ULONG f;
  79. BOOL fRetried = FALSE;
  80. ULONG i2;
  81. ULONG cb;
  82. if (pcCert) {
  83. cb = 0;
  84. f = CertGetCertificateContextProperty(pcCert, CERT_KEY_PROV_INFO_PROP_ID, NULL, &cb);
  85. if (cb) {
  86. if (!MemAlloc((LPVOID *) &pkeyinfo, cb)) {
  87. hr = E_OUTOFMEMORY;
  88. goto err;
  89. }
  90. f = CertGetCertificateContextProperty(pcCert, CERT_KEY_PROV_INFO_PROP_ID, pkeyinfo, &cb);
  91. Assert(f);
  92. pwszProvName = pkeyinfo->pwszProvName;
  93. dwProvType = pkeyinfo->dwProvType;
  94. pwszContainer = pkeyinfo->pwszContainerName;
  95. } // else cert doesn't specify provider. Use default provider.
  96. } // else use default provider
  97. TryEnhanced:
  98. f = CRYPT_ACQUIRE_CONTEXT(&hprov, pwszContainer, pwszProvName, dwProvType, 0);
  99. #ifdef DEBUG
  100. {
  101. DWORD dw = GetLastError();
  102. }
  103. #endif // DEBUG
  104. if (f) {
  105. DWORD cbMax;
  106. PROV_ENUMALGS * pbData = NULL;
  107. cbMax = 0;
  108. CryptGetProvParam(hprov, PP_ENUMALGS, NULL, &cbMax, CRYPT_FIRST);
  109. if ((cbMax == 0) || !MemAlloc((LPVOID *) &pbData, cbMax)) {
  110. hr = E_OUTOFMEMORY;
  111. goto err;
  112. }
  113. cb = cbMax;
  114. f = CryptGetProvParam(hprov, PP_ENUMALGS, (LPBYTE)pbData, &cb, CRYPT_FIRST);
  115. Assert(f);
  116. do {
  117. for (i2 = 0; i2 < CEncAlgs - 1; i2++) {
  118. if ((strcmp(pbData->szName, RgAlgsDesc[i2].szCSPAlgName) == 0) &&
  119. (pbData->dwBitLen == RgAlgsDesc[i2].dwBits)) {
  120. rgfShow[i2] = TRUE;
  121. break;
  122. }
  123. }
  124. cb = cbMax;
  125. f = CryptGetProvParam(hprov, PP_ENUMALGS, (LPBYTE) pbData, &cb, 0);
  126. } while (f);
  127. CryptReleaseContext(hprov, 0);
  128. SafeMemFree(pbData);
  129. //
  130. // Some providers are really crazy, they have a base and an enhanced provider
  131. // and these providers do not do the same set of algorithms. THis means
  132. // that we need to enumerate all of the different algorithms when we
  133. // are looking at these providers. We have the "exhaustive" set of
  134. // providers at this point in time.
  135. //
  136. if (!fRetried) {
  137. fRetried = TRUE;
  138. #ifndef WIN16
  139. if (! pwszProvName || (StrCmpW(pwszProvName, MS_DEF_PROV_W) == NULL)) {
  140. pwszProvName = MS_ENHANCED_PROV_W;
  141. goto TryEnhanced;
  142. }
  143. if (StrCmpW(pwszProvName, MS_DEF_DSS_DH_PROV_W) == 0) {
  144. pwszProvName = MS_ENH_DSS_DH_PROV_W;
  145. goto TryEnhanced;
  146. }
  147. if (StrCmpW(pwszProvName, MS_ENHANCED_PROV_W) == NULL) {
  148. pwszProvName = MS_DEF_PROV_W;
  149. goto TryEnhanced;
  150. }
  151. if (StrCmpW(pwszProvName, MS_ENH_DSS_DH_PROV_W) == NULL) {
  152. pwszProvName = MS_DEF_DSS_DH_PROV_W;
  153. goto TryEnhanced;
  154. }
  155. #else
  156. if (! pwszProvName || (wcscmp(pwszProvName, MS_DEF_PROV_A) == NULL)) {
  157. pwszProvName = MS_ENHANCED_PROV_A;
  158. goto TryEnhanced;
  159. }
  160. #endif
  161. }
  162. }
  163. SafeMemFree(pkeyinfo);
  164. //
  165. // If we are looking at diffie-hellman certificates, then we must remove DES
  166. // from the list as there is no support in the core code.
  167. //
  168. if (dwProvType == PROV_DSS_DH) {
  169. for (i2=0; i2<CEncAlgs; i2++) {
  170. if (RgAlgsDesc[i2].pszObjId == SzDES) {
  171. rgfShow[i2] = FALSE;
  172. break;
  173. }
  174. }
  175. }
  176. err:
  177. return(hr);
  178. }
  179. MIMEOLEAPI MimeOleSMimeCapsToDlg(LPBYTE pbSymCaps, DWORD cbSymCaps, DWORD cCerts,
  180. PCCERT_CONTEXT * rgCerts, HWND hwnd, DWORD idEncAlgs,
  181. DWORD idSignAlgs, DWORD idBlob)
  182. {
  183. DWORD cb;
  184. BOOL f;
  185. HRESULT hr = E_FAIL;
  186. DWORD i;
  187. WPARAM j;
  188. int iSignDef = -1;
  189. int iEncDef = -1;
  190. DWORD i2;
  191. PCRYPT_SMIME_CAPABILITIES pcaps = NULL;
  192. CHAR rgch[100];
  193. BOOL rgfShow[CEncAlgs] = {0};
  194. if (cbSymCaps != 0) {
  195. if ((hr = HrDecodeObject(pbSymCaps, cbSymCaps, PKCS_SMIME_CAPABILITIES,
  196. CRYPT_DECODE_NOCOPY_FLAG, &cb, (LPVOID *)&pcaps)) || ! pcaps) {
  197. goto err;
  198. }
  199. Assert(pcaps);
  200. //
  201. // Filter the list of capabilities passed in by the list of items that
  202. // we already know about. We don't display algorithms that we don't
  203. // recognize.
  204. //
  205. for (i=0; i<pcaps->cCapability; i++) {
  206. for (i2=0; i2<CEncAlgs; i2++) {
  207. if ((strcmp(pcaps->rgCapability[i].pszObjId,
  208. RgAlgsDesc[i2].pszObjId) == 0) &&
  209. (pcaps->rgCapability[i].Parameters.cbData ==
  210. RgAlgsDesc[i2].cbData) &&
  211. (memcmp(pcaps->rgCapability[i].Parameters.pbData,
  212. RgAlgsDesc[i2].pbData, RgAlgsDesc[i2].cbData) == 0)) {
  213. rgfShow[i2] = TRUE;
  214. if ((RgAlgsDesc[i2].dwFlags == flEncryption) && (iEncDef == -1)) {
  215. iEncDef = i2;
  216. }
  217. else if ((RgAlgsDesc[i2].dwFlags == flSigning) && (iSignDef == -1)) {
  218. iSignDef = i2;
  219. }
  220. break;
  221. }
  222. }
  223. if (i2 == CEncAlgs) {
  224. pcaps->rgCapability[i].pszObjId = NULL;
  225. }
  226. }
  227. }
  228. //
  229. // For each certificate, we now want to find the list of capabilities
  230. // provided by each of the CSP providers
  231. //
  232. for (i = 0; i < cCerts; i++) {
  233. hr = GetAlgorithmsFromCert(rgCerts[i], rgfShow, CEncAlgs);
  234. }
  235. // If there were no cert, get the algorithms from the default provider.
  236. if (! cCerts) {
  237. hr = GetAlgorithmsFromCert(NULL, rgfShow, CEncAlgs);
  238. }
  239. //
  240. // Now populate the combo box with the encryption algrithms if we have
  241. // a possiblity todo this.
  242. //
  243. if (idEncAlgs != 0) {
  244. SendDlgItemMessageA(hwnd, idEncAlgs, CB_RESETCONTENT, 0, 0);
  245. for (i=0; i<CEncAlgs; i++) {
  246. if (rgfShow[i] && (RgAlgsDesc[i].dwFlags == flEncryption)) {
  247. j = SendDlgItemMessageA(hwnd, idEncAlgs, CB_ADDSTRING,
  248. 0, (LPARAM) RgAlgsDesc[i].szAlgName);
  249. SendDlgItemMessageA(hwnd, idEncAlgs, CB_SETITEMDATA, j, i);
  250. if (iEncDef == -1) {
  251. iEncDef = i;
  252. }
  253. }
  254. }
  255. if (iEncDef != (DWORD)-1) {
  256. SendDlgItemMessageA(hwnd, idEncAlgs, CB_SELECTSTRING,
  257. (WPARAM) -1, (LPARAM) RgAlgsDesc[iEncDef].szAlgName);
  258. }
  259. }
  260. //
  261. // Now populate the Signature Alg combo box
  262. //
  263. if (idSignAlgs != 0) {
  264. SendDlgItemMessageA(hwnd, idSignAlgs, CB_RESETCONTENT, 0, 0);
  265. for (i=0; i<CEncAlgs; i++) {
  266. if (rgfShow[i] && (RgAlgsDesc[i].dwFlags == flSigning)) {
  267. j = SendDlgItemMessageA(hwnd, idSignAlgs, CB_ADDSTRING,
  268. 0, (LPARAM) RgAlgsDesc[i].szAlgName);
  269. SendDlgItemMessageA(hwnd, idSignAlgs, CB_SETITEMDATA, j, i);
  270. if (iSignDef == -1) {
  271. iSignDef = i;
  272. }
  273. }
  274. }
  275. if (iSignDef != (DWORD)-1) {
  276. SendDlgItemMessageA(hwnd, idSignAlgs, CB_SELECTSTRING,
  277. (WPARAM) -1, (LPARAM) RgAlgsDesc[iSignDef].szAlgName);
  278. }
  279. }
  280. //
  281. // Finally, lets play with the question of perference for signed blob data
  282. //
  283. if (idBlob != 0) {
  284. SendDlgItemMessageA(hwnd, idBlob, BM_SETCHECK, rgfShow[CEncAlgs-1], 0);
  285. }
  286. hr = S_OK;
  287. err:
  288. SafeMemFree(pcaps);
  289. return hr;
  290. }
  291. MIMEOLEAPI MimeOleSMimeCapsFromDlg(HWND hwnd, DWORD idEncAlgs, DWORD idSignAlgs,
  292. DWORD idBlob, LPBYTE pbSymCaps, DWORD * pcbSymCaps)
  293. {
  294. DWORD c;
  295. CRYPT_SMIME_CAPABILITIES caps;
  296. BOOL f;
  297. int fBlob = FALSE;
  298. DWORD i;
  299. DWORD i1;
  300. DWORD j;
  301. DWORD iEncDef = (DWORD) -1;
  302. DWORD iSignDef = (DWORD) -1;
  303. CRYPT_SMIME_CAPABILITY rgcaps[CEncAlgs];
  304. BOOL rgfShow[CEncAlgs] = {0};
  305. //
  306. // If we were passed a combo box for the encryption alg, then we pull
  307. // the default information out of it.
  308. //
  309. // Additionally we are going to pull out information about which algs
  310. // are currently supported by the CSPs involved in the process. This
  311. // will have been populated from a previous call to SymCapsToDlg
  312. //
  313. if (idEncAlgs != 0) {
  314. i = (DWORD) SendDlgItemMessageA(hwnd, idEncAlgs, CB_GETCURSEL, 0, 0);
  315. iEncDef = (DWORD) SendDlgItemMessageA(hwnd, idEncAlgs, CB_GETITEMDATA, i, 0);
  316. c = (DWORD) SendDlgItemMessageA(hwnd, idEncAlgs, CB_GETCOUNT, 0, 0);
  317. for (i=0; i<c; i++) {
  318. i1 = (DWORD) SendDlgItemMessageA(hwnd, idEncAlgs, CB_GETITEMDATA, i, 0);
  319. if (i1 < CEncAlgs) {
  320. rgfShow[i1] = TRUE;
  321. }
  322. }
  323. }
  324. //
  325. // If we were passed a combo box for the signing algs, then we pull the
  326. // default information out of it.
  327. //
  328. // Additionally, we are going to pull out information about which algs
  329. // are currently supported by the CSPs involved in the in process. This
  330. // will have been populated from a previous call to SymCapsToDlg.
  331. //
  332. if (idSignAlgs != 0) {
  333. i = (DWORD) SendDlgItemMessageA(hwnd, idSignAlgs, CB_GETCURSEL, 0, 0);
  334. iSignDef = (DWORD) SendDlgItemMessageA(hwnd, idSignAlgs, CB_GETITEMDATA, i, 0);
  335. c = (DWORD) SendDlgItemMessageA(hwnd, idSignAlgs, CB_GETCOUNT, 0, 0);
  336. for (i=0; i<c; i++) {
  337. i1 = (DWORD) SendDlgItemMessageA(hwnd, idSignAlgs, CB_GETITEMDATA, i, 0);
  338. if (i1 < CEncAlgs) {
  339. rgfShow[i1] = TRUE;
  340. }
  341. }
  342. }
  343. j = 0;
  344. if (idEncAlgs != 0) {
  345. //
  346. // If we have a default encryuption alg, then put it first
  347. //
  348. if (iEncDef != -1) {
  349. rgcaps[j].pszObjId = RgAlgsDesc[iEncDef].pszObjId;
  350. rgcaps[j].Parameters.cbData = RgAlgsDesc[iEncDef].cbData;
  351. rgcaps[j].Parameters.pbData = (LPBYTE) RgAlgsDesc[iEncDef].pbData;
  352. j += 1;
  353. }
  354. //
  355. // We need to build the list of encryption algs supported, if we have
  356. // a dialog box item, then use that to build the list.
  357. //
  358. for (i=0; i<CEncAlgs; i++) {
  359. if (rgfShow[i] && (RgAlgsDesc[i].dwFlags == flEncryption) && (iEncDef != i)) {
  360. rgcaps[j].pszObjId = RgAlgsDesc[i].pszObjId;
  361. rgcaps[j].Parameters.cbData = RgAlgsDesc[i].cbData;
  362. rgcaps[j].Parameters.pbData = (LPBYTE) RgAlgsDesc[i].pbData;
  363. j += 1;
  364. }
  365. }
  366. }
  367. else {
  368. //
  369. // No dialog, so we are just going to assume that only 40-bit RC2 is
  370. // supported
  371. //
  372. rgcaps[j].pszObjId = szOID_RSA_RC2CBC;
  373. rgcaps[j].Parameters.cbData = sizeof(RgbRc2_40bit);
  374. rgcaps[j].Parameters.pbData = (LPBYTE) RgbRc2_40bit;
  375. j += 1;
  376. }
  377. if (idSignAlgs != 0) {
  378. if (iSignDef != -1) {
  379. rgcaps[j].pszObjId = RgAlgsDesc[iSignDef].pszObjId;
  380. rgcaps[j].Parameters.cbData = RgAlgsDesc[iSignDef].cbData;
  381. rgcaps[j].Parameters.pbData = (LPBYTE) RgAlgsDesc[iSignDef].pbData;
  382. j += 1;
  383. }
  384. for (i=0; i<CEncAlgs; i++) {
  385. if (rgfShow[i] && (RgAlgsDesc[i].dwFlags == flSigning) && (iSignDef != i)) {
  386. rgcaps[j].pszObjId = RgAlgsDesc[i].pszObjId;
  387. rgcaps[j].Parameters.cbData = RgAlgsDesc[i].cbData;
  388. rgcaps[j].Parameters.pbData = (LPBYTE) RgAlgsDesc[i].pbData;
  389. j += 1;
  390. }
  391. }
  392. }
  393. else {
  394. //
  395. // No dialog, so we are just going to assume that only SHA-1 is
  396. // supported
  397. //
  398. rgcaps[j].pszObjId = szOID_OIWSEC_sha1RSASign;
  399. rgcaps[j].Parameters.cbData = 0;
  400. rgcaps[j].Parameters.pbData = NULL;
  401. j += 1;
  402. }
  403. //
  404. // If we were passed in an ID blob item, then we should see if we are
  405. // going to force a send in blob format
  406. //
  407. if (idBlob != 0) {
  408. if (SendDlgItemMessageA(hwnd, idBlob, BM_GETCHECK, 0, 0) == 1) {
  409. rgcaps[j].pszObjId = RgAlgsDesc[CEncAlgs-1].pszObjId;
  410. rgcaps[j].Parameters.cbData = RgAlgsDesc[CEncAlgs-1].cbData;
  411. rgcaps[j].Parameters.pbData = (LPBYTE) RgAlgsDesc[CEncAlgs-1].pbData;
  412. j += 1;
  413. }
  414. }
  415. //
  416. // Now actually encrypt the data and return the result. Note that we
  417. // don't allocate space but use the space allocated by our caller
  418. //
  419. caps.cCapability = j;
  420. caps.rgCapability = rgcaps;
  421. f = CryptEncodeObject(X509_ASN_ENCODING, PKCS_SMIME_CAPABILITIES,
  422. &caps, pbSymCaps, pcbSymCaps);
  423. return f ? S_OK : E_FAIL;
  424. }
  425. static HRESULT SymCapAdd(LPBYTE pbSymCaps, DWORD cbSymCaps, BYTE * rgbFilter)
  426. {
  427. DWORD cb;
  428. BOOL f;
  429. HRESULT hr;
  430. DWORD i;
  431. DWORD i2;
  432. PCRYPT_SMIME_CAPABILITIES pcaps = NULL;
  433. //
  434. // Take the sym caps and decode it
  435. //
  436. if ((hr = HrDecodeObject(pbSymCaps, cbSymCaps, PKCS_SMIME_CAPABILITIES,
  437. CRYPT_DECODE_NOCOPY_FLAG, &cb, (LPVOID *)&pcaps)) || ! pcaps) {
  438. goto err;
  439. }
  440. Assert(pcaps);
  441. //
  442. // Filter the list of capabilities passed in by the list of items that
  443. // are on the list.
  444. //
  445. for (i2=0, f = TRUE; i2<CEncAlgs; i2++) {
  446. if (rgbFilter[i2] == FALSE) {
  447. f = FALSE;
  448. continue;
  449. }
  450. for (i=0; i<pcaps->cCapability; i++) {
  451. if ((strcmp(pcaps->rgCapability[i].pszObjId,
  452. RgAlgsDesc[i2].pszObjId) == 0) &&
  453. (pcaps->rgCapability[i].Parameters.cbData ==
  454. RgAlgsDesc[i2].cbData) &&
  455. (memcmp(pcaps->rgCapability[i].Parameters.pbData,
  456. RgAlgsDesc[i2].pbData, RgAlgsDesc[i2].cbData) == 0)) {
  457. break;
  458. }
  459. }
  460. if (i == pcaps->cCapability) {
  461. rgbFilter[i2] = FALSE;
  462. f = FALSE;
  463. }
  464. }
  465. hr = f ? S_OK : S_FALSE;
  466. err:
  467. SafeMemFree(pcaps);
  468. return hr;
  469. }
  470. //// SymCapInit
  471. //
  472. MIMEOLEAPI MimeOleSMimeCapInit(LPBYTE pbSymCapSender, DWORD cbSymCapSender, LPVOID * ppv)
  473. {
  474. HRESULT hr = S_OK;
  475. DWORD i;
  476. LPBYTE pb = NULL;
  477. if (!MemAlloc((LPVOID *) &pb, CEncAlgs * sizeof(BYTE))) {
  478. return E_OUTOFMEMORY;
  479. }
  480. if (pbSymCapSender && cbSymCapSender) {
  481. for (i=0; i<CEncAlgs; i++) pb[i] = TRUE;
  482. hr = SymCapAdd(pbSymCapSender, cbSymCapSender, pb);
  483. if (FAILED(hr)) {
  484. MemFree(pb);
  485. goto exit;
  486. }
  487. // Assert(hr == S_OK);
  488. } else {
  489. HCRYPTPROV hprov = NULL;
  490. LPTSTR pszProvName = NULL; // use default provider
  491. DWORD dwProvType = PROV_RSA_FULL;
  492. BOOL f;
  493. ULONG cb;
  494. // No sender symcap specified. Init it to the highest available.
  495. for (i = 0; i < CEncAlgs; i++) { // init to all false
  496. pb[i] = FALSE;
  497. }
  498. TryEnhanced:
  499. // Open the provider
  500. hr = E_OUTOFMEMORY;
  501. f = CryptAcquireContext(&hprov, NULL, pszProvName, dwProvType, CRYPT_VERIFYCONTEXT);
  502. if (f) {
  503. DWORD cbMax;
  504. PROV_ENUMALGS * pbData = NULL;
  505. hr = S_OK;
  506. cbMax = 0;
  507. CryptGetProvParam(hprov, PP_ENUMALGS, NULL, &cbMax, CRYPT_FIRST);
  508. if ((cbMax == 0) || ! MemAlloc((LPVOID *)&pbData, cbMax)) {
  509. hr = E_OUTOFMEMORY;
  510. goto exit;
  511. }
  512. cb = cbMax;
  513. f = CryptGetProvParam(hprov, PP_ENUMALGS, (LPBYTE)pbData, &cb, CRYPT_FIRST);
  514. Assert(f);
  515. do {
  516. // Walk through the list of all known S/MIME caps looking to see if we
  517. // have a match.
  518. for (i = 0; i < CEncAlgs; i++) {
  519. // Assume if we get the correct algorithm name, that the CAPI
  520. // bitLen parameter is a max value and we will support all smaller ones
  521. // as well.
  522. if (lstrcmpi(pbData->szName, RgAlgsDesc[i].szCSPAlgName) == 0) {
  523. if (pbData->dwBitLen >= RgAlgsDesc[i].dwBits) {
  524. pb[i] = TRUE; // We support this one
  525. }
  526. }
  527. }
  528. cb = cbMax;
  529. f = CryptGetProvParam(hprov, PP_ENUMALGS, (LPBYTE)pbData, &cb, 0);
  530. } while (f);
  531. CryptReleaseContext(hprov, 0);
  532. SafeMemFree(pbData);
  533. // Try the enhanced provider?
  534. if (! pszProvName || (lstrcmpi(pszProvName, MS_DEF_PROV) == NULL)) {
  535. pszProvName = MS_ENHANCED_PROV;
  536. goto TryEnhanced;
  537. }
  538. }
  539. }
  540. *ppv = pb;
  541. exit:
  542. return(hr);
  543. }
  544. MIMEOLEAPI MimeOleSMimeCapAddSMimeCap(LPBYTE pbSymCap, DWORD cbSymCap, LPVOID pv)
  545. {
  546. if ((pbSymCap != NULL) && (cbSymCap > 0)) {
  547. return SymCapAdd(pbSymCap, cbSymCap, (LPBYTE) pv);
  548. }
  549. return E_INVALIDARG;
  550. }
  551. MIMEOLEAPI MimeOleSMimeCapAddCert(LPBYTE /*pbCert*/, DWORD /*cbCert*/,
  552. BOOL fParanoid, LPVOID pv)
  553. {
  554. BOOL f;
  555. DWORD i;
  556. DWORD iSkip;
  557. LPBYTE pb = (LPBYTE) pv;
  558. //
  559. // If we are paranoid, then we only allow 3-DES
  560. // Otherwise we only allow RC2 40-bit
  561. //
  562. if (fParanoid) {
  563. iSkip = 0;
  564. }
  565. else {
  566. iSkip = IRC240;
  567. }
  568. for (i=0, f = TRUE; i<CEncAlgs; i++) {
  569. if ((i != iSkip) && (RgAlgsDesc[i].dwFlags == flEncryption)) {
  570. pb[i] &= 0;
  571. f = pb[i];
  572. }
  573. }
  574. return f ? S_OK : S_FALSE;
  575. }
  576. HRESULT GetResult(DWORD iTarget, LPBYTE pb, LPBYTE pbEncode, DWORD * pcbEncode,
  577. DWORD * pdw)
  578. {
  579. CRYPT_SMIME_CAPABILITY cap;
  580. CRYPT_SMIME_CAPABILITIES caps;
  581. BOOL f = FALSE;
  582. int i;
  583. //
  584. // Look for the first possible answer to the question
  585. //
  586. for (i=0; i<CEncAlgs; i++) {
  587. if (RgAlgsDesc[i].dwFlags == iTarget) {
  588. break;
  589. }
  590. }
  591. Assert(i != CEncAlgs);
  592. //
  593. // Look for the highest possible alg to send data with
  594. //
  595. for (; i<CEncAlgs; i++) {
  596. if ((RgAlgsDesc[i].dwFlags != iTarget) || pb[i]) {
  597. break;
  598. }
  599. }
  600. //
  601. // We must not have run off the end of the array, all hash algs come after encryption
  602. // algs
  603. //
  604. Assert( i < CEncAlgs );
  605. //
  606. // If did not find an algorithm, return the appropriate error
  607. //
  608. if (RgAlgsDesc[i].dwFlags != iTarget) {
  609. *pcbEncode = 0;
  610. if (pdw != NULL) {
  611. *pdw = 0;
  612. }
  613. return S_FALSE;
  614. }
  615. //
  616. // Build the S/MIME Capability string with just this one item in it
  617. //
  618. caps.cCapability = 1;
  619. caps.rgCapability = &cap;
  620. cap.pszObjId = RgAlgsDesc[i].pszObjId;
  621. cap.Parameters.cbData = RgAlgsDesc[i].cbData;
  622. cap.Parameters.pbData = (LPBYTE)RgAlgsDesc[i].pbData;
  623. //
  624. // Determine the "extra" parameter. For encryption it is the
  625. // bit size of the algorithm. For Signing it is weither we should be doing
  626. // blob signed
  627. //
  628. if (pdw != NULL) {
  629. if (iTarget == 1) {
  630. *pdw = RgAlgsDesc[i].dwBits;
  631. }
  632. else {
  633. Assert(iTarget == 2);
  634. *pdw = pb[CEncAlgs-1];
  635. }
  636. }
  637. f = CryptEncodeObject(X509_ASN_ENCODING, PKCS_SMIME_CAPABILITIES,
  638. &caps, pbEncode, pcbEncode);
  639. #ifndef WIN16
  640. if (!f && (::GetLastError() != ERROR_MORE_DATA)) {
  641. return E_FAIL;
  642. }
  643. #endif
  644. return f ? S_OK : S_FALSE;
  645. }
  646. MIMEOLEAPI MimeOleSMimeCapGetEncAlg(LPVOID pv, LPBYTE pbEncode, DWORD * pcbEncode,
  647. DWORD * pdwBits)
  648. {
  649. return GetResult(1, (LPBYTE) pv, pbEncode, pcbEncode, pdwBits);
  650. }
  651. MIMEOLEAPI MimeOleSMimeCapGetHashAlg(LPVOID pv, LPBYTE pbEncode, DWORD * pcbEncode,
  652. DWORD * pfBlobSign)
  653. {
  654. return GetResult(2, (LPBYTE) pv, pbEncode, pcbEncode, pfBlobSign);
  655. }
  656. MIMEOLEAPI MimeOleSMimeCapRelease(LPVOID pv)
  657. {
  658. MemFree(pv);
  659. return S_OK;
  660. }
  661. MIMEOLEAPI MimeOleAlgNameFromSMimeCap(LPBYTE pbEncode, DWORD cbEncode,
  662. LPCSTR * ppszProtocol)
  663. {
  664. DWORD cb = 0;
  665. BOOL f;
  666. HRESULT hr;
  667. DWORD i;
  668. PCRYPT_SMIME_CAPABILITIES pcaps = NULL;
  669. //
  670. // Decode the S/MIME caps which is passed in, allocate space to hold
  671. // the resulting value
  672. //
  673. hr = HrDecodeObject(pbEncode, cbEncode, PKCS_SMIME_CAPABILITIES, CRYPT_DECODE_NOCOPY_FLAG, &cb, (LPVOID *)&pcaps);
  674. if (FAILED(hr) || NULL == pcaps)
  675. {
  676. if (hr != E_OUTOFMEMORY)
  677. {
  678. if (RgchUnknown[0] == 0)
  679. {
  680. LoadStringA(g_hLocRes, IDS_UNKNOWN_ALG, RgchUnknown, sizeof(RgchUnknown));
  681. }
  682. *ppszProtocol = RgchUnknown;
  683. return S_FALSE;
  684. }
  685. else
  686. {
  687. return E_OUTOFMEMORY;
  688. }
  689. }
  690. Assert(pcaps);
  691. Assert(pcaps->cCapability == 1);
  692. //
  693. // Walk through the list of all known S/MIME caps looking to see if we
  694. // have a match. If so then setup the return answer.
  695. //
  696. for (i=0; i<CEncAlgs; i++) {
  697. if ((strcmp(pcaps->rgCapability[0].pszObjId, RgAlgsDesc[i].pszObjId) == 0) &&
  698. (pcaps->rgCapability[0].Parameters.cbData == RgAlgsDesc[i].cbData) &&
  699. (memcmp(pcaps->rgCapability[0].Parameters.pbData,
  700. RgAlgsDesc[i].pbData, RgAlgsDesc[i].cbData) == 0)) {
  701. *ppszProtocol = RgAlgsDesc[i].szAlgName;
  702. break;
  703. }
  704. }
  705. //
  706. // We did not find a match. So now we need to assume that we might have been
  707. // passed a Parameter rather than an S/MIME cap. So try decoding as a parameter
  708. //
  709. if (i== CEncAlgs) {
  710. if (strcmp(pcaps->rgCapability[0].pszObjId, szOID_RSA_RC2CBC) == 0) {
  711. PCRYPT_RC2_CBC_PARAMETERS prc2;
  712. prc2 = (PCRYPT_RC2_CBC_PARAMETERS)
  713. PVDecodeObject(pcaps->rgCapability[0].Parameters.pbData,
  714. pcaps->rgCapability[0].Parameters.cbData,
  715. PKCS_RC2_CBC_PARAMETERS, NULL);
  716. if (prc2 != NULL) {
  717. if (prc2->dwVersion == CRYPT_RC2_40BIT_VERSION) {
  718. *ppszProtocol = SzRc2_40;
  719. }
  720. else if (prc2->dwVersion == CRYPT_RC2_64BIT_VERSION) {
  721. *ppszProtocol = SzRc2_64;
  722. }
  723. else if (prc2->dwVersion == CRYPT_RC2_128BIT_VERSION) {
  724. *ppszProtocol = SzRc2_128;
  725. }
  726. else {
  727. *ppszProtocol = SzRc2;
  728. }
  729. SafeMemFree(prc2); // Must be freed prior to pcaps
  730. }
  731. else {
  732. *ppszProtocol = SzRc2;
  733. }
  734. }
  735. else if (strcmp(pcaps->rgCapability[0].pszObjId, szOID_RSA_DES_EDE3_CBC) == 0) {
  736. *ppszProtocol = Sz3DES;
  737. }
  738. else if (strcmp(pcaps->rgCapability[0].pszObjId, szOID_OIWSEC_desCBC) == 0) {
  739. *ppszProtocol = SzDES;
  740. }
  741. else if (strcmp(pcaps->rgCapability[0].pszObjId, szOID_INFOSEC_mosaicConfidentiality) == 0) {
  742. *ppszProtocol = SzSkipjack;
  743. }
  744. else {
  745. StrCpyNA(Rgch, pcaps->rgCapability[0].pszObjId, ARRAYSIZE(Rgch));
  746. *ppszProtocol = Rgch;
  747. }
  748. MemFree(pcaps);
  749. return S_FALSE;
  750. }
  751. MemFree(pcaps);
  752. return S_OK;
  753. }
  754. MIMEOLEAPI MimeOleAlgStrengthFromSMimeCap(LPBYTE pbEncode, DWORD cbEncode, BOOL fEncryption,
  755. DWORD * pdwStrength)
  756. {
  757. DWORD cb = 0;
  758. BOOL f;
  759. HRESULT hr = S_OK;
  760. DWORD i;
  761. PCRYPT_SMIME_CAPABILITIES pcaps = NULL;
  762. // Init return value
  763. *pdwStrength = 0;
  764. if (pbEncode && cbEncode) {
  765. //
  766. // Decode the S/MIME caps which is passed in, allocate space to hold
  767. // the resulting value
  768. //
  769. if ((hr = HrDecodeObject(pbEncode, cbEncode, PKCS_SMIME_CAPABILITIES,
  770. CRYPT_DECODE_NOCOPY_FLAG, &cb, (LPVOID *)&pcaps)) || ! pcaps) {
  771. goto exit;;
  772. }
  773. Assert(pcaps);
  774. Assert(pcaps->cCapability == 1);
  775. //
  776. // Walk through the list of all known S/MIME caps looking to see if we
  777. // have a match. If so then setup the return answer.
  778. //
  779. for (i=0; i<CEncAlgs; i++) {
  780. if ((strcmp(pcaps->rgCapability[0].pszObjId, RgAlgsDesc[i].pszObjId) == 0) &&
  781. (pcaps->rgCapability[0].Parameters.cbData == RgAlgsDesc[i].cbData) &&
  782. (memcmp(pcaps->rgCapability[0].Parameters.pbData,
  783. RgAlgsDesc[i].pbData, RgAlgsDesc[i].cbData) == 0)) {
  784. *pdwStrength = RgAlgsDesc[i].dwBits;
  785. break;
  786. }
  787. }
  788. //
  789. // We did not find a match. So now we need to assume that we might have been
  790. // passed a Parameter rather than an S/MIME cap. So try decoding as a parameter
  791. //
  792. if (i== CEncAlgs) {
  793. if (strcmp(pcaps->rgCapability[0].pszObjId, szOID_RSA_RC2CBC) == 0) {
  794. PCRYPT_RC2_CBC_PARAMETERS prc2;
  795. prc2 = (PCRYPT_RC2_CBC_PARAMETERS)
  796. PVDecodeObject(pcaps->rgCapability[0].Parameters.pbData,
  797. pcaps->rgCapability[0].Parameters.cbData,
  798. PKCS_RC2_CBC_PARAMETERS, NULL);
  799. if (prc2 != NULL) {
  800. if (prc2->dwVersion == CRYPT_RC2_40BIT_VERSION) {
  801. *pdwStrength = cdwBits_RC2_40bit;
  802. }
  803. else if (prc2->dwVersion == CRYPT_RC2_64BIT_VERSION) {
  804. *pdwStrength = cdwBits_RC2_64bit;
  805. }
  806. else if (prc2->dwVersion == CRYPT_RC2_128BIT_VERSION) {
  807. *pdwStrength = cdwBits_RC2_128bit;
  808. }
  809. else {
  810. *pdwStrength = cdwBits_RC2_40bit;
  811. }
  812. SafeMemFree(prc2); // Must be freed prior to pcaps
  813. }
  814. else {
  815. *pdwStrength = cdwBits_RC2_40bit;
  816. }
  817. }
  818. else if (strcmp(pcaps->rgCapability[0].pszObjId, szOID_RSA_DES_EDE3_CBC) == 0) {
  819. *pdwStrength = cdwBits_3DES;
  820. }
  821. else if (strcmp(pcaps->rgCapability[0].pszObjId, szOID_OIWSEC_desCBC) == 0) {
  822. *pdwStrength = cdwBits_DES;
  823. }
  824. else if (strcmp(pcaps->rgCapability[0].pszObjId, szOID_INFOSEC_mosaicConfidentiality) == 0) {
  825. *pdwStrength = 80;
  826. }
  827. else {
  828. *pdwStrength = 0;
  829. }
  830. MemFree(pcaps);
  831. return S_FALSE;
  832. }
  833. MemFree(pcaps);
  834. } else {
  835. // No SMimeCap passed in, find the maximum supported by this configuration
  836. HCRYPTPROV hprov = NULL;
  837. LPTSTR pszProvName = NULL; // use default provider
  838. DWORD dwProvType = PROV_RSA_FULL;
  839. TryEnhanced:
  840. f = CryptAcquireContext(&hprov, NULL, pszProvName, dwProvType, CRYPT_VERIFYCONTEXT);
  841. if (f) {
  842. DWORD cbMax;
  843. PROV_ENUMALGS * pbData = NULL;
  844. cbMax = 0;
  845. CryptGetProvParam(hprov, PP_ENUMALGS, NULL, &cbMax, CRYPT_FIRST);
  846. if ((cbMax == 0) || ! MemAlloc((LPVOID *)&pbData, cbMax)) {
  847. hr = E_OUTOFMEMORY;
  848. goto exit;
  849. }
  850. cb = cbMax;
  851. f = CryptGetProvParam(hprov, PP_ENUMALGS, (LPBYTE)pbData, &cb, CRYPT_FIRST);
  852. Assert(f);
  853. do {
  854. // Walk through the list of all known S/MIME caps looking to see if we
  855. // have a match.
  856. for (i = 0; i < CEncAlgs; i++) {
  857. if ((RgAlgsDesc[i].dwFlags == (DWORD)(fEncryption ? flEncryption : flSigning)) && lstrcmpi(pbData->szName, RgAlgsDesc[i].szCSPAlgName) == 0) {
  858. if (pbData->dwBitLen > *pdwStrength) {
  859. *pdwStrength = pbData->dwBitLen;
  860. }
  861. }
  862. }
  863. cb = cbMax;
  864. f = CryptGetProvParam(hprov, PP_ENUMALGS, (LPBYTE)pbData, &cb, 0);
  865. } while (f);
  866. CryptReleaseContext(hprov, 0);
  867. SafeMemFree(pbData);
  868. // Try the enhanced provider?
  869. if (! pszProvName || (lstrcmpi(pszProvName, MS_DEF_PROV) == NULL)) {
  870. pszProvName = MS_ENHANCED_PROV;
  871. goto TryEnhanced;
  872. }
  873. }
  874. }
  875. exit:
  876. return(hr);
  877. }
  878. MIMEOLEAPI MimeOleSMimeCapsFull(LPVOID pv, BOOL fFullEncryption, BOOL fFullSigning, LPBYTE pbSymCaps, DWORD * pcbSymCaps)
  879. {
  880. CRYPT_SMIME_CAPABILITIES caps;
  881. BOOL f;
  882. DWORD i;
  883. DWORD j = 0;
  884. CRYPT_SMIME_CAPABILITY rgcaps[CEncAlgs];
  885. LPBYTE rgfUse = (LPBYTE)pv;
  886. //
  887. // We need to build the list of encryption algs supported, if we have
  888. // a dialog box item, then use that to build the list.
  889. //
  890. if (fFullEncryption) {
  891. for (i = 0; i < CEncAlgs; i++) {
  892. if (rgfUse[i] && (RgAlgsDesc[i].dwFlags == flEncryption)) {
  893. rgcaps[j].pszObjId = RgAlgsDesc[i].pszObjId;
  894. rgcaps[j].Parameters.cbData = RgAlgsDesc[i].cbData;
  895. rgcaps[j].Parameters.pbData = (LPBYTE)RgAlgsDesc[i].pbData;
  896. j += 1;
  897. }
  898. }
  899. } else {
  900. //
  901. // Just assume that only 40-bit RC2 is supported
  902. //
  903. rgcaps[j].pszObjId = szOID_RSA_RC2CBC;
  904. rgcaps[j].Parameters.cbData = sizeof(RgbRc2_40bit);
  905. rgcaps[j].Parameters.pbData = (LPBYTE) RgbRc2_40bit;
  906. j += 1;
  907. }
  908. //
  909. // Now, put in the signing algorithms
  910. //
  911. if (fFullSigning) {
  912. for (i = 0; i < CEncAlgs; i++) {
  913. if (rgfUse[i] && (RgAlgsDesc[i].dwFlags == flSigning)) {
  914. rgcaps[j].pszObjId = RgAlgsDesc[i].pszObjId;
  915. rgcaps[j].Parameters.cbData = RgAlgsDesc[i].cbData;
  916. rgcaps[j].Parameters.pbData = (LPBYTE)RgAlgsDesc[i].pbData;
  917. j += 1;
  918. }
  919. }
  920. } else {
  921. //
  922. // Just assume that only SHA-1 is supported
  923. //
  924. rgcaps[j].pszObjId = szOID_OIWSEC_sha1RSASign;
  925. rgcaps[j].Parameters.cbData = 0;
  926. rgcaps[j].Parameters.pbData = NULL;
  927. j += 1;
  928. }
  929. //
  930. // Now actually encrypt the data and return the result. Note that we
  931. // don't allocate space but use the space allocated by our caller
  932. //
  933. caps.cCapability = j;
  934. caps.rgCapability = rgcaps;
  935. f = CryptEncodeObject(X509_ASN_ENCODING, PKCS_SMIME_CAPABILITIES,
  936. &caps, pbSymCaps, pcbSymCaps);
  937. return(f ? S_OK : E_FAIL);
  938. }