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.
 
 
 
 
 
 

1808 lines
60 KiB

/* --- FIXES
-- SMIME TEST
fixed --- Can't do more than 4 || signers
fixed --- Can't Sc(Ekt(B))
- --- Sb(Sb(Sb(B))) only two layers are generated?
- --- Unauthenticated attributes
*/
/// http:iptdalpha3 - symbols for crypt32.
/*-----------------------------------------
SMimeTst.C -- Function Test of S/Mime
-----------------------------------------*/
#define INITGUID
#define DEFINE_STRCONST
#include "item.h"
#include "smtpcall.h"
#include "instring.h"
#include "dbgutil.h"
#include "sign.h"
#include "maillist.h"
#define WinMainT WinMain
long FAR PASCAL WndProc (HWND, UINT, UINT, LONG);
char szAppName [] = "SMimeTst";
static const TCHAR c_szDebug[] = "mshtmdbg.dll";
static const TCHAR c_szDebugUI[] = "DoTracePointsDialog";
static const TCHAR c_szRegSpy[] = "DbgRegisterMallocSpy";
static const TCHAR c_szInvokeUI1[] = "/d";
static const TCHAR c_szInvokeUI2[] = "-d";
HINSTANCE hInst;
const int MAX_LAYERS = 100;
extern const BYTE RgbSHA1AlgId[];
extern const int CbSHA1AlgId;
const GUID GuidCertValidate = CERT_CERTIFICATE_ACTION_VERIFY;
HWND HdlgMsg;
HWND HwndTree;
BOOL CALLBACK DetailDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK EncDataDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK EncDataComposeDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK EncTransCompDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK EncAgreeCompDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK EncInfoReadDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK MailListDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam);
enum {
Dlg_Message,
Dlg_Sign_Info_Compose,
Dlg_Sign_Info_Read,
Dlg_Sign_Data_Compose,
Dlg_Sign_Data_Read,
Dlg_Enc_Info_Compose,
Dlg_Enc_Info_Read,
Dlg_Enc_Data_Agree_Compose,
Dlg_Enc_Data_Trans_Compose,
Dlg_Enc_Data_MailList_Compose,
Dlg_Max
};
struct {
int id;
DLGPROC proc;
HWND hwnd;
} RgDlgs[] = {
{IDD_DETAIL, DetailDlgProc},
{IDD_SIGN_INFO_COMPOSE, SignInfoDlgProc},
{IDD_SIGN_INFO_COMPOSE, SignInfoDlgProc},
{IDD_SIGN_DATA_COMPOSE, SignDataDlgProc},
{IDD_SIGN_DATA_READ, SignDataReadDlgProc},
{IDD_ENCRYPT_INFO_COMPOSE, EncDataDlgProc},
{IDD_ENCRYPT_INFO_READ, EncInfoReadDlgProc},
{IDD_ENC_AGREE_COMPOSE, EncAgreeCompDlgProc},
{IDD_ENC_TRANS_COMPOSE, EncTransCompDlgProc},
{IDD_ENC_ML_COMPOSE, EncMLComposeDlgProc}
};
HWND HdlgEncData;
HWND HdlgSignInfo;
HWND HwndDetail;
CMessage RootMsg;
BYTE RgbSignHash[20];
HCERTSTORE HCertStoreMy = NULL;
IImnAccountManager * PAcctMan = NULL;
ISMTPTransport * PSmtp = NULL;
extern DWORD MsgSMTP = 0;
char RgchBody[] = "Now is the time for all good men (and women) to come to the aid of their country.\r\n";
char RgchExample[] = "This is some sample content.";
typedef void (STDAPICALLTYPE *PFNDEBUGUI)(BOOL);
typedef void (STDAPICALLTYPE *PFNREGSPY)(void);
void WaitForCompletion(UINT uiMsg, DWORD wparam)
{
MSG msg;
while(GetMessage(&msg, NULL, 0, 0))
{
if ((msg.message == uiMsg) && (msg.wParam == wparam) ||
(msg.wParam == IXP_DISCONNECTED))
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
void ShowWindow(int id, LPARAM lparam)
{
int i;
for (i=0; i<Dlg_Max; i++) {
ShowWindow(RgDlgs[i].hwnd, SW_HIDE);
}
ShowWindow(RgDlgs[id].hwnd, SW_SHOWNORMAL);
SendMessage(RgDlgs[id].hwnd, UM_SET_DATA, 0, lparam);
}
BOOL pfnFilter(PCCERT_CONTEXT pccert, long lCustData, DWORD, DWORD)
{
BOOL f = FALSE;
LPCSTR pszObjId = pccert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId;
if (lCustData & FILTER_RSA_KEYEX) {
f |= (strcmp(pszObjId, szOID_RSA_RSA) == 0);
}
if (lCustData & FILTER_RSA_SIGN) {
f |= (strcmp(pszObjId, szOID_RSA_RSA) == 0);
}
if (lCustData & FILTER_DSA_SIGN) {
f |= (strcmp(pszObjId, szOID_X957_DSA) == 0);
}
if (lCustData & FILTER_DH_KEYEX) {
f |= (strcmp(pszObjId, szOID_ANSI_X942_DH) == 0);
}
if (lCustData & FILTER_KEA_KEYEX) {
f |= (strcmp(pszObjId, szOID_INFOSEC_keyExchangeAlgorithm) == 0);
}
return f;
}
BOOL DoCertDialog(HWND hwndOwner, LPTSTR szTitle, HCERTSTORE hCertStore, PCCERT_CONTEXT *ppCert, int iFilter)
{
DWORD cchEmail;
CERT_SELECT_STRUCT css = {0};
PCCERT_CONTEXT pCurCert;
BOOL fRet = FALSE;
pCurCert = CertDuplicateCertificateContext(*ppCert);
css.dwSize = sizeof(CERT_SELECT_STRUCT);
css.hwndParent = hwndOwner;
css.hInstance = hInst;
css.arrayCertStore = &hCertStore;
css.szTitle = szTitle;
css.cCertStore = 1;
css.szPurposeOid = szOID_PKIX_KP_EMAIL_PROTECTION;
css.arrayCertContext = ppCert;
css.cCertContext = 1;
css.lCustData = iFilter;
css.pfnFilter = pfnFilter;
if (CertSelectCertificate(&css) && (pCurCert != *ppCert)) {
fRet = TRUE;
}
CertFreeCertificateContext(pCurCert);
return fRet;
}
BOOL ViewCertDialog(HWND hwndOwner, LPTSTR szTitle, PCCERT_CONTEXT pCert)
{
CERT_VIEWPROPERTIES_STRUCT cvs = {0};
char * psz = szOID_PKIX_KP_EMAIL_PROTECTION;
cvs.dwSize = sizeof(cvs);
cvs.hwndParent = hwndOwner;
cvs.szTitle = szTitle;
cvs.pCertContext = pCert;
cvs.cArrayPurposes = 1;
cvs.arrayPurposes = &psz;
CertViewProperties(&cvs);
return TRUE;
}
// HrValidateCert
//
// Description:
// This routine is used to check the validity of a certificate, the codes
// are modified from HrDoTrustWork in cryptdlg.dll, by xzhang
//
// Parameters:
// pcert - Point to the certificate we want to validate
// hstore - Extra store for searching certficates
// pbd - Point to BinData for returning the certificate chain
// pcCertsInChain - Point to DWORD for returning the # of certs in chain
// pdwErrors - Returns the errors encountered in validating the cert
//
// Return Value:
// Result code of operation.
//
// Returned in *pdwErrors;
//
// The return value consists of a set of flags about why we failed to
// do the validation. Current reasons are:
//
// SIGFAILURE_INVALID_CERT - Certificate is internally inconsistant
// SIGFAILURE_UNKNOWN_ROOT - Root certificate in chain is either unknown
// or not self sign.
// SIGFAILURE_CERT_EXPIRED - Certificate has expired
// SIGFAILURE_CERT_REVOKED - Certificate has been revoked
// SIGFAILURE_CRL_NOT_FOUND - CRL was not found for some Issuer
// SIGFAILURE_INVALID_SIGNATURE - Invalid signature, not the above reason
//
HRESULT HrValidateCert(PCCERT_CONTEXT pccert, HCERTSTORE hstore, HCRYPTPROV hprov,
HCERTSTORE * phcertstorOut, DWORD * pdwErrors)
{
WINTRUST_BLOB_INFO blob = {0};
DWORD cCertsInChain = 0;
DWORD cStores;
WINTRUST_DATA data = {0};
DWORD dwCAs = 0;
DWORD dwErrors = 0;
DWORD dwRet = 0;
BOOL f;
HCERTSTORE hcertstorOut;
DWORD i;
PCCERT_CONTEXT pccertOut = NULL;
PCCERT_CONTEXT * rgCerts = NULL;
DWORD * rgdwErrors = NULL;
HCERTSTORE rghstoreCA[2] = {NULL};
CERT_VERIFY_CERTIFICATE_TRUST trust = {0};
HRESULT hr;
Assert(pdwErrors != NULL);
//
// Make sure we have a place to store the output unless we are being
// told to ignore it
//
if (phcertstorOut != NULL) {
// Try to open an output store if we have not been given one
if (*phcertstorOut == NULL) {
hcertstorOut = CertOpenStore(CERT_STORE_PROV_MEMORY,
X509_ASN_ENCODING, hprov,
CERT_STORE_NO_CRYPT_RELEASE_FLAG,
NULL);
if (hcertstorOut == NULL) {
hr = E_FAIL;
goto ExitHere;
}
*phcertstorOut = hcertstorOut;
}
else {
hcertstorOut = *phcertstorOut;
}
}
else {
// No output is being requested
hcertstorOut = NULL;
}
//
// Fill the WINTRUST_DATA
//
data.cbStruct = sizeof(WINTRUST_DATA);
data.dwUIChoice = WTD_UI_NONE;
data.fdwRevocationChecks = WTD_REVOKE_NONE;
data.dwUnionChoice = WTD_CHOICE_BLOB;
data.pBlob = &blob;
//
// Fill the trust blob information
//
blob.cbStruct = sizeof(WINTRUST_BLOB_INFO);
blob.cbMemObject = sizeof(CERT_VERIFY_CERTIFICATE_TRUST);
blob.pbMemObject = (LPBYTE)&trust;
//
// Fill the certificate trust information
//
trust.cbSize = sizeof(trust);
trust.pccert = pccert;
trust.dwFlags = (CERT_TRUST_DO_FULL_SEARCH | CERT_TRUST_PERMIT_MISSING_CRLS
|CERT_TRUST_DO_FULL_TRUST | CERT_TRUST_ADD_CERT_STORES);
trust.dwIgnoreErr = CERT_VALIDITY_NO_CRL_FOUND;
trust.pdwErrors = &dwErrors;
trust.pszUsageOid = szOID_PKIX_KP_EMAIL_PROTECTION;
trust.hprov = hprov;
//
// If we have a store of certificates, then pass it in to give us additional
// places to look
//
rghstoreCA[0] = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING,
hprov, (CERT_SYSTEM_STORE_CURRENT_USER |
CERT_STORE_NO_CRYPT_RELEASE_FLAG),
L"CA");
if (rghstoreCA[0] == NULL) {
hr = E_FAIL;
goto ExitHere;
}
cStores = 1;
trust.rghstoreCAs = rghstoreCA;
if (hstore) {
cStores = 2;
rghstoreCA[1] = hstore;
}
trust.cStores = cStores;
trust.pcChain = &cCertsInChain;
trust.prgChain = &rgCerts;
trust.prgdwErrors = &rgdwErrors;
//
// Call the brain function to verify the trust status of this certificate
//
hr = WinVerifyTrust(NULL, (GUID *)&GuidCertValidate, &data);
if(FAILED(hr) || cCertsInChain == 0) {
//
// We completely failed the verificaiton
//
*pdwErrors = /*SIGFAILURE_OTHER*/ 1;
//
// But we still need to shove this certificate into the output store
// if the user wants one
//
if (NULL != hcertstorOut) {
// Add the certificate to the store. We need to remember the
// new context so we can properly add CRLs
f = CertAddCertificateContextToStore(hcertstorOut, pccert,
CERT_STORE_ADD_NEW,
&pccertOut);
Assert(f || (NULL == pccertOut));
// Look for any CRLs which might apply to the new context
// and add them to the store as well
if (NULL != pccertOut) {
// hr = HrAddValidCRLsToStore(hcertstorOut, pccertOut,
// rghstoreCA, cStores);
Assert(S_OK == hr);
}
}
hr = S_OK;
goto ExitHere;
}
//
// Now build the certificates chain for SSignature when requested
//
if (hcertstorOut != NULL) {
if (cCertsInChain == 0) {
// Store the certificate in the output store and remember the
// new certificate context for checking the CRLs
f = CertAddCertificateContextToStore(hcertstorOut, pccert,
CERT_STORE_ADD_NEW,
&pccertOut);
Assert(f || (NULL == pccertOut));
// Look for any CRLs which might apply and add them to the store
// as well
if (NULL != pccertOut) {
// hr = HrAddValidCRLsToStore(hcertstorOut, pccertOut,
// rghstoreCA, cStores);
Assert(S_OK == hr);
}
}
for (i=0; i<cCertsInChain; i++) {
// Free any output certificate context we have already
if (NULL != pccertOut) {
CertFreeCertificateContext(pccertOut);
pccertOut = NULL;
}
// Add the encoded certificate to the store
f = CertAddEncodedCertificateToStore(hcertstorOut, X509_ASN_ENCODING,
rgCerts[i]->pbCertEncoded,
rgCerts[i]->cbCertEncoded,
CERT_STORE_ADD_NEW, &pccertOut);
Assert(f || (NULL == pccertOut));
// Add any appropriate CRLs to the store as well
if (NULL != pccertOut) {
// hr = HrAddValidCRLsToStore(hcertstorOut, pccertOut,
// rghstoreCA, cStores);
Assert(S_OK == hr);
}
}
}
//
// Setup the signuare error flags as used in ExSec32.dll
//
if(rgdwErrors == NULL) {
*pdwErrors = /*SIGFAILURE_OTHER*/ 1;
hr = MAPI_E_NOT_ENOUGH_MEMORY;
goto ExitHere;
}
// We only care about the trust status of the leaf certificate
dwErrors = rgdwErrors[0];
if (dwErrors != 0) {
if(dwErrors & CERT_VALIDITY_SIGNATURE_FAILS) {
dwRet |= /*SIGFAILURE_INVALID_CERT*/ 2;
dwErrors &= ~CERT_VALIDITY_SIGNATURE_FAILS;
}
if(dwErrors & CERT_VALIDITY_CERTIFICATE_REVOKED) {
dwRet |= /*SIGFAILURE_CERT_REVOKED*/ 4;
dwErrors &= ~CERT_VALIDITY_CERTIFICATE_REVOKED;
}
if(dwErrors & CERT_VALIDITY_AFTER_END) {
dwRet |= /*SIGFAILURE_CERT_EXPIRED*/ 8;
dwErrors &= ~CERT_VALIDITY_AFTER_END;
}
if(dwErrors & CERT_VALIDITY_EXPLICITLY_DISTRUSTED) {
dwRet |= /*SIGFAILURE_CERT_DISTRUSTED*/ 16;
dwErrors &= ~CERT_VALIDITY_EXPLICITLY_DISTRUSTED;
}
if((dwErrors & CERT_VALIDITY_NO_ISSUER_CERT_FOUND) &&
(cCertsInChain == 1)) {
dwRet |= /*SIGFAILURE_CERT_DISTRUSTED*/ 128;
dwErrors &= ~CERT_VALIDITY_NO_ISSUER_CERT_FOUND;
}
if((dwErrors & CERT_VALIDITY_NO_TRUST_DATA) &&
(cCertsInChain == 1)) {
dwRet |= /*SIGFAILURE_CERT_DISTRUSTED*/ 256;
dwErrors &= ~CERT_VALIDITY_NO_TRUST_DATA;
}
if(dwErrors & CERT_VALIDITY_NO_TRUST_DATA) {
dwRet |= /*SIGFAILURE_UNKNOWN_ROOT*/ 32;
dwErrors &= ~CERT_VALIDITY_NO_TRUST_DATA;
}
if(dwErrors & CERT_VALIDITY_ISSUER_DISTRUST) {
dwRet |= /*SIGFAILURE_ISSUER_DISTRUSTED*/ 64;
dwErrors &= ~CERT_VALIDITY_ISSUER_DISTRUST;
}
if(dwErrors) { // catch all other non-specified case
dwRet |= /*SIGFAILURE_OTHER*/ 1;
}
}
*pdwErrors = dwRet;
hr = S_OK;
ExitHere:
//
// Clean up any items laying around
//
if (NULL != pccertOut) {
CertFreeCertificateContext(pccertOut);
}
if (rghstoreCA[0] != NULL) {
CertCloseStore(rghstoreCA[0], 0);
}
if(rgdwErrors)
LocalFree(rgdwErrors);
if(rgCerts != NULL) {
for(i=0; i < cCertsInChain; ++i) {
CertFreeCertificateContext(rgCerts[i]);
}
LocalFree(rgCerts);
}
return hr;
}
BOOL GetOpenEmailFileName(HWND hwnd, LPTSTR szInputFile, LPCSTR szTitle) {
TCHAR szFileName[CCH_OPTION_STRING];
OPENFILENAME ofn = {0};
lstrcpy(szFileName, szInputFile);
if (szInputFile[0] == '<') szInputFile[0] = 0;
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwnd;
ofn.hInstance = hInst;
ofn.lpstrFilter = "Email File\0*.eml\0";
ofn.lpstrCustomFilter = NULL;
ofn.nMaxCustFilter = 0;
ofn.nFilterIndex = 0;
ofn.lpstrFile = szFileName;
ofn.nMaxFile = CCH_OPTION_STRING;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.lpstrTitle = szTitle;
ofn.Flags = OFN_HIDEREADONLY;
ofn.nFileOffset = 0;
ofn.nFileExtension = 0;
ofn.lpstrDefExt = "eml";
ofn.lCustData = 0;
ofn.lpfnHook = NULL;
ofn.lpTemplateName = NULL;
if (GetOpenFileName(&ofn)) {
lstrcpy(szInputFile, szFileName);
return(TRUE);
}
return(FALSE);
}
HRESULT InsertBody(IMimeMessage * pmm, HBODY hbody)
{
HRESULT hr;
hr = pmm->ToMultipart(hbody, "y-security", NULL);
if (FAILED(hr)) return hr;
return S_OK;
}
int PASCAL
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine,
int nCmdShow)
{
BOOL f;
HINSTANCE hInstDebug = NULL;
HRESULT hr;
HWND hwnd;
INITCOMMONCONTROLSEX initCommCtrl = { 8, ICC_TREEVIEW_CLASSES };
MSG msg;
WNDCLASS wndclass;
// OLE Init
hr = CoInitialize(NULL);
if (FAILED(hr))
{
exit(1);
}
InitDemandLoadedLibs();
InitCommonControlsEx(&initCommCtrl);
// Load options from the registry
GetOptions();
if (!hPrevInstance) {
hInst = hInstance;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW) ;
wndclass.hbrBackground = CreateSolidBrush(0x00ffff);
wndclass.lpszMenuName = szAppName ;
wndclass.lpszClassName = szAppName ;
RegisterClass (&wndclass) ;
}
MsgSMTP = RegisterWindowMessage("SMTPTransport_Notify");
if (! hInstDebug) {
// Load mshtmdbg.dll
hInstDebug = LoadLibrary(c_szDebug);
// Did it load ?
if (NULL != hInstDebug) {
// Locals
PFNREGSPY pfnRegSpy;
// If the user passed /d on the command line, lets configure mshtmdbg.dll
if (0 == lstrcmpi(lpszCmdLine, c_szInvokeUI1) ||
0 == lstrcmpi(lpszCmdLine, c_szInvokeUI2)) {
// Locals
PFNDEBUGUI pfnDebugUI;
// Get the proc address of the UI
pfnDebugUI = (PFNDEBUGUI)GetProcAddress(hInstDebug, c_szDebugUI);
if (NULL != pfnDebugUI) {
(*pfnDebugUI)(TRUE);
}
}
// Get the process address of the registration
pfnRegSpy = (PFNREGSPY)GetProcAddress(hInstDebug, c_szRegSpy);
if (NULL != pfnRegSpy)
(*pfnRegSpy)();
}
}
hwnd = CreateWindow (szAppName, "S/Mime Test", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, NULL, NULL, hInstance, NULL) ;
ShowWindow (hwnd, nCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
f = CertCloseStore(HCertStoreMy, CERT_CLOSE_STORE_CHECK_FLAG);
if (!f) {
AssertSz(FALSE, "Global My Cert store did not close completely");
}
if (PSmtp) PSmtp->Release();
if (PAcctMan) PAcctMan->Release();
if (hInstDebug) {
FreeLibrary(hInstDebug);
}
FreeDemandLoadedLibs();
CoFreeUnusedLibraries();
return(msg.wParam);
}
BOOL CALLBACK DetailDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_INITDIALOG:
break;
default:
return FALSE;
}
return TRUE;
}
BOOL CALLBACK MsgDataDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
TCHAR rgchFileName[CCH_OPTION_STRING];
switch (msg) {
case WM_INITDIALOG:
SetDlgItemText(hdlg, IDC_MD_PLAIN_NAME, RootMsg.GetPlainFile());
SetDlgItemText(hdlg, IDC_MD_CIPHER_NAME, RootMsg.GetCipherFile());
SetDlgItemInt(hdlg, IDC_MD_ITERATION, RootMsg.GetIterationCount(), FALSE);
SendDlgItemMessage(hdlg, IDC_MD_TOFILE, BM_SETCHECK, FALSE, 0);
break;
case WM_COMMAND:
switch (wParam) {
case IDC_MD_PLAIN_CHOOSE:
if (GetOpenEmailFileName(hdlg, RootMsg.GetPlainFile(),
"Select Plain Text File")) {
SetDlgItemText(hdlg, IDC_MD_PLAIN_NAME, RootMsg.GetPlainFile());
}
break;
case IDC_MD_CIPHER_CHOOSE:
if (GetOpenEmailFileName(hdlg, RootMsg.GetCipherFile(),
"Select Cipher Text File")) {
SetDlgItemText(hdlg, IDC_MD_CIPHER_NAME, RootMsg.GetCipherFile());
}
break;
case MAKELONG(IDC_MD_PLAIN_NAME, EN_CHANGE):
GetDlgItemText(hdlg, IDC_MD_PLAIN_NAME, RootMsg.GetPlainFile(),
RootMsg.GetFileNameSize());
break;
case MAKELONG(IDC_MD_CIPHER_NAME, EN_CHANGE):
GetDlgItemText(hdlg, IDC_MD_CIPHER_NAME, RootMsg.GetCipherFile(),
RootMsg.GetFileNameSize());
break;
case MAKELONG(IDC_MD_ITERATION, EN_CHANGE):
RootMsg.GetIterationCount() = GetDlgItemInt(hdlg, IDC_MD_ITERATION,
NULL, FALSE);
break;
case MAKELONG(IDC_MD_TOFILE, BN_CLICKED):
RootMsg.SetToFile(!SendDlgItemMessage(hdlg, IDC_MD_TOFILE, BM_GETCHECK, 0, 0));
break;
default:
return FALSE;
}
default:
return FALSE;
}
return TRUE;
}
BOOL InsertNode(LPSTR pszLayerName, int iImage, DWORD iDlg, DWORD dwData)
{
HTREEITEM hitem;
CItem * pitem;
TV_INSERTSTRUCT tvins;
TV_ITEM tvitm;
hitem = TreeView_GetSelection(HwndTree);
tvins.item.mask = TVIF_TEXT | TVIF_PARAM;
tvins.hParent = TreeView_GetParent(HwndTree, hitem);
if (tvins.hParent == NULL) {
tvins.hParent = hitem;
tvins.hInsertAfter = TVI_FIRST;
pitem = NULL;
}
else {
tvins.hInsertAfter = hitem;
tvitm.mask = TVIF_PARAM;
tvitm.hItem = hitem;
TreeView_GetItem(HwndTree, &tvitm);
pitem = (CItem *) tvitm.lParam;
}
tvins.item.pszText = pszLayerName;
tvins.item.cchTextMax = strlen(pszLayerName);
tvins.item.iImage = iImage;
tvins.item.iSelectedImage = tvins.item.iImage;
tvins.item.lParam = dwData;
hitem = TreeView_InsertItem(HwndTree, &tvins);
TreeView_Expand(HwndTree, tvins.hParent, TVE_EXPAND);
TreeView_SelectItem(HwndTree, hitem);
SendMessage(RgDlgs[iDlg].hwnd, UM_SET_DATA, 0, tvins.item.lParam);
RootMsg.MakeChild((CItem *) tvins.item.lParam, pitem);
return TRUE;
}
BOOL InsertNode2(int typeParent, LPSTR pszTitle, DWORD iImage, DWORD iDlg,
CItem * pItemNew)
{
HTREEITEM hitem;
HTREEITEM hitemParent;
CItem * pitem;
CItem * pitemParent;
TV_ITEM tvitm;
TV_INSERTSTRUCT tvins;
hitem = TreeView_GetSelection(HwndTree);
hitemParent = TreeView_GetParent(HwndTree, hitem);
tvitm.mask = TVIF_PARAM;
tvitm.hItem = hitem;
TreeView_GetItem(HwndTree, &tvitm);
pitemParent = (CItem *) tvitm.lParam;
if (pitemParent->GetType() == typeParent) {
tvins.hParent = hitemParent;
tvins.hInsertAfter = hitem;
pitem = pitemParent;
pitemParent = ((CSignData *) pitemParent)->GetParent();
}
else {
tvins.hParent = hitem;
tvins.hInsertAfter = TVI_FIRST;
pitem = NULL;
}
tvins.item.lParam = (DWORD) pItemNew;
pItemNew->SetParent(pitemParent);
tvins.item.mask = TVIF_TEXT | TVIF_PARAM;
tvins.hInsertAfter = hitem;
tvins.item.pszText = pszTitle;
tvins.item.cchTextMax = strlen(pszTitle);
tvins.item.iImage = iImage;
tvins.item.iSelectedImage = tvins.item.iImage;
hitem = TreeView_InsertItem(HwndTree, &tvins);
TreeView_Expand(HwndTree, tvins.hParent, TVE_EXPAND);
TreeView_SelectItem(HwndTree, hitem);
SendMessage(RgDlgs[iDlg].hwnd, UM_SET_DATA, 0, tvins.item.lParam);
pitemParent->MakeChild((CItem *) tvins.item.lParam, pitem);
return 0;
}
long FAR PASCAL WndProc (HWND hwnd, UINT message, UINT wParam, LONG lParam)
{
HTREEITEM hitem;
HTREEITEM hitemRoot;
HRESULT hr;
int i;
CItem * pitem;
CItem * pitemParent;
LPNMTREEVIEW ptv;
char rgch[300];
TV_ITEM tvitm;
TV_INSERTSTRUCT tvins;
switch (message) {
case WM_CREATE:
// Create our child windows -- we only have one top level window so use
// some globals
HdlgMsg = CreateDialog(hInst, MAKEINTRESOURCE(IDD_MSG_DATA), hwnd,
MsgDataDlgProc);
HwndTree = CreateWindow(WC_TREEVIEW, "Tree",
WS_CHILD | WS_CLIPCHILDREN | WS_HSCROLL |
WS_VSCROLL | WS_VISIBLE | TVS_HASBUTTONS |
TVS_HASLINES , 0, 0, 0, 0,
hwnd, NULL, hInst, NULL);
for (i=0; i<Dlg_Max; i++) {
RgDlgs[i].hwnd = CreateDialog(hInst, MAKEINTRESOURCE(RgDlgs[i].id),
hwnd, RgDlgs[i].proc);
AssertSz(RgDlgs[i].hwnd != NULL, "Missed creating a window");
}
// Initialize Tree with an item
tvins.item.mask = TVIF_TEXT | TVIF_PARAM;
tvins.hParent = TVI_ROOT;
tvins.hInsertAfter = TVI_FIRST;
tvins.item.pszText = "Message";
tvins.item.cchTextMax = 7;
tvins.item.iImage = 0;
tvins.item.iSelectedImage = tvins.item.iImage;
tvins.item.lParam = (DWORD) &RootMsg;
hitem = TreeView_InsertItem(HwndTree, &tvins);
TreeView_SelectItem(HwndTree, hitem);
TreeView_Expand(HwndTree, tvins.hParent, TVE_EXPAND);
// LoadWAB();
break;
case WM_COMMAND :
switch (wParam) {
case IDM_EXIT :
SendMessage (hwnd, WM_CLOSE, 0, 0L) ;
return 0 ;
case IDM_E_INSERT_SIGN:
InsertNode("Signature Layer", 1, Dlg_Sign_Info_Compose,
(DWORD) new CSignInfo(STATE_COMPOSE, &RootMsg));
return 0;
case IDM_E_INSERT_SIGNATURE:
pitem = new CSignData(STATE_COMPOSE);
InsertNode2(TYPE_SIGN_DATA, "Signature", 2, Dlg_Sign_Data_Compose,
pitem);
((CSignData *) pitem)->SetDefaultCert();
return 0;
case IDM_E_INSERT_ENCRYPT:
InsertNode("Encryption Layer", 3, Dlg_Enc_Info_Compose,
(DWORD) new CEnvData(STATE_COMPOSE, &RootMsg));
return 0;
case IDM_E_INSERT_TRANSPORT:
InsertNode2(TYPE_ENV_MAILLIST, "Transport", 3, Dlg_Enc_Data_Trans_Compose,
new CEnvCertTrans(STATE_COMPOSE));
break;
case IDM_E_INSERT_AGREEMENT:
InsertNode2(TYPE_ENV_MAILLIST, "Agree", 3, Dlg_Enc_Data_Agree_Compose,
new CEnvCertAgree(STATE_COMPOSE));
break;
case IDM_E_INSERT_MAILLIST:
InsertNode2(TYPE_ENV_MAILLIST, "Mail List", 3, Dlg_Enc_Data_MailList_Compose,
new CEnvMailList(STATE_COMPOSE));
break;
case IDM_ENCODE:
SendMessage(RgDlgs[Dlg_Sign_Data_Compose].hwnd, UM_SET_DATA, 0, NULL);
SendMessage(RgDlgs[Dlg_Enc_Info_Compose].hwnd, UM_SET_DATA, 0, NULL);
SendMessage(RgDlgs[Dlg_Enc_Data_Agree_Compose].hwnd, UM_SET_DATA, 0, NULL);
SendMessage(RgDlgs[Dlg_Enc_Data_Trans_Compose].hwnd, UM_SET_DATA, 0, NULL);
SendMessage(RgDlgs[Dlg_Enc_Data_MailList_Compose].hwnd, UM_SET_DATA, 0, NULL);
for (i=0; i<RootMsg.GetIterationCount(); i++) {
hr = RootMsg.Encode(hwnd);
if (FAILED(hr)) {
wsprintf(rgch, "Encode failed with 0x%08x on iteration %d",
hr, i);
MessageBox(hwnd, rgch, szAppName, MB_OK);
break;
}
CoFreeUnusedLibraries();
}
SendMessage(hwnd, UM_RESET, 0, 0);
RootMsg.ResetMessage();
return 0;
case IDM_DECODE:
for (i=0; i<RootMsg.GetIterationCount(); i++) {
SendMessage(hwnd, UM_RESET, 0, 0);
RootMsg.ResetMessage();
hr = RootMsg.Decode(hwnd);
if (FAILED(hr)) {
wsprintf(rgch, "Decode failed with 0x%08x on iteration %d",
hr, i);
MessageBox(hwnd, rgch, szAppName, MB_OK);
RootMsg.ResetMessage();
break;
}
CoFreeUnusedLibraries();
}
SendMessage(hwnd, UM_FILL, 0, 0);
return(0);
case IDM_RESET:
SendMessage(hwnd, UM_RESET, 0, 0);
RootMsg.ResetMessage();
return 0;
case IDM_VALIDATE:
for (i=0; i<Dlg_Max; i++) {
if (IsWindowVisible(RgDlgs[i].hwnd)) {
SendMessage(RgDlgs[i].hwnd, message, wParam, lParam);
break;
}
}
break;
case IDM_F_OPTIONS:
DialogBox(hInst, MAKEINTRESOURCE(idd_Options), hwnd, OptionsDlgProc);
return(0);
case IDM_F_MAILLIST:
DialogBox(hInst, MAKEINTRESOURCE(IDD_FILE_MAILLIST), hwnd, MailListDlgProc);
return 0;
case IDM_ABOUT:
MessageBox (hwnd, "S/Mime Function Test.",
szAppName, MB_ICONINFORMATION | MB_OK);
return(0);
}
break ;
case WM_SIZE:
{
int cx = LOWORD(lParam);
int cy = HIWORD(lParam);
MoveWindow(HdlgMsg, 0, 1, cx, (cy/3)-2, TRUE);
MoveWindow(HwndTree, 0, (cy/3)+1, (cx/3-1), cy-((cy/3)+1), TRUE);
for (i=0; i<Dlg_Max; i++) {
MoveWindow(RgDlgs[i].hwnd, (cx/3)+1, (cy/3+1), cx-(cx/3)+1,
cy-((cy/3)+1), TRUE);
}
}
break;
case WM_SETFOCUS:
SetFocus(HwndTree);
return 0;
case WM_NOTIFY:
switch (((NMHDR *) lParam)->code) {
case TVN_SELCHANGEDA:
case TVN_SELCHANGEDW:
ptv = (LPNMTREEVIEW) lParam;
switch (((CItem *) ptv->itemNew.lParam)->GetType() |
((CItem *) ptv->itemNew.lParam)->GetState()) {
case TYPE_SIGN_DATA | STATE_COMPOSE:
ShowWindow(Dlg_Sign_Data_Compose, ptv->itemNew.lParam);
break;
case TYPE_SIGN_DATA | STATE_READ:
ShowWindow(Dlg_Sign_Data_Read, ptv->itemNew.lParam);
break;
case TYPE_ENV_INFO | STATE_COMPOSE:
ShowWindow(Dlg_Enc_Info_Compose, ptv->itemNew.lParam);
break;
case TYPE_ENV_INFO | STATE_READ:
Assert(FALSE);
break;
case TYPE_ENV_AGREE | STATE_COMPOSE:
ShowWindow(Dlg_Enc_Data_Agree_Compose, ptv->itemNew.lParam);
break;
case TYPE_ENV_AGREE | STATE_READ:
Assert(FALSE);
break;
case TYPE_ENV_TRANS | STATE_COMPOSE:
ShowWindow(Dlg_Enc_Data_Trans_Compose, ptv->itemNew.lParam);
break;
case TYPE_ENV_TRANS | STATE_READ:
Assert(FALSE);
break;
case TYPE_ENV_MAILLIST | STATE_COMPOSE:
ShowWindow(Dlg_Enc_Data_MailList_Compose, ptv->itemNew.lParam);
break;
case TYPE_ENV_MAILLIST | STATE_READ:
Assert(FALSE);
break;
case TYPE_MSG | STATE_COMPOSE:
case TYPE_MSG | STATE_READ:
ShowWindow(Dlg_Message, NULL);
break;
case TYPE_SIGN_INFO | STATE_COMPOSE:
case TYPE_SIGN_INFO | STATE_READ:
ShowWindow(Dlg_Sign_Info_Compose, ptv->itemNew.lParam);
break;
}
}
return 0;
case WM_INITMENU:
tvitm.mask = TVIF_PARAM | TVIF_CHILDREN;
tvitm.hItem = TreeView_GetSelection(HwndTree);
TreeView_GetItem(HwndTree, &tvitm);
i = ((CItem *) tvitm.lParam)->GetType();
EnableMenuItem(GetMenu(hwnd), IDM_E_INSERT_SIGN, MF_BYCOMMAND |
(i == TYPE_SIGN_DATA) ? MF_GRAYED : MF_ENABLED);
EnableMenuItem(GetMenu(hwnd), IDM_E_INSERT_ENCRYPT, MF_BYCOMMAND |
(i == TYPE_SIGN_DATA) ? MF_GRAYED : MF_ENABLED);
EnableMenuItem(GetMenu(hwnd), IDM_E_INSERT_SIGNATURE, MF_BYCOMMAND |
((i == TYPE_SIGN_DATA) || (i == TYPE_SIGN_INFO)) ?
MF_ENABLED : MF_GRAYED);
EnableMenuItem(GetMenu(hwnd), IDM_E_INSERT_TRANSPORT, MF_BYCOMMAND |
((i == TYPE_ENV_INFO) || (i == TYPE_ENV_AGREE) ||
(i == TYPE_ENV_TRANS) || (i == TYPE_ENV_MAILLIST)) ?
MF_ENABLED : MF_GRAYED);
EnableMenuItem(GetMenu(hwnd), IDM_E_DELETE_LAYER, MF_BYCOMMAND |
(((i == TYPE_SIGN_INFO) || (i == TYPE_ENV_INFO)) &&
(tvitm.cChildren == 0)) ? MF_ENABLED : MF_GRAYED);
EnableMenuItem(GetMenu(hwnd), IDM_E_DELETE_SIGNATURE, MF_BYCOMMAND |
(i == TYPE_SIGN_DATA) ? MF_ENABLED : MF_GRAYED);
break;
case WM_DESTROY:
// Reset the message object to have no contents
SendMessage(hwnd, UM_RESET, 0, 0);
RootMsg.ResetMessage();
SaveOptions();
CleanupOptions();
// UnloadWAB();
for (i=0; i<Dlg_Max; i++) {
DestroyWindow(RgDlgs[i].hwnd);
}
DestroyWindow(HwndTree);
DestroyWindow(HdlgMsg);
PostQuitMessage(0);
return(0);
case UM_RESET:
hitemRoot = TreeView_GetRoot(HwndTree);
while (TRUE) {
TVITEM tvitem;
tvitem.hItem = TreeView_GetChild(HwndTree, hitemRoot);
if (tvitem.hItem == NULL) {
break;
}
tvitem.mask = TVIF_PARAM | TVIF_CHILDREN;
TreeView_GetItem(HwndTree, &tvitem);
if (tvitem.cChildren != 0) {
for (i=0; i<tvitem.cChildren; i++) {
TVITEM tvitem2;
tvitem2.hItem = TreeView_GetChild(HwndTree, tvitem.hItem);
tvitem2.mask = TVIF_PARAM | TVIF_CHILDREN;
TreeView_GetItem(HwndTree, &tvitem2);
delete (CItem *) tvitem2.lParam;
TreeView_DeleteItem(HwndTree, tvitem2.hItem);
}
}
delete (CItem *) tvitem.lParam;
TreeView_DeleteItem(HwndTree, tvitem.hItem);
}
}
return(DefWindowProc (hwnd, message, wParam, lParam));
}
int _stdcall WinMainCRTStartup (void)
{
int i;
STARTUPINFOA si;
PTSTR pszCmdLine = GetCommandLine();
SetErrorMode(SEM_FAILCRITICALERRORS);
if (*pszCmdLine == TEXT ('\"'))
{
// Scan, and skip over, subsequent characters until
// another double-quote or a null is encountered.
while (*++pszCmdLine && (*pszCmdLine != TEXT ('\"')));
// If we stopped on a double-quote (usual case), skip over it.
if (*pszCmdLine == TEXT ('\"')) pszCmdLine++;
}
else
{
while (*pszCmdLine > TEXT (' ')) pszCmdLine++;
}
// Skip past any white space preceeding the second token.
while (*pszCmdLine && (*pszCmdLine <= TEXT (' '))) pszCmdLine++;
si.dwFlags = 0;
GetStartupInfo (&si);
i = WinMainT(GetModuleHandle (NULL), NULL, pszCmdLine,
si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT);
ExitProcess(i);
return i;
}
//////////////////////////////////////////////////////////////////////////
void CItem::MakeChild(CItem * pChild, CItem * pAfter)
{
if (pAfter == NULL) {
pChild->m_pSibling = m_pChild;
m_pChild = pChild;
}
else if (m_pChild == pAfter) {
pChild->m_pSibling = pAfter;
m_pChild = pChild;
}
else {
CItem * pItem = m_pChild;
while (pItem != NULL) {
if (pItem == pAfter) {
pChild->m_pSibling = pItem->m_pSibling;
pItem->m_pSibling = pChild;
break;
}
pItem = pItem->m_pSibling;
}
}
}
void CItem::RemoveAsChild(CItem * pChild)
{
if (m_pChild == pChild) {
m_pChild = pChild->m_pSibling;
pChild->m_pSibling = NULL;
}
else {
CItem * pItem = m_pChild;
while (pItem != NULL) {
if (pItem->m_pSibling == pChild) {
pItem->m_pSibling = pChild->m_pSibling;
pChild->m_pSibling = NULL;
break;
}
pItem = pItem->m_pSibling;
}
}
}
HCERTSTORE CMessage::GetAllStore()
{
HCERTSTORE hCertStore;
if (m_hCertStoreAll == NULL) {
m_hCertStoreAll = CertOpenStore(CERT_STORE_PROV_COLLECTION,
X509_ASN_ENCODING, NULL, 0, NULL);
AssertSz(m_hCertStoreAll != NULL, "Open Collection Store");
hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING,
NULL, CERT_SYSTEM_STORE_CURRENT_USER,
L"MY");
AssertSz(hCertStore != NULL, "Open My Cert Store failed");
CertAddStoreToCollection(m_hCertStoreAll, hCertStore, 0, 0);
CertCloseStore(hCertStore, 0);
hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING,
NULL, CERT_SYSTEM_STORE_CURRENT_USER,
L"AddressBook");
AssertSz(hCertStore != NULL, "Open Address Book Cert Store failed");
CertAddStoreToCollection(m_hCertStoreAll, hCertStore, 0, 0);
CertCloseStore(hCertStore, 0);
hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING,
NULL, CERT_SYSTEM_STORE_CURRENT_USER,
L"CA");
AssertSz(hCertStore != NULL, "Open CA Cert Store failed");
CertAddStoreToCollection(m_hCertStoreAll, hCertStore, 0, 0);
CertCloseStore(hCertStore, 0);
}
return m_hCertStoreAll;
}
HCERTSTORE CMessage::GetMyStore()
{
if (m_hCertStoreMy == NULL) {
m_hCertStoreMy = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING,
NULL, CERT_SYSTEM_STORE_CURRENT_USER,
L"MY");
AssertSz(m_hCertStoreMy != NULL, "Open My Cert Store failed");
}
return m_hCertStoreMy;
}
BOOL CMessage::ResetMessage(void)
{
BOOL f;
CItem * pItem;
CItem * pItemNext;
AssertSz(Head() == NULL, "Failed to release all children");
AssertSz(Next() == NULL, "Should never have ANY siblings");
for (pItem = Head(); pItem != NULL; pItem = pItemNext) {
pItemNext = pItem->Next();
delete pItem;
}
if (m_hCertStoreMy != NULL) {
f = CertCloseStore(m_hCertStoreMy, CERT_CLOSE_STORE_CHECK_FLAG);
if (!f) {
AssertSz(FALSE, "My Cert store did not close completely");
}
m_hCertStoreMy = NULL;
}
return TRUE;
}
HRESULT CMessage::AddToMessage(DWORD * pulLayer, IMimeMessage * pmm, HWND hwnd)
{
*pulLayer = 0;
return AddToMessage(pulLayer, pmm, hwnd, Head());
}
HRESULT CMessage::AddToMessage(DWORD * pulLayer, IMimeMessage * pmm,
HWND hwnd, CItem * pitem)
{
HRESULT hr;
if (pitem == NULL) {
return S_OK;
}
hr = pitem->AddToMessage(pulLayer, pmm, hwnd);
if (FAILED(hr)) return hr;
return AddToMessage(pulLayer, pmm, hwnd, pitem->Next());
}
HRESULT CMessage::Decode(HWND hwnd)
{
DWORD cLayers;
HBODY hNode;
HRESULT hr;
DWORD iLayer;
PCCERT_CONTEXT pccert = NULL;
IMimeBody * pmb = NULL;
IMimeBody * pmbReceipt = NULL;
IMimeMessage * pmm = NULL;
IMimeMessage * pmmReceipt = NULL;
IMimeSecurity * pms = NULL;
IMimeSecurity2 * pms2 = NULL;
IPersistFile * pfile = NULL;
IPersistFile * pfileOut = NULL;
WCHAR rgchW[MAX_PATH];
DWORD * rgdwSecurityType = NULL;
DWORD * rgdwValidity = NULL;
PCCERT_CONTEXT * rgpccert = NULL;
PROPVARIANT * rgpvAlgHash = NULL;
ULONG ulType;
PROPVARIANT var;
// Build the message tree and attach the input file
hr = CoCreateInstance(CLSID_IMimeMessage, NULL, CLSCTX_INPROC_SERVER,
IID_IMimeMessage, (LPVOID *) &pmm);
if (FAILED(hr)) goto exit;
hr = pmm->InitNew();
if (FAILED(hr)) goto exit;
// Load the file
hr = pmm->QueryInterface(IID_IPersistFile, (LPVOID *) &pfile);
if (FAILED(hr)) goto exit;
MultiByteToWideChar(CP_ACP, 0, GetCipherFile(), -1,
rgchW, sizeof(rgchW)/sizeof(rgchW[0]));
hr = pfile->Load(rgchW, STGM_READ | STGM_SHARE_EXCLUSIVE);
if (FAILED(hr)) goto exit;
//
// Try using the IMimeSecurity2 interface if it exists and will work
hr = pmm->QueryInterface(IID_IMimeSecurity2, (LPVOID *) &pms2);
if (FAILED(hr)) {
if (hr == E_NOINTERFACE) goto TryOldCode;
goto exit;
}
hr = pms2->Decode(hwnd, 0, this);
if (FAILED(hr)) {
if (hr != E_FAIL) goto exit;
TryOldCode:
// Start up the S/MIME engine
hr = CoCreateInstance(CLSID_IMimeSecurity, NULL, CLSCTX_INPROC_SERVER,
IID_IMimeSecurity, (LPVOID *) &pms);
if (FAILED(hr)) goto exit;
hr = pms->InitNew();
if (FAILED(hr)) goto exit;
// Bind in the HWND
hr = pmm->BindToObject(HBODY_ROOT, IID_IMimeBody, (LPVOID *) &pmb);
if (FAILED(hr)) goto exit;
var.vt = VT_UI4;
var.ulVal = (DWORD) hwnd;
hr = pmb->SetOption(OID_SECURITY_HWND_OWNER, &var);
if (FAILED(hr)) goto exit;
pmb->Release(); pmb = NULL;
// Now decode the message
hr = pms->DecodeMessage(pmm, 0);
if (FAILED(hr)) goto exit;
}
//
hNode = HBODY_ROOT;
while (TRUE) {
hr = pmm->BindToObject(hNode, IID_IMimeBody, (LPVOID *) &pmb);
if (FAILED(hr)) goto exit;
// Create the fun objects from the properties
hr = pmb->GetOption(OID_SECURITY_TYPE, &var);
if (FAILED(hr)) goto exit;
ulType = var.ulVal;
if (ulType & MST_THIS_SIGN) {
HTREEITEM hitem;
TV_INSERTSTRUCT tvins;
CSignInfo * psi = new CSignInfo(STATE_READ, &RootMsg);
CSignData * psd = new CSignData(STATE_READ);
psd->SetParent(psi);
tvins.item.mask = TVIF_TEXT | TVIF_PARAM;
tvins.hParent = TreeView_GetRoot(HwndTree);
tvins.hInsertAfter = TVI_LAST;
tvins.item.pszText = "Signature Layer";
tvins.item.cchTextMax = 15;
tvins.item.iImage = 1;
tvins.item.iSelectedImage = tvins.item.iImage;
tvins.item.lParam = (DWORD) psi;
if (ulType & MST_BLOB_FLAG) {
psi->m_fBlob = TRUE;
}
hitem = TreeView_InsertItem(HwndTree, &tvins);
TreeView_Expand(HwndTree, tvins.hParent, TVE_EXPAND);
tvins.item.mask = TVIF_TEXT | TVIF_PARAM;
tvins.hParent = hitem;
tvins.hInsertAfter = TVI_LAST;
tvins.item.pszText = "Signature";
tvins.item.cchTextMax = 15;
tvins.item.iImage = 2;
tvins.item.iSelectedImage = tvins.item.iImage;
tvins.item.lParam = (DWORD) psd;
TreeView_InsertItem(HwndTree, &tvins);
TreeView_Expand(HwndTree, tvins.hParent, TVE_EXPAND);
hr = pmb->GetOption(OID_SECURITY_RO_MSG_VALIDITY, &var);
if (FAILED(hr)) goto exit;
psd->m_ulValidity = var.ulVal;
// hr = pmb->GetOption(OID_SECURITY_HCERTSTORE, &var);
// if (FAILED(hr)) goto exit;
hr = pmb->GetOption(OID_SECURITY_CERT_SIGNING, &var);
if (FAILED(hr)) goto exit;
psd->m_pccert = (PCCERT_CONTEXT) var.ulVal;
// hr = pmb->GetOption(OID_SECURITY_ALG_HASH, &var);
// if (FAILED(hr)) goto exit;
}
if (ulType & MST_THIS_ENCRYPT) {
HTREEITEM hitem;
TV_INSERTSTRUCT tvins;
CEnvData * ped = new CEnvData(STATE_READ, &RootMsg);
tvins.item.mask = TVIF_TEXT | TVIF_PARAM;
tvins.hParent = TreeView_GetRoot(HwndTree);
tvins.hInsertAfter = TVI_LAST;
tvins.item.pszText = "Envelope";
tvins.item.cchTextMax = 15;
tvins.item.iImage = 1;
tvins.item.iSelectedImage = tvins.item.iImage;
tvins.item.lParam = (DWORD) ped;
hitem = TreeView_InsertItem(HwndTree, &tvins);
hr = pmb->GetOption(OID_SECURITY_CERT_DECRYPTION, &var);
if (FAILED(hr)) goto exit;
Assert(FALSE);
// ped->m_pccert = (PCCERT_CONTEXT) var.ulVal;
}
if (ulType & MST_RECEIPT_REQUEST) {
CERT_ALT_NAME_ENTRY rgNames[1];
CERT_ALT_NAME_INFO myNames = {1, rgNames};
rgNames[0].dwAltNameChoice = CERT_ALT_NAME_RFC822_NAME;
rgNames[0].pwszRfc822Name = L"[email protected]";
if (HCertStoreMy == NULL) {
HCertStoreMy = CertOpenStore(CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING,
NULL, CERT_SYSTEM_STORE_CURRENT_USER,
L"MY");
if (HCertStoreMy == NULL) goto exit;
}
if (SignHash.cbData != 0) {
pccert = CertFindCertificateInStore(HCertStoreMy,
X509_ASN_ENCODING, 0,
CERT_FIND_SHA1_HASH,
&SignHash, NULL);
if (pccert == NULL) goto exit;
}
// hr = MimeOleCreateReceipt(pmm, pccert, hwnd, &pmmReceipt,
// &myNames);
if (FAILED(hr)) goto exit;
// Get the root body
hr = pmmReceipt->BindToObject(HBODY_ROOT, IID_IMimeBody,
(LPVOID *) &pmbReceipt);
if (FAILED(hr)) goto exit;
// Set the HWND for CAPI calls
var.vt = VT_UI4;
var.ulVal = (ULONG) hwnd;
hr = pmbReceipt->SetOption(OID_SECURITY_HWND_OWNER, &var);
if (FAILED(hr)) goto exit;
var.vt = VT_UI4;
var.ulVal = MST_THIS_SIGN | MST_THIS_BLOBSIGN;
hr = pmbReceipt->SetOption(OID_SECURITY_TYPE, &var);
if (FAILED(hr)) goto exit;
var.vt = VT_BLOB;
var.blob.pBlobData = (LPBYTE) RgbSHA1AlgId;
var.blob.cbSize = CbSHA1AlgId;
hr = pmbReceipt->SetOption(OID_SECURITY_ALG_HASH, &var);
if (FAILED(hr)) goto exit;
var.vt = VT_UI4;
var.ulVal = (ULONG) pccert;
hr = pmbReceipt->SetOption(OID_SECURITY_CERT_SIGNING, &var);
if (hr == S_OK) {
hr = pmmReceipt->QueryInterface(IID_IPersistFile, (LPVOID *) &pfileOut);
if (FAILED(hr)) goto exit;
hr = pfileOut->Save(L"c:\\receipt.eml", FALSE);
if (FAILED(hr)) goto exit;
}
pmbReceipt->Release();
}
if (pmb->IsContentType(STR_CNT_MULTIPART, "y-security") != S_OK) {
break;
}
if (hNode == HBODY_ROOT) {
pmb->GetHandle(&hNode);
}
pmb->Release(); pmb = NULL;
hr = pmm->GetBody(IBL_FIRST, hNode, &hNode);
if (FAILED(hr)) goto exit;
}
hr = S_OK;
exit:
if (pfileOut != NULL) pfileOut->Release();
if (pfile != NULL) pfile->Release();
if (pmb != NULL) pmb->Release();
if (pms != NULL) pms->Release();
if (pmm != NULL) pmm->Release();
if (pmmReceipt != NULL) pmmReceipt->Release();
if (pccert != NULL) CertFreeCertificateContext(pccert);
return hr;
}
HRESULT CMessage::Encode(HWND hwnd)
{
DWORD cLayers;
HBODY hbody;
HRESULT hr;
HCERTSTORE hstore = NULL;
IImnAccount * pAccount = NULL;
PCCERT_CONTEXT pccertEncrypt = NULL;
LPSTR pchBody;
IPersistFile * pfileIn = NULL;
IPersistFile * pfileOut = NULL;
IMimeBody * pmb = NULL;
IMimeMessage * pmm = NULL;
IMimeSecurity * pms = NULL;
IMimeSecurity2 * pms2 = NULL;
LPSTREAM pstmBody = NULL;
LPSTREAM pstmFile = NULL;
WCHAR rgchW[CCH_OPTION_STRING];
DWORD ulLayers = 0;
PROPVARIANT var;
// Build the message tree and attach the body
hr = CoCreateInstance(CLSID_IMimeMessage, NULL, CLSCTX_INPROC_SERVER,
IID_IMimeMessage, (LPVOID *) &pmm);
if (FAILED(hr)) goto exit;
hr = pmm->InitNew();
if (FAILED(hr)) goto exit;
pchBody = GetPlainFile();
if ((*pchBody == 0) || (_stricmp(pchBody, "<none>") == 0)) {
// Create the body stream
hr = CreateStreamOnHGlobal( NULL, TRUE, &pstmBody);
if (FAILED(hr)) goto exit;
hr = pstmBody->Write(RgchBody, lstrlen(RgchBody), NULL);
if (FAILED(hr)) goto exit;
// Attach the body to the message
hr = pmm->SetTextBody(TXT_PLAIN, IET_8BIT, NULL, pstmBody, &hbody);
if (FAILED(hr)) goto exit;
//
}
else if (_stricmp(pchBody, "<example>") == 0) {
// Create the body stream
hr = CreateStreamOnHGlobal( NULL, TRUE, &pstmBody);
if (FAILED(hr)) goto exit;
hr = pstmBody->Write(RgchExample, lstrlen(RgchExample), NULL);
if (FAILED(hr)) goto exit;
// Get the root body
hr = pmm->BindToObject(HBODY_ROOT, IID_IMimeBody, (LPVOID *) &pmb);
if (FAILED(hr)) goto exit;
hr = pmb->SetData(IET_BINARY, "OID", szOID_RSA_data,
IID_IStream, pstmBody);
if (FAILED(hr)) goto exit;
pmb->Release(); pmb = NULL;
}
else {
MultiByteToWideChar(CP_ACP, 0, pchBody, -1,
rgchW, sizeof(rgchW)/sizeof(rgchW[0]));
// Load the file
hr = pmm->QueryInterface(IID_IPersistFile, (LPVOID *) &pfileIn);
if (FAILED(hr)) goto exit;
hr = pfileIn->Load(rgchW, STGM_READ | STGM_SHARE_EXCLUSIVE);
if (FAILED(hr)) goto exit;
}
var.vt = VT_BOOL;
var.boolVal = TRUE;
hr = pmm->SetOption(OID_SAVEBODY_KEEPBOUNDARY, &var);
if (hr) goto exit;
// Find out what goes where for initialization
hr = AddToMessage(&cLayers, pmm, hwnd);
if (FAILED(hr)) goto exit;
if (1) {
hr = pmm->QueryInterface(IID_IMimeSecurity2, (LPVOID *) &pms2);
if (FAILED(hr)) goto exit;
hr = pms2->Encode(hwnd, SEF_SENDERSCERTPROVIDED |
SEF_ENCRYPTWITHNOSENDERCERT);
if (FAILED(hr)) goto exit;
pms2->Release(); pms2 = NULL;
}
else {
// Get the root body
hr = pmm->BindToObject(HBODY_ROOT, IID_IMimeBody, (LPVOID *) &pmb);
if (FAILED(hr)) goto exit;
// Set the HWND for CAPI calls
var.vt = VT_UI4;
var.ulVal = (ULONG) hwnd;
hr = pmb->SetOption(OID_SECURITY_HWND_OWNER, &var);
if (FAILED(hr)) goto exit;
pmb->Release(); pmb = NULL;
// Sometimes we must force the encode outside of the Save call
if (1) {
hr = CoCreateInstance(CLSID_IMimeSecurity, NULL, CLSCTX_INPROC_SERVER,
IID_IMimeSecurity, (LPVOID *) &pms);
if (FAILED(hr)) goto exit;
hr = pms->InitNew();
if (FAILED(hr)) goto exit;
hr = pms->EncodeBody(pmm, HBODY_ROOT, EBF_RECURSE |
SEF_SENDERSCERTPROVIDED |
SEF_ENCRYPTWITHNOSENDERCERT |
EBF_COMMITIFDIRTY);
if (FAILED(hr)) goto exit;
pms->Release(); pms = NULL;
}
}
// Set the subject
var.vt = VT_LPSTR;
var.pszVal = "Test subject";
hr = pmm->SetBodyProp(HBODY_ROOT, STR_HDR_SUBJECT, 0, &var);
if (FAILED(hr)) goto exit;
// Deal with either dump to file or send via SMTP
if (m_fToFile) {
// Dump to a file
hr = pmm->QueryInterface(IID_IPersistFile, (LPVOID *) &pfileOut);
if (FAILED(hr)) goto exit;
MultiByteToWideChar(CP_ACP, 0, GetCipherFile(), -1,
rgchW, sizeof(rgchW)/sizeof(rgchW[0]));
hr = pfileOut->Save(rgchW, FALSE);
if (FAILED(hr)) goto exit;
}
else {
SMTPMESSAGE rMessage = {0};
INETSERVER rServer;
char szAccount[] = "SMimeTst";
INETADDR rgAddress[11];
if (PAcctMan == NULL) {
hr = CoCreateInstance(CLSID_ImnAccountManager, NULL, CLSCTX_INPROC_SERVER,
IID_IImnAccountManager, (LPVOID *) &PAcctMan);
if (FAILED(hr)) goto exit;
hr = PAcctMan->Init(NULL);
if (FAILED(hr)) goto exit;
}
if (PSmtp == NULL) {
// Create smtp transport
hr = HrCreateSMTPTransport(&PSmtp);
if (FAILED(hr)) goto exit;
}
memset(&rgAddress, 0, sizeof(rgAddress));
rMessage.rAddressList.prgAddress = rgAddress;
rMessage.rAddressList.cAddress = 2;
strcpy(rgAddress[0].szEmail, szSenderEmail);
rgAddress[0].addrtype = ADDR_FROM;
strcpy(rgAddress[1].szEmail, szRecipientEmail);
rgAddress[1].addrtype = ADDR_TO;
pmm->GetMessageSource(&rMessage.pstmMsg, 0);
pmm->GetMessageSize(&rMessage.cbSize, 0);
hr = PAcctMan->FindAccount(AP_ACCOUNT_NAME, szAccount, &pAccount);
if (FAILED(hr)) goto exit;
hr = PSmtp->InetServerFromAccount(pAccount, &rServer);
if (FAILED(hr)) goto exit;
hr = PSmtp->Connect(&rServer, TRUE, TRUE);
if (FAILED(hr)) goto exit;
WaitForCompletion(MsgSMTP, SMTP_CONNECTED);
pAccount->Release(); pAccount = NULL;
hr = PSmtp->SendMessage(&rMessage);
WaitForCompletion(MsgSMTP, SMTP_SEND_MESSAGE);
hr = PSmtp->CommandQUIT();
if (FAILED(hr)) goto exit;
WaitForCompletion(MsgSMTP, SMTP_QUIT);
}
hr = NULL;
exit:
if (pAccount != NULL) pAccount->Release();
if (pfileIn != NULL) pfileIn->Release();
if (pfileOut != NULL) pfileOut->Release();
if (pstmBody != NULL) pstmBody->Release();
if (pstmFile != NULL) pstmFile->Release();
if (pms2 != NULL) pms2->Release();
if (pms != NULL) pms->Release();
if (pmb != NULL) pmb->Release();
if (pmm != NULL) pmm->Release();
return hr;
}
STDMETHODIMP CMessage::QueryInterface(REFIID riid, LPVOID *ppv)
{
return E_FAIL;
}
STDMETHODIMP_(ULONG) CMessage::AddRef(void)
{
return E_FAIL;
}
STDMETHODIMP_(ULONG) CMessage::Release(void)
{
return E_FAIL;
}
STDMETHODIMP CMessage::FindKeyFor(HWND hwnd, DWORD dwFlags, DWORD dwRecipIndex,
const CMSG_CMS_RECIPIENT_INFO * pRecipInfo,
DWORD * pdwCtrl, CMS_CTRL_DECRYPT_INFO * pDecryptInfo,
PCCERT_CONTEXT * ppcert)
{
// Only support mail list recipients
if (pRecipInfo->dwRecipientChoice != CMSG_MAIL_LIST_RECIPIENT) {
return S_FALSE;
}
*pdwCtrl = CMSG_CTRL_MAIL_LIST_DECRYPT;
return CMailListKey::FindKeyFor(hwnd, dwFlags, dwRecipIndex,
pRecipInfo, pDecryptInfo);
}
STDMETHODIMP CMessage::GetParameters(PCCERT_CONTEXT, LPVOID, DWORD *, LPBYTE *)
{
return E_FAIL;
}