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.

445 lines
14 KiB

  1. #ifdef SMIME_V3
  2. #include <windows.h>
  3. #include <mimeole.h>
  4. #include <essout.h>
  5. #include "badstrfunctions.h"
  6. #include "demand.h"
  7. #include "crypttls.h"
  8. #include "demand2.h"
  9. extern CRYPT_DECODE_PARA CryptDecodeAlloc;
  10. #define szOID_MSFT_ATTR_SEQUENCE "1.3.6.1.4.1.311.16.1.1"
  11. /////////////////////////////////////////////////////////////////////////
  12. typedef struct {
  13. DWORD cNames;
  14. CERT_NAME_BLOB * rgNames;
  15. } ReceiptNames;
  16. HRESULT SetNames(ReceiptNames * pnames, DWORD cNames, CERT_NAME_BLOB * rgNames)
  17. {
  18. DWORD cb;
  19. DWORD i;
  20. LPBYTE pb;
  21. if (pnames->rgNames != NULL) {
  22. free(pnames->rgNames);
  23. pnames->rgNames = NULL;
  24. pnames->cNames = 0;
  25. }
  26. for (i=0, cb=cNames*sizeof(CERT_NAME_BLOB); i<cNames; i++) {
  27. cb += rgNames[i].cbData;
  28. }
  29. pnames->rgNames = (CERT_NAME_BLOB *) malloc(cb);
  30. if (pnames->rgNames == NULL) {
  31. return E_OUTOFMEMORY;
  32. }
  33. pb = (LPBYTE) &pnames->rgNames[cNames];
  34. for (i=0; i<cNames; i++) {
  35. pnames->rgNames[i].pbData = pb;
  36. pnames->rgNames[i].cbData = rgNames[i].cbData;
  37. memcpy(pb, rgNames[i].pbData, rgNames[i].cbData);
  38. pb += rgNames[i].cbData;
  39. }
  40. pnames->cNames = cNames;
  41. return S_OK;
  42. }
  43. HRESULT MergeNames(ReceiptNames * pnames, DWORD cNames, CERT_NAME_BLOB * rgNames)
  44. {
  45. DWORD cb;
  46. DWORD i;
  47. DWORD i1;
  48. LPBYTE pb;
  49. CERT_NAME_BLOB * p;
  50. for (i=0, cb=0; i<pnames->cNames; i++) {
  51. cb += pnames->rgNames[i].cbData;
  52. }
  53. for (i=0; i<cNames; i++) {
  54. cb += rgNames[i].cbData;
  55. }
  56. p = (CERT_NAME_BLOB *) malloc(cb + (pnames->cNames + cNames) *
  57. sizeof(CERT_NAME_BLOB));
  58. if (p == NULL) {
  59. return E_OUTOFMEMORY;
  60. }
  61. pb = (LPBYTE) &p[pnames->cNames + cNames];
  62. for (i=0, i1=0; i<pnames->cNames; i++, i1++) {
  63. p[i1].pbData = pb;
  64. p[i1].cbData = pnames->rgNames[i].cbData;
  65. memcpy(pb, pnames->rgNames[i].pbData, pnames->rgNames[i].cbData);
  66. pb += pnames->rgNames[i].cbData;
  67. }
  68. for (i=0; i<pnames->cNames; i++, i1++) {
  69. p[i1].pbData = pb;
  70. p[i1].cbData = rgNames[i].cbData;
  71. memcpy(pb, rgNames[i].pbData, rgNames[i].cbData);
  72. pb += rgNames[i].cbData;
  73. }
  74. free(pnames->rgNames);
  75. pnames->rgNames = p;
  76. pnames->cNames = i1;
  77. return S_OK;
  78. }
  79. /////////////////////////////////////////////////////////////////////////
  80. MIMEOLEAPI MimeOleCreateReceipt(IMimeMessage * pMsgSrc, PCX509CERT pCertToSign,
  81. HWND hwndDlg, IMimeMessage ** ppMessage,
  82. const CERT_ALT_NAME_INFO * pMyNames)
  83. {
  84. DWORD cb;
  85. DWORD cLayers;
  86. DWORD dwReceiptsFrom;
  87. BOOL fSkipAddress = FALSE;
  88. HRESULT hr;
  89. DWORD i;
  90. DWORD i1;
  91. DWORD i2;
  92. DWORD iAttr;
  93. DWORD iLayer;
  94. PCRYPT_ATTRIBUTES pattrs = NULL;
  95. IMimeBody * pbody = NULL;
  96. LPBYTE pbReceiptReq = NULL;
  97. IMimeAddressTable * pmatbl = NULL;
  98. IMimeBody * pmb = NULL;
  99. IMimeMessage * pmm = NULL;
  100. PSMIME_RECEIPT_REQUEST preq = NULL;
  101. LPSTREAM pstm = NULL;
  102. ReceiptNames receiptsTo = {0, NULL};
  103. PROPVARIANT * rgpvAuthAttr = NULL;
  104. PROPVARIANT var;
  105. //
  106. // Get the Layer Count
  107. // Get the Authenticated Attributes
  108. // Decode Receipt Request
  109. // Set ReceiptsFrom from the request
  110. // For Each layer
  111. // is mlExpansion in this layer? No -- Skip to next layer
  112. // Receipt for First Tier only? Yes - return S_FALSE
  113. // Policy override on mlExpansion?
  114. // None - return S_FALSE
  115. // insteadOf - set ReceiptsFrom from mlExpansion History
  116. // inAdditionTo - add to ReceiptsFrom
  117. // Is my name in ReceiptsFrom list? No -- return S_FALSE
  118. // Setup new IMimeMessage
  119. // Attach receipt body
  120. // Address from Receipt Request
  121. // return S_OK
  122. // Obtain the body of the message
  123. hr = pMsgSrc->BindToObject(HBODY_ROOT, IID_IMimeBody, (LPVOID *) &pbody);
  124. if (FAILED(hr)) {
  125. goto CommonExit;
  126. }
  127. // Get the set of authenticated attributes on all layers of S/MIME in the
  128. // message.
  129. hr = pbody->GetOption(OID_SECURITY_SIGNATURE_COUNT, &var);
  130. if (FAILED(hr)) {
  131. goto GeneralFail;
  132. }
  133. cLayers = var.ulVal;
  134. hr = pbody->GetOption(OID_SECURITY_AUTHATTR_RG, &var);
  135. if (FAILED(hr)) {
  136. goto CommonExit;
  137. }
  138. rgpvAuthAttr = var.capropvar.pElems;
  139. // Create a stream object to hold the receipt and put the receipt into the
  140. // stream -- this supplies the body of the receipt message.
  141. hr = MimeOleCreateVirtualStream(&pstm);
  142. if (FAILED(hr)) {
  143. goto CommonExit;
  144. }
  145. hr = pbody->GetOption(OID_SECURITY_RECEIPT, &var);
  146. if (FAILED(hr)) {
  147. goto CommonExit;
  148. }
  149. hr = pstm->Write(var.blob.pBlobData, var.blob.cbSize, NULL);
  150. if (FAILED(hr)) {
  151. goto CommonExit;
  152. }
  153. //
  154. // Walk through each layer of authenticated attributes processing the
  155. // two relevant attributes.
  156. //
  157. for (iLayer=0; iLayer<cLayers; iLayer++) {
  158. if (rgpvAuthAttr[iLayer].blob.cbSize == 0) {
  159. continue;
  160. }
  161. //
  162. // Decode the attributes at this layer of S/MIME
  163. //
  164. if (!CryptDecodeObjectEx(X509_ASN_ENCODING, szOID_MSFT_ATTR_SEQUENCE,
  165. rgpvAuthAttr[iLayer].blob.pBlobData,
  166. rgpvAuthAttr[iLayer].blob.cbSize,
  167. CRYPT_ENCODE_ALLOC_FLAG, &CryptDecodeAlloc,
  168. &pattrs, &cb)) {
  169. goto GeneralFail;
  170. }
  171. //
  172. // Walk through each attribute looking for
  173. // if innermost layer - the receipt request
  174. // else - a Mail List expansion history
  175. //
  176. for (iAttr=0; iAttr<pattrs->cAttr; iAttr++) {
  177. if (iLayer==0) {
  178. if (strcmp(pattrs->rgAttr[iAttr].pszObjId,
  179. szOID_SMIME_Receipt_Request) == 0) {
  180. //
  181. // Crack the contents of the receipt request
  182. //
  183. if (!CryptDecodeObjectEx(X509_ASN_ENCODING,
  184. szOID_SMIME_Receipt_Request,
  185. pattrs->rgAttr[iAttr].rgValue[0].pbData,
  186. pattrs->rgAttr[iAttr].rgValue[0].cbData,
  187. CRYPT_DECODE_ALLOC_FLAG,
  188. &CryptDecodeAlloc, &preq, &cb)) {
  189. goto GeneralFail;
  190. }
  191. //
  192. // Initialize the ReceiptsTo list
  193. //
  194. if (preq->cReceiptsTo != 0) {
  195. SetNames(&receiptsTo, preq->cReceiptsTo, preq->rgReceiptsTo);
  196. }
  197. // Who are receipts from?
  198. dwReceiptsFrom = preq->ReceiptsFrom.AllOrFirstTier;
  199. }
  200. else if (strcmp(pattrs->rgAttr[iAttr].pszObjId,
  201. szOID_RSA_messageDigest) == 0) {
  202. ;
  203. }
  204. }
  205. else if ((iLayer != 0) && (strcmp(pattrs->rgAttr[iAttr].pszObjId,
  206. szOID_SMIME_MLExpansion_History) == 0)) {
  207. //
  208. // If receipts are from first tier only and we see this attribute
  209. // we are not first tier by definition.
  210. //
  211. if (dwReceiptsFrom == SMIME_RECEIPTS_FROM_FIRST_TIER) {
  212. hr = S_FALSE;
  213. goto CommonExit;
  214. }
  215. PSMIME_ML_EXPANSION_HISTORY pmlhist = NULL;
  216. //
  217. // Crack the attribute
  218. //
  219. if (!CryptDecodeObjectEx(X509_ASN_ENCODING,
  220. szOID_SMIME_MLExpansion_History,
  221. pattrs->rgAttr[iAttr].rgValue[0].pbData,
  222. pattrs->rgAttr[iAttr].rgValue[0].cbData,
  223. CRYPT_ENCODE_ALLOC_FLAG,
  224. &CryptDecodeAlloc, &pmlhist, &cb)) {
  225. goto GeneralFail;
  226. }
  227. PSMIME_MLDATA pMLData = &pmlhist->rgMLData[pmlhist->cMLData-1];
  228. switch( pMLData->dwPolicy) {
  229. // No receipt is to be returned
  230. case SMIME_MLPOLICY_NONE:
  231. hr = S_FALSE;
  232. free(pmlhist);
  233. goto CommonExit;
  234. // Return receipt to a new list
  235. case SMIME_MLPOLICY_INSTEAD_OF:
  236. SetNames(&receiptsTo, pMLData->cNames, pMLData->rgNames);
  237. break;
  238. case SMIME_MLPOLICY_IN_ADDITION_TO:
  239. MergeNames(&receiptsTo, pMLData->cNames, pMLData->rgNames);
  240. break;
  241. case SMIME_MLPOLICY_NO_CHANGE:
  242. break;
  243. default:
  244. free(pmlhist);
  245. goto GeneralFail;
  246. }
  247. free(pmlhist);
  248. break;
  249. }
  250. }
  251. free(pattrs);
  252. pattrs = NULL;
  253. }
  254. //
  255. // Am I on the ReceiptsFrom List --
  256. //
  257. if (preq->ReceiptsFrom.cNames != 0) {
  258. BOOL fFoundMe = FALSE;
  259. for (i=0; !fFoundMe && (i<preq->ReceiptsFrom.cNames); i++) {
  260. CERT_ALT_NAME_INFO * pname = NULL;
  261. if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME,
  262. preq->ReceiptsFrom.rgNames[i].pbData,
  263. preq->ReceiptsFrom.rgNames[i].cbData,
  264. CRYPT_ENCODE_ALLOC_FLAG,
  265. &CryptDecodeAlloc, &pname, &cb)) {
  266. goto GeneralFail;
  267. }
  268. for (i1=0; i1<pname->cAltEntry; i1++) {
  269. for (i2=0; i2<pMyNames->cAltEntry; i2++) {
  270. if (pname->rgAltEntry[i1].dwAltNameChoice !=
  271. pMyNames->rgAltEntry[i1].dwAltNameChoice) {
  272. continue;
  273. }
  274. switch (pname->rgAltEntry[i1].dwAltNameChoice) {
  275. case CERT_ALT_NAME_RFC822_NAME:
  276. if (lstrcmpW(pname->rgAltEntry[i1].pwszRfc822Name,
  277. pMyNames->rgAltEntry[i1].pwszRfc822Name) == 0) {
  278. fFoundMe = TRUE;
  279. goto FoundMe;
  280. }
  281. }
  282. }
  283. }
  284. FoundMe:
  285. free(pname);
  286. }
  287. if (!fFoundMe) {
  288. hr = S_FALSE;
  289. goto CommonExit;
  290. }
  291. }
  292. hr = MimeOleCreateMessage(NULL, &pmm);
  293. if (FAILED(hr)) {
  294. goto CommonExit;
  295. }
  296. hr = pmm->BindToObject(HBODY_ROOT, IID_IMimeBody, (LPVOID *) &pmb);
  297. if (FAILED(hr)) {
  298. goto CommonExit;
  299. }
  300. hr = pmb->SetData(IET_BINARY, "OID", szOID_SMIME_ContentType_Receipt,
  301. IID_IStream, pstm);
  302. if (FAILED(hr)) {
  303. goto CommonExit;
  304. }
  305. //
  306. // Address the receipt back to the receipients
  307. //
  308. hr = pmm->GetAddressTable(&pmatbl);
  309. if (FAILED(hr)) {
  310. goto CommonExit;
  311. }
  312. for (i=0; i<receiptsTo.cNames; i++) {
  313. CERT_ALT_NAME_INFO * pname = NULL;
  314. if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_ALTERNATE_NAME,
  315. receiptsTo.rgNames[i].pbData,
  316. receiptsTo.rgNames[i].cbData,
  317. CRYPT_ENCODE_ALLOC_FLAG,
  318. &CryptDecodeAlloc, &pname, &cb)) {
  319. goto GeneralFail;
  320. }
  321. for (i1=0; i1<pname->cAltEntry; i1++) {
  322. char cch;
  323. char rgch[256];
  324. if (pname->rgAltEntry[i1].dwAltNameChoice == CERT_ALT_NAME_RFC822_NAME) {
  325. cch = WideCharToMultiByte(CP_ACP, 0,
  326. pname->rgAltEntry[i1].pwszRfc822Name,
  327. -1, rgch, sizeof(rgch), NULL, NULL);
  328. if (cch > 0) {
  329. hr = pmatbl->AppendRfc822(IAT_TO, IET_UNICODE,
  330. rgch);
  331. if (FAILED(hr)) {
  332. goto CommonExit;
  333. }
  334. }
  335. break;
  336. }
  337. }
  338. if (i1 == pname->cAltEntry) {
  339. fSkipAddress = TRUE;
  340. }
  341. }
  342. #ifdef DEBUG
  343. {
  344. LPSTREAM pstmTmp = NULL;
  345. hr = MimeOleCreateVirtualStream(&pstmTmp);
  346. pmm->Save(pstmTmp, TRUE);
  347. pstmTmp->Release();
  348. }
  349. #endif // DEBUG
  350. hr = S_OK;
  351. *ppMessage = pmm;
  352. pmm->AddRef();
  353. CommonExit:
  354. CoTaskMemFree(var.blob.pBlobData);
  355. if (preq != NULL) free(preq);
  356. if (pbReceiptReq != NULL) CoTaskMemFree(pbReceiptReq);
  357. if (rgpvAuthAttr != NULL) CoTaskMemFree(rgpvAuthAttr);
  358. if (pattrs != NULL) free(pattrs);
  359. if (pstm != NULL) pstm->Release();
  360. if (pmatbl != NULL) pmatbl->Release();
  361. if (pmb != NULL) pmb->Release();
  362. if (pmm != NULL) pmm->Release();
  363. if (pbody != NULL) pbody->Release();
  364. return hr;
  365. GeneralFail:
  366. hr = E_FAIL;
  367. goto CommonExit;
  368. }
  369. #endif // SMIME_V3