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.

1323 lines
40 KiB

  1. // implements much of the exported CKey
  2. #include "stdafx.h"
  3. #include "resource.h"
  4. #include "KeyObjs.h"
  5. #include "passdlg.h"
  6. #include "AdmnInfo.h"
  7. #include "NKChseCA.h"
  8. #include "NKDN.h"
  9. #include "NKDN2.h"
  10. #include "NKKyInfo.h"
  11. #include "NKUsrInf.h"
  12. #include "creating.h"
  13. #include "resource.h"
  14. #include "intrlkey.h"
  15. #include <iis64.h>
  16. #define SECURITY_WIN32
  17. extern "C"
  18. {
  19. #include <wincrypt.h>
  20. // #include <sslsp.h>
  21. #include <schnlsp.h>
  22. #include <sspi.h>
  23. #include <ISSPERR.h>
  24. }
  25. #include "mismtchd.h"
  26. #define CRLF "\r\n"
  27. // NON_LOCALIZABLE strings for use in the request header
  28. #define HEADER_ADMINISTRATOR _T(CRLF "Webmaster: ")
  29. #define HEADER_PHONE _T(CRLF "Phone: ")
  30. #define HEADER_SERVER _T(CRLF "Server: ")
  31. #define HEADER_COMMON_NAME _T(CRLF CRLF "Common-name: ")
  32. #define HEADER_ORG_UNIT _T(CRLF "Organization Unit: ")
  33. #define HEADER_ORGANIZATION _T(CRLF "Organization: ")
  34. #define HEADER_LOCALITY _T(CRLF "Locality: ")
  35. #define HEADER_STATE _T(CRLF "State: ")
  36. #define HEADER_COUNTRY _T(CRLF "Country: ")
  37. #define HEADER_END_SPACING _T(CRLF CRLF )
  38. // defines taken from the old KeyGen utility
  39. #define MESSAGE_HEADER "-----BEGIN NEW CERTIFICATE REQUEST-----\r\n"
  40. #define MESSAGE_TRAILER "-----END NEW CERTIFICATE REQUEST-----\r\n"
  41. #define MIME_TYPE "Content-Type: application/x-pkcs10\r\n"
  42. #define MIME_ENCODING "Content-Transfer-Encoding: base64\r\n\r\n"
  43. int HTUU_encode(unsigned char *bufin, unsigned int nbytes, char *bufcoded);
  44. #define BACKUP_ID 'KRBK'
  45. IMPLEMENT_DYNCREATE(CKey, CTreeItem);
  46. //------------------------------------------------------------------------------
  47. CKey::CKey():
  48. m_cbPrivateKey( 0 ),
  49. m_pPrivateKey( NULL ),
  50. m_cbCertificate( 0 ),
  51. m_pCertificate( NULL ),
  52. m_cbCertificateRequest( 0 ),
  53. m_pCertificateRequest( NULL )
  54. {;}
  55. //------------------------------------------------------------------------------
  56. CKey::~CKey()
  57. {
  58. LPTSTR pBuff;
  59. // specifically write zeros out over the password
  60. try
  61. {
  62. pBuff = m_szPassword.GetBuffer(256);
  63. }
  64. catch( CException e )
  65. {
  66. pBuff = NULL;
  67. }
  68. if ( pBuff )
  69. {
  70. // zero out the buffer
  71. ZeroMemory( pBuff, 256 );
  72. // release the buffer
  73. m_szPassword.ReleaseBuffer(0);
  74. }
  75. // zero out the private key and the certificate
  76. if ( m_pPrivateKey )
  77. {
  78. // zero out the buffer
  79. ZeroMemory( m_pPrivateKey, m_cbPrivateKey );
  80. // free the pointer
  81. GlobalFree( (HANDLE)m_pPrivateKey );
  82. m_pPrivateKey = NULL;
  83. }
  84. if ( m_pCertificate )
  85. {
  86. // zero out the buffer
  87. ZeroMemory( m_pCertificate, m_cbCertificate );
  88. // free the pointer
  89. GlobalFree( (HANDLE)m_pCertificate );
  90. m_pCertificate = NULL;
  91. }
  92. if ( m_pCertificateRequest )
  93. {
  94. // zero out the buffer
  95. ZeroMemory( m_pCertificateRequest, m_cbCertificateRequest );
  96. // free the pointer
  97. GlobalFree( (HANDLE)m_pCertificateRequest );
  98. m_pCertificate = NULL;
  99. }
  100. }
  101. //------------------------------------------------------------------------------
  102. CKey* CKey::PClone( void )
  103. {
  104. CKey* pClone = NULL;
  105. // TRY to make a new key object
  106. try
  107. {
  108. pClone = new CKey();
  109. // copy over all the data
  110. pClone->CopyDataFrom( this );
  111. }
  112. catch( CException e )
  113. {
  114. // if the object had been made, delete it
  115. if ( pClone )
  116. delete pClone;
  117. return NULL;
  118. }
  119. return pClone;
  120. }
  121. //------------------------------------------------------------------------------
  122. void CKey::CopyDataFrom( CKey* pKey )
  123. {
  124. // make sure this is ok
  125. ASSERT( pKey );
  126. ASSERT( pKey->IsKindOf(RUNTIME_CLASS(CKey)) );
  127. if ( !pKey ) return;
  128. // delete any data currently in this key
  129. // zero out the private key and the certificate
  130. if ( m_pPrivateKey )
  131. {
  132. ZeroMemory( m_pPrivateKey, m_cbPrivateKey );
  133. GlobalFree( (HANDLE)m_pPrivateKey );
  134. m_pPrivateKey = NULL;
  135. }
  136. if ( m_pCertificate )
  137. {
  138. ZeroMemory( m_pCertificate, m_cbCertificate );
  139. GlobalFree( (HANDLE)m_pCertificate );
  140. m_pCertificate = NULL;
  141. }
  142. if ( m_pCertificateRequest )
  143. {
  144. ZeroMemory( m_pCertificateRequest, m_cbCertificateRequest );
  145. GlobalFree( (HANDLE)m_pCertificateRequest );
  146. m_pCertificate = NULL;
  147. }
  148. // copy over the basic stuff
  149. m_szItemName = pKey->m_szItemName;
  150. m_iImage = pKey->m_iImage;
  151. m_szPassword = pKey->m_szPassword;
  152. m_cbPrivateKey = pKey->m_cbPrivateKey;
  153. m_cbCertificate = pKey->m_cbCertificate;
  154. m_cbCertificateRequest = pKey->m_cbCertificateRequest;
  155. // now the pointer based data
  156. if ( pKey->m_pPrivateKey )
  157. {
  158. m_pPrivateKey = GlobalAlloc( GPTR, m_cbPrivateKey );
  159. if ( !m_pPrivateKey ) AfxThrowMemoryException();
  160. memcpy( m_pPrivateKey, pKey->m_pPrivateKey, m_cbPrivateKey );
  161. }
  162. if ( pKey->m_pCertificate )
  163. {
  164. m_pCertificate = GlobalAlloc( GPTR, m_cbCertificate );
  165. if ( !m_pCertificate ) AfxThrowMemoryException();
  166. memcpy( m_pCertificate, pKey->m_pCertificate, m_cbCertificate );
  167. }
  168. if ( pKey->m_pCertificateRequest )
  169. {
  170. m_pCertificateRequest = GlobalAlloc( GPTR, m_cbCertificateRequest );
  171. if ( !m_pCertificateRequest ) AfxThrowMemoryException();
  172. memcpy( m_pCertificateRequest, pKey->m_pCertificateRequest,
  173. m_cbCertificateRequest );
  174. }
  175. }
  176. //------------------------------------------------------------------------------
  177. void CKey::SetName( CString &szNewName )
  178. {
  179. m_szItemName = szNewName;
  180. UpdateCaption();
  181. SetDirty( TRUE );
  182. }
  183. //------------------------------------------------------------------------------
  184. void CKey::UpdateIcon( void )
  185. {
  186. // if there is no certificate, then the immature key
  187. if ( !m_pCertificate )
  188. {
  189. m_iImage = TREE_ICON_KEY_IMMATURE;
  190. FSetImage( m_iImage );
  191. return;
  192. }
  193. // there is a certificate, but we need to see if it has
  194. // expired or not. We do that by cracking the certificate
  195. // default the key to being ok
  196. m_iImage = TREE_ICON_KEY_OK;
  197. CKeyCrackedData cracker;
  198. // crack the key
  199. if ( cracker.CrackKey(this) )
  200. {
  201. // get the expiration time
  202. CTime ctimeExpires( cracker.GetValidUntil() );
  203. // get the current time
  204. CTime ctimeCurrent = CTime::GetCurrentTime();
  205. // test if it has expired first
  206. if ( ctimeCurrent > ctimeExpires )
  207. m_iImage = TREE_ICON_KEY_EXPIRED;
  208. }
  209. // set the image
  210. FSetImage( m_iImage );
  211. }
  212. //------------------------------------------------------------------------------
  213. BOOL CKey::FInstallCertificate( CString szPath, CString szPass )
  214. {
  215. CFile cfile;
  216. PVOID pData = NULL;
  217. BOOL fSuccess =FALSE;;
  218. // open the file
  219. if ( !cfile.Open( szPath, CFile::modeRead | CFile::shareDenyNone ) )
  220. return FALSE;
  221. // how big is the file - add one so we can zero terminate the buffer
  222. DWORD cbCertificate = cfile.GetLength() + 1;
  223. // make sure the file has some size
  224. if ( !cbCertificate )
  225. {
  226. AfxMessageBox( IDS_ERR_INVALID_CERTIFICATE, MB_OK | MB_ICONINFORMATION );
  227. return FALSE;
  228. }
  229. // put the rest of the operation in a try/catch
  230. // specifically write zeros out over the password
  231. try
  232. {
  233. // allocate space for the data
  234. pData = GlobalAlloc( GPTR, cbCertificate );
  235. if ( !pData ) AfxThrowMemoryException();
  236. // copy in the data from the file to the pointer - will throw and exception
  237. DWORD cbRead = cfile.Read( pData, cbCertificate );
  238. // zero terminate for decoding
  239. ((BYTE*)pData)[cbRead] = 0;
  240. // great. The last thing left is to uudecode the data we got
  241. uudecode_cert( (char*)pData, &cbCertificate );
  242. // close the file
  243. cfile.Close();
  244. // install the certificate
  245. fSuccess = FInstallCertificate( pData, cbCertificate, szPass );
  246. }
  247. catch( CException e )
  248. {
  249. // if the pointer was allocated, deallocate it
  250. if ( pData )
  251. {
  252. GlobalFree( pData );
  253. pData = NULL;
  254. }
  255. // return failure
  256. return FALSE;
  257. }
  258. // return success
  259. return fSuccess;
  260. }
  261. //------------------------------------------------------------------------------
  262. // it is up to the module to verify the certificate
  263. BOOL CKey::FInstallCertificate( PVOID pCert, DWORD cbCert, CString &szPass )
  264. {
  265. // cache the old certificate in case the new one fails
  266. DWORD old_cbCertificate = m_cbCertificate;
  267. PVOID old_pCertificate = m_pCertificate;
  268. // set the new one into place
  269. m_cbCertificate = cbCert;
  270. m_pCertificate = pCert;
  271. /* // MOVED TO THE MODULE
  272. // verify the password
  273. if ( !FVerifyValidPassword(szPass) )
  274. {
  275. // resore the old values
  276. m_cbCertificate = old_cbCertificate;
  277. m_pCertificate = old_pCertificate;
  278. // dispose of the new stuff
  279. GlobalFree( pCert );
  280. // return false
  281. return FALSE;
  282. }
  283. */
  284. // Re-Set the password, incase we stored a request from Backup file.
  285. m_szPassword = szPass;
  286. // it checks out ok, so we can get rid of the old stuff
  287. // be careful not to get rid of the current test cert if that is whats there
  288. if ( old_pCertificate && (old_pCertificate != pCert) )
  289. {
  290. GlobalFree( old_pCertificate );
  291. old_pCertificate = NULL;
  292. }
  293. // mark the key as dirty
  294. SetDirty( TRUE );
  295. return TRUE;
  296. }
  297. //------------------------------------------------------------------------------
  298. // verfying a valid password is now a several-stop process. First we have to verify
  299. // that the certificate is the correct one that was requested. Apparenly lots of
  300. // users out there are attempting to install either invalid certificates, or valid
  301. // certificates on the wrong key. Then, when they can't figure out that they messed
  302. // it up, they call us. Or Verisign. To do this we use CAPI2 to get a certificate context
  303. // from the certificate. If that fails is in an invalid cert (say... an EXE file).
  304. // Then we test that certificat's public key to see if it matches the public key
  305. // stored in the request (which we also have to use CAPI2 to crack) If there is no
  306. // request (keyset files) then tough bannanas. They will have to rely on the errors
  307. // returned by the AcquireCredentialsHandle routine.
  308. BOOL CKey::FVerifyValidPassword( CString szPassword )
  309. {
  310. PVOID pRequestObject = NULL;
  311. PCCERT_CONTEXT pcontextCertificate = NULL;
  312. BOOL fAnswer = TRUE;
  313. SSL_CREDENTIAL_CERTIFICATE creds;
  314. CredHandle hCreds;
  315. SECURITY_STATUS scRet;
  316. TimeStamp ts;
  317. DWORD err;
  318. CString sz;
  319. CString szErr;
  320. // skip the private, internal request header
  321. PUCHAR pRequest = NULL;
  322. DWORD cbRequest = 0;
  323. PUCHAR pcert = (PUCHAR)m_pCertificate;
  324. DWORD cbcert = m_cbCertificate;
  325. // if the request is there, get its context
  326. if ( m_pCertificateRequest )
  327. {
  328. // see if this request has a header block in front of it. If it does, then use
  329. // it to get the real request. If it doesn't then just use the request.
  330. // if it does have a header the first DWORD will be REQUEST_HEADER_IDENTIFIER
  331. if ( *(DWORD*)m_pCertificateRequest == REQUEST_HEADER_IDENTIFIER )
  332. {
  333. // get the real request that comes after the request header
  334. pRequest = (PUCHAR)m_pCertificateRequest +
  335. ((LPREQUEST_HEADER)m_pCertificateRequest)->cbSizeOfHeader;
  336. cbRequest = ((LPREQUEST_HEADER)m_pCertificateRequest)->cbRequestSize;
  337. }
  338. else
  339. {
  340. // there is no header
  341. pRequest = (PUCHAR)m_pCertificateRequest;
  342. cbRequest = m_cbCertificateRequest;
  343. }
  344. // note that if the request isn't there or if it is invalid it is still
  345. // ok to try and verify the certificate
  346. DWORD cbBuffSize = 0;
  347. // start by decoding the request object - get the size of the required buffer
  348. CryptDecodeObject( X509_ASN_ENCODING,
  349. X509_CERT_REQUEST_TO_BE_SIGNED,
  350. pRequest,
  351. cbRequest,
  352. 0,
  353. NULL,
  354. &cbBuffSize );
  355. // now make an attempt to decode it
  356. pRequestObject = GlobalAlloc( GPTR, cbBuffSize );
  357. if ( !pRequestObject )
  358. goto GetCredentials;
  359. if ( !CryptDecodeObject( X509_ASN_ENCODING,
  360. X509_CERT_REQUEST_TO_BE_SIGNED,
  361. pRequest,
  362. cbRequest,
  363. 0,
  364. pRequestObject,
  365. &cbBuffSize ) )
  366. {
  367. GlobalFree( pRequestObject );
  368. pRequestObject = NULL;
  369. goto GetCredentials;
  370. }
  371. }
  372. GetCredentials:
  373. // OK. Verisign and Certsrv and probably others too wrap the certificate in a wrapper
  374. // that, while following the normal formatting convensions, causes the context routine
  375. // below to fail. This means that we have to detect if the wrapper is there and, if it
  376. // is, we need to skip it. Fortunately, the wrapper contains the word "certificate"
  377. // yes, this is sorta grungy, but its what petesk said to do.
  378. sz = pcert;
  379. sz = sz.Left(20);
  380. if ( sz.Find("certificate") == 6 )
  381. {
  382. pcert += 17;
  383. }
  384. // get the context on the certificate
  385. pcontextCertificate = CertCreateCertificateContext( X509_ASN_ENCODING, pcert, cbcert );
  386. // if we were unable to create the context, then fail with an appropriate error message
  387. if ( !pcontextCertificate )
  388. {
  389. // get the error for the dialog
  390. err = GetLastError();
  391. // tell the user that they chose an invalid certificate
  392. sz.LoadString( IDS_CERTERR_INVALID_CERTIFICATE );
  393. sz.Format( "%s%x", sz, err );
  394. AfxMessageBox( sz );
  395. // time to leave with a failure
  396. fAnswer = FALSE;
  397. goto cleanup;
  398. }
  399. // if we have both a cert context AND a decoded request object, then we can confirm that
  400. // they are in fact matched to each other.
  401. if ( pcontextCertificate && pRequestObject )
  402. {
  403. // use CAPI2 to do the comparison between the two public key info structures
  404. if ( !CertComparePublicKeyInfo( X509_ASN_ENCODING,
  405. &((PCERT_REQUEST_INFO)pRequestObject)->SubjectPublicKeyInfo,
  406. &pcontextCertificate->pCertInfo->SubjectPublicKeyInfo ) )
  407. {
  408. // The certificate is mis-matched to the request. Fail with the right message
  409. CMismatchedCertDlg mismatchdlg(
  410. &((PCERT_REQUEST_INFO)pRequestObject)->Subject,
  411. &pcontextCertificate->pCertInfo->Subject);
  412. mismatchdlg.DoModal();
  413. fAnswer = FALSE;
  414. goto cleanup;
  415. }
  416. }
  417. // use SSL to finish verifying the password
  418. // fill in the credentials record
  419. creds.cbPrivateKey = m_cbPrivateKey;
  420. creds.pPrivateKey = (PUCHAR)m_pPrivateKey;
  421. creds.cbCertificate = m_cbCertificate;
  422. creds.pCertificate = (PUCHAR)m_pCertificate;
  423. // prepare the password
  424. creds.pszPassword = (PSTR)LPCTSTR(szPassword);
  425. // attempt to get the credentials
  426. scRet = AcquireCredentialsHandleW( NULL, // My name (ignored)
  427. UNISP_NAME_W, // Package
  428. SECPKG_CRED_INBOUND, // Use
  429. NULL, // Logon ID (ignored)
  430. &creds, // auth data
  431. NULL, // dce-stuff
  432. NULL, // dce-stuff
  433. &hCreds, // handle
  434. &ts ); // we really get it below
  435. // check the results
  436. if ( FAILED(scRet) )
  437. {
  438. sz.Empty();
  439. // add on the appropriate sub-error message
  440. switch( scRet )
  441. {
  442. case SEC_E_UNKNOWN_CREDENTIALS:
  443. case SEC_E_NO_CREDENTIALS:
  444. case SEC_E_INTERNAL_ERROR:
  445. // Unfortunately, SChannel returns the "internal error" when a bad password
  446. // is returned. There may or may not be other circumstances under which this
  447. // error is returned, but this is by far the most common. Also I taked to
  448. // PeteSk about it and he agreed that this is how it should be used.
  449. // bad password
  450. sz.LoadString( IDS_CERTERROR_BADPASSWORD );
  451. break;
  452. case SEC_E_SECPKG_NOT_FOUND:
  453. case SEC_E_BAD_PKGID:
  454. // the system does not have the package installed
  455. sz.LoadString( IDS_CERTERROR_PACKAGELOAD_ERROR );
  456. break;
  457. case SEC_E_INSUFFICIENT_MEMORY:
  458. sz.LoadString( IDS_CERTERR_LOMEM );
  459. break;
  460. case SEC_E_CANNOT_INSTALL:
  461. sz.LoadString( EDS_CERTERR_SCHNL_BAD_INIT );
  462. break;
  463. default:
  464. sz.LoadString( IDS_CERTERR_SCHNL_GENERIC );
  465. break;
  466. }
  467. // put up the error message
  468. szErr.LoadString( IDS_CERTERR_SCHANNEL_ERR );
  469. sz.Format( "%s%s%x", sz, szErr, scRet );
  470. AfxMessageBox( sz );
  471. // return failure
  472. fAnswer = FALSE;
  473. goto cleanup;
  474. }
  475. // close the credentials handle
  476. FreeCredentialsHandle( &hCreds );
  477. // clean up the certificate contexts
  478. cleanup:
  479. if ( pRequestObject )
  480. GlobalFree( pRequestObject );
  481. if ( pcontextCertificate )
  482. CertFreeCertificateContext( pcontextCertificate );
  483. // return success
  484. return fAnswer;
  485. }
  486. //------------------------------------------------------------------------------
  487. void CKey::OutputHeader( CFile* pFile, PVOID privData1, PVOID privData2 )
  488. {
  489. PADMIN_INFO pInfo = (PADMIN_INFO)privData1;
  490. // we start this by getting the DN strings from either the dialog that was
  491. // passed in through privData or throught cracking the certificate.
  492. CString szCN, szOU, szO, szL, szS, szC;
  493. CKeyCrackedData cracker;
  494. // the only way to get the info is from cracking an existing cert
  495. if ( cracker.CrackKey(this) )
  496. {
  497. cracker.GetDNNetAddress( szCN );
  498. cracker.GetDNUnit( szOU );
  499. cracker.GetDNOrganization( szO );
  500. cracker.GetDNLocality( szL );
  501. cracker.GetDNState( szS );
  502. cracker.GetDNCountry( szC );
  503. }
  504. else
  505. {
  506. if (pInfo->pCommonName) szCN = *pInfo->pCommonName;
  507. if (pInfo->pOrgUnit) szOU = *pInfo->pOrgUnit;
  508. if (pInfo->pOrg) szO = *pInfo->pOrg;
  509. if (pInfo->pLocality) szL = *pInfo->pLocality;
  510. if (pInfo->pState) szS = *pInfo->pState;
  511. if (pInfo->pCountry) szC = *pInfo->pCountry;
  512. }
  513. // ok, output all the strings, starting with the administrator information
  514. CString sz = HEADER_ADMINISTRATOR;
  515. pFile->Write( sz, sz.GetLength() );
  516. if ( pInfo->pEmail )
  517. pFile->Write( *pInfo->pEmail, pInfo->pEmail->GetLength() );
  518. sz = HEADER_PHONE;
  519. pFile->Write( sz, sz.GetLength() );
  520. if ( pInfo->pPhone )
  521. pFile->Write( *pInfo->pPhone, pInfo->pPhone->GetLength() );
  522. sz = HEADER_SERVER;
  523. pFile->Write( sz, sz.GetLength() );
  524. sz.LoadString( IDS_SERVER_INFO_STRING );
  525. pFile->Write( sz, sz.GetLength() );
  526. sz = HEADER_COMMON_NAME;
  527. pFile->Write( sz, sz.GetLength() );
  528. pFile->Write( szCN, szCN.GetLength() );
  529. sz = HEADER_ORG_UNIT;
  530. pFile->Write( sz, sz.GetLength() );
  531. pFile->Write( szOU, szOU.GetLength() );
  532. sz = HEADER_ORGANIZATION;
  533. pFile->Write( sz, sz.GetLength() );
  534. pFile->Write( szO, szO.GetLength() );
  535. sz = HEADER_LOCALITY;
  536. pFile->Write( sz, sz.GetLength() );
  537. pFile->Write( szL, szL.GetLength() );
  538. sz = HEADER_STATE;
  539. pFile->Write( sz, sz.GetLength() );
  540. pFile->Write( szS, szS.GetLength() );
  541. sz = HEADER_COUNTRY;
  542. pFile->Write( sz, sz.GetLength() );
  543. pFile->Write( szC, szC.GetLength() );
  544. sz = HEADER_END_SPACING;
  545. pFile->Write( sz, sz.GetLength() );
  546. }
  547. //------------------------------------------------------------------------------
  548. // this routine is based on the routine "Requestify" from KeyGen
  549. BOOL CKey::FOutputRequestFile( CString szFile, BOOL fMime, PVOID privData )
  550. {
  551. PADMIN_INFO pAdminInfo= (PADMIN_INFO)privData;
  552. ADMIN_INFO AdminInfo;
  553. CAdminInfoDlg aiDlg;
  554. // ok, the priv data points to a structure that contains three strings
  555. // describing the admin requesting this request. If it is null, then we
  556. // must ask this information.
  557. if ( !pAdminInfo )
  558. {
  559. if ( aiDlg.DoModal() != IDOK )
  560. return FALSE;
  561. // fill the darned thing in
  562. ZeroMemory( &AdminInfo, sizeof(AdminInfo) );
  563. pAdminInfo = &AdminInfo;
  564. AdminInfo.pEmail = &aiDlg.m_sz_email;
  565. AdminInfo.pPhone = &aiDlg.m_sz_phone;
  566. }
  567. PUCHAR pEncoded;
  568. DWORD cbData = m_cbCertificateRequest;
  569. // encode the request into a new pointer
  570. pEncoded = PCreateEncodedRequest( m_pCertificateRequest, &cbData, FALSE );
  571. /*
  572. PUCHAR pb;
  573. DWORD cb;
  574. PUCHAR p;
  575. DWORD Size;
  576. PUCHAR pSource;
  577. DWORD cbSource;
  578. ASSERT( pSource );
  579. ASSERT( cbSource );
  580. // we don't actually want to change the source data, so make a copy of it first
  581. pSource = (PUCHAR)GlobalAlloc( GPTR, m_cbCertificateRequest );
  582. if ( !pSource )
  583. {
  584. AfxThrowMemoryException();
  585. return FALSE;
  586. }
  587. cbSource = m_cbCertificateRequest;
  588. // copy over the data
  589. CopyMemory( pSource, m_pCertificateRequest, cbSource );
  590. cb = (cbSource * 3 / 4) + 1024;
  591. pb = (PUCHAR)LocalAlloc( LMEM_FIXED, cb );
  592. if ( !pb )
  593. return FALSE;
  594. p = pb;
  595. if ( fMime )
  596. {
  597. Size = strlen( MIME_TYPE );
  598. CopyMemory( p, MIME_TYPE, Size );
  599. p += Size;
  600. Size = strlen( MIME_ENCODING );
  601. CopyMemory( p, MIME_ENCODING, Size );
  602. p += Size;
  603. }
  604. else
  605. {
  606. Size = strlen( MESSAGE_HEADER );
  607. CopyMemory( p, MESSAGE_HEADER, Size );
  608. p += Size;
  609. }
  610. do
  611. {
  612. Size = HTUU_encode( pSource,
  613. (cbSource > 48 ? 48 : cbSource),
  614. (PCHAR)p );
  615. p += Size;
  616. *p++ = '\r';
  617. *p++ = '\n';
  618. if ( cbSource < 48 )
  619. break;
  620. cbSource -= 48;
  621. pSource += 48;
  622. } while (cbSource);
  623. if ( !fMime )
  624. {
  625. Size = strlen( MESSAGE_TRAILER );
  626. CopyMemory( p, MESSAGE_TRAILER, Size );
  627. p += Size;
  628. }
  629. */
  630. // write the requestified data into the target file
  631. try
  632. {
  633. // try to open the file
  634. CFile cfile;
  635. if ( !cfile.Open(szFile, CFile::modeCreate | CFile::modeWrite) )
  636. {
  637. AfxMessageBox( IDS_IO_ERROR );
  638. return FALSE;
  639. }
  640. // write out the header stuff that simon at Verisign
  641. // requested at the LAST POSSIBLE MINUTE!!!
  642. OutputHeader( &cfile, pAdminInfo, NULL );
  643. // write the data to the file
  644. // cfile.Write( pb, (p - pb) );
  645. cfile.Write( pEncoded, cbData );
  646. // close the file
  647. cfile.Close();
  648. }
  649. catch( CException e )
  650. {
  651. if ( pEncoded )
  652. LocalFree( pEncoded );
  653. return FALSE;
  654. }
  655. if ( pEncoded )
  656. LocalFree( pEncoded );
  657. return TRUE;
  658. }
  659. //------------------------------------------------------------------------
  660. PUCHAR PCreateEncodedRequest( PVOID pRequest, DWORD* pcb, BOOL fMime )
  661. {
  662. PUCHAR pb;
  663. DWORD cb;
  664. PUCHAR p;
  665. DWORD Size;
  666. PUCHAR pSource;
  667. DWORD cbSource;
  668. DWORD cbRequest = *pcb;
  669. ASSERT( pcb && *pcb );
  670. ASSERT( pRequest );
  671. // get the correct pointer to and size of the request, taking into account the header
  672. LPREQUEST_HEADER pHeader = (LPREQUEST_HEADER)pRequest;
  673. if ( pHeader->Identifier == REQUEST_HEADER_IDENTIFIER )
  674. {
  675. pRequest = (PUCHAR)pRequest + pHeader->cbSizeOfHeader;
  676. cbRequest = *pcb = pHeader->cbRequestSize;
  677. }
  678. // we don't actually want to change the source data, so make a copy of it first
  679. pSource = (PUCHAR)GlobalAlloc( GPTR, cbRequest );
  680. if ( !pSource )
  681. {
  682. AfxThrowMemoryException();
  683. return FALSE;
  684. }
  685. cbSource = cbRequest;
  686. // copy over the data
  687. CopyMemory( pSource, pRequest, cbSource );
  688. cb = (cbSource * 3 / 4) + 1024;
  689. pb = (PUCHAR)LocalAlloc( LMEM_FIXED, cb );
  690. if ( !pb )
  691. return FALSE;
  692. p = pb;
  693. if ( fMime )
  694. {
  695. Size = strlen( MIME_TYPE );
  696. CopyMemory( p, MIME_TYPE, Size );
  697. p += Size;
  698. Size = strlen( MIME_ENCODING );
  699. CopyMemory( p, MIME_ENCODING, Size );
  700. p += Size;
  701. }
  702. else
  703. {
  704. Size = strlen( MESSAGE_HEADER );
  705. CopyMemory( p, MESSAGE_HEADER, Size );
  706. p += Size;
  707. }
  708. do
  709. {
  710. Size = HTUU_encode( pSource,
  711. (cbSource > 48 ? 48 : cbSource),
  712. (PCHAR)p );
  713. p += Size;
  714. *p++ = '\r';
  715. *p++ = '\n';
  716. if ( cbSource < 48 )
  717. break;
  718. cbSource -= 48;
  719. pSource += 48;
  720. } while (cbSource);
  721. if ( !fMime )
  722. {
  723. Size = strlen( MESSAGE_TRAILER );
  724. CopyMemory( p, MESSAGE_TRAILER, Size );
  725. p += Size;
  726. }
  727. // set the count of bytes into place
  728. *pcb = DIFF(p - pb);
  729. //return the pointer to the encoded information
  730. return pb;
  731. }
  732. // Taken right out of KenGen.c
  733. static char six2pr[64] =
  734. {
  735. 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
  736. 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
  737. 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
  738. 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
  739. '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
  740. };
  741. // Taken right out of KenGen.c
  742. /*--- function HTUU_encode -----------------------------------------------
  743. *
  744. * Encode a single line of binary data to a standard format that
  745. * uses only printing ASCII characters (but takes up 33% more bytes).
  746. *
  747. * Entry bufin points to a buffer of bytes. If nbytes is not
  748. * a multiple of three, then the byte just beyond
  749. * the last byte in the buffer must be 0.
  750. * nbytes is the number of bytes in that buffer.
  751. * This cannot be more than 48.
  752. * bufcoded points to an output buffer. Be sure that this
  753. * can hold at least 1 + (4*nbytes)/3 characters.
  754. *
  755. * Exit bufcoded contains the coded line. The first 4*nbytes/3 bytes
  756. * contain printing ASCII characters representing
  757. * those binary bytes. This may include one or
  758. * two '=' characters used as padding at the end.
  759. * The last byte is a zero byte.
  760. * Returns the number of ASCII characters in "bufcoded".
  761. */
  762. // Now the HTUU_encode is taken from infocomm/common/fcache and has been fixed by amallet
  763. // it has been modified slightly to take into account that the output buffer was resized above
  764. int HTUU_encode(unsigned char *bufin, unsigned int nbytes, char *bufcoded)
  765. {
  766. register char *outptr = bufcoded;
  767. unsigned int i;
  768. BOOL fOneByteDiff = FALSE;
  769. BOOL fTwoByteDiff = FALSE;
  770. unsigned int iRemainder = 0;
  771. unsigned int iClosestMultOfThree = 0;
  772. iRemainder = nbytes % 3; //also works for nbytes == 1, 2
  773. fOneByteDiff = (iRemainder == 1 ? TRUE : FALSE);
  774. fTwoByteDiff = (iRemainder == 2 ? TRUE : FALSE);
  775. iClosestMultOfThree = ((nbytes - iRemainder)/3) * 3 ;
  776. //
  777. // Encode bytes in buffer up to multiple of 3 that is closest to nbytes.
  778. //
  779. for (i=0; i< iClosestMultOfThree ; i += 3) {
  780. *(outptr++) = six2pr[*bufin >> 2]; /* c1 */
  781. *(outptr++) = six2pr[((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)]; /*c2*/
  782. *(outptr++) = six2pr[((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03)];/*c3*/
  783. *(outptr++) = six2pr[bufin[2] & 077]; /* c4 */
  784. bufin += 3;
  785. }
  786. //
  787. // We deal with trailing bytes by pretending that the input buffer has been padded with
  788. // zeros. Expressions are thus the same as above, but the second half drops off b'cos
  789. // ( a | ( b & 0) ) = ( a | 0 ) = a
  790. //
  791. if (fOneByteDiff)
  792. {
  793. *(outptr++) = six2pr[*bufin >> 2]; /* c1 */
  794. *(outptr++) = six2pr[((*bufin << 4) & 060)]; /* c2 */
  795. //pad with '='
  796. *(outptr++) = '='; /* c3 */
  797. *(outptr++) = '='; /* c4 */
  798. }
  799. else if (fTwoByteDiff)
  800. {
  801. *(outptr++) = six2pr[*bufin >> 2]; /* c1 */
  802. *(outptr++) = six2pr[((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)]; /*c2*/
  803. *(outptr++) = six2pr[((bufin[1] << 2) & 074)];/*c3*/
  804. //pad with '='
  805. *(outptr++) = '='; /* c4 */
  806. }
  807. //encoded buffer must be zero-terminated
  808. *outptr = '\0';
  809. return DIFF(outptr - bufcoded);
  810. }
  811. //============================ BASED ON SETKEY
  812. const int pr2six[256]={
  813. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  814. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63,
  815. 52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9,
  816. 10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27,
  817. 28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
  818. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  819. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  820. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  821. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  822. 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  823. 64,64,64,64,64,64,64,64,64,64,64,64,64
  824. };
  825. //
  826. // We have to squirt a record into the decoded stream
  827. //
  828. #define CERT_RECORD 13
  829. #define CERT_SIZE_HIBYTE 2 // Index into record of record size
  830. #define CERT_SIZE_LOBYTE 3
  831. unsigned char abCertHeader[] = {0x30, 0x82, // Record
  832. 0x00, 0x00, // Size of cert + buff
  833. 0x04, 0x0b, 0x63, 0x65,// Cert record data
  834. 0x72, 0x74, 0x69, 0x66,
  835. 0x69, 0x63, 0x61, 0x74,
  836. 0x65 };
  837. void uudecode_cert(char *bufcoded, DWORD *pcbDecoded )
  838. {
  839. int nbytesdecoded;
  840. char *bufin = bufcoded;
  841. unsigned char *bufout = (unsigned char *)bufcoded;
  842. unsigned char *pbuf;
  843. int nprbytes;
  844. char * beginbuf = bufcoded;
  845. ASSERT(bufcoded);
  846. ASSERT(pcbDecoded);
  847. /* Strip leading whitespace. */
  848. while(*bufcoded==' ' ||
  849. *bufcoded == '\t' ||
  850. *bufcoded == '\r' ||
  851. *bufcoded == '\n' )
  852. {
  853. bufcoded++;
  854. }
  855. //
  856. // If there is a beginning '---- ....' then skip the first line
  857. //
  858. if ( bufcoded[0] == '-' && bufcoded[1] == '-' )
  859. {
  860. bufin = strchr( bufcoded, '\n' );
  861. if ( bufin )
  862. {
  863. bufin++;
  864. bufcoded = bufin;
  865. }
  866. else
  867. {
  868. bufin = bufcoded;
  869. }
  870. }
  871. else
  872. {
  873. bufin = bufcoded;
  874. }
  875. //
  876. // Strip all cr/lf from the block
  877. //
  878. pbuf = (unsigned char *)bufin;
  879. while ( *pbuf )
  880. {
  881. if ( *pbuf == '\r' || *pbuf == '\n' )
  882. {
  883. memmove( (void*)pbuf, pbuf+1, strlen( (char*)pbuf + 1) + 1 );
  884. }
  885. else
  886. {
  887. pbuf++;
  888. }
  889. }
  890. /* Figure out how many characters are in the input buffer.
  891. * If this would decode into more bytes than would fit into
  892. * the output buffer, adjust the number of input bytes downwards.
  893. */
  894. while(pr2six[*(bufin++)] <= 63);
  895. nprbytes = DIFF(bufin - bufcoded) - 1;
  896. nbytesdecoded = ((nprbytes+3)/4) * 3;
  897. bufin = bufcoded;
  898. while (nprbytes > 0) {
  899. *(bufout++) =
  900. (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
  901. *(bufout++) =
  902. (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
  903. *(bufout++) =
  904. (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
  905. bufin += 4;
  906. nprbytes -= 4;
  907. }
  908. if(nprbytes & 03) {
  909. if(pr2six[bufin[-2]] > 63)
  910. nbytesdecoded -= 2;
  911. else
  912. nbytesdecoded -= 1;
  913. }
  914. //
  915. // Now we need to add a new wrapper sequence around the certificate
  916. // indicating this is a certificate
  917. //
  918. memmove( beginbuf + sizeof(abCertHeader),
  919. beginbuf,
  920. nbytesdecoded );
  921. memcpy( beginbuf,
  922. abCertHeader,
  923. sizeof(abCertHeader) );
  924. //
  925. // The beginning record size is the total number of bytes decoded plus
  926. // the number of bytes in the certificate header
  927. //
  928. beginbuf[CERT_SIZE_HIBYTE] = (BYTE) (((USHORT)nbytesdecoded+CERT_RECORD) >> 8);
  929. beginbuf[CERT_SIZE_LOBYTE] = (BYTE) ((USHORT)nbytesdecoded+CERT_RECORD);
  930. nbytesdecoded += sizeof(abCertHeader);
  931. if ( pcbDecoded )
  932. *pcbDecoded = nbytesdecoded;
  933. }
  934. // ============ END BASED ON SETKEY
  935. //------------------------------------------------------------------------------
  936. BOOL CKey::FImportKeySetFiles( CString szPrivate, CString szPublic, CString &szPass )
  937. {
  938. BOOL fSuccess = TRUE;
  939. // in this routine, we load the data from the file, initialize it, and ask
  940. // the user for a password, which we then confirm with AcquireCredHandle.
  941. // several things we will be doing can throw, so use a try/catch
  942. try
  943. {
  944. // start by opening the private data file
  945. CFile cfile( szPrivate, CFile::modeRead|CFile::shareDenyWrite );
  946. // get the length of the file
  947. m_cbPrivateKey = cfile.GetLength();
  948. // create a handle to hold the data
  949. m_pPrivateKey = GlobalAlloc( GPTR, m_cbPrivateKey );
  950. if ( !m_pPrivateKey )
  951. {
  952. cfile.Close();
  953. AfxThrowMemoryException();
  954. };
  955. // great, now read the data out of the file
  956. cfile.Read( m_pPrivateKey, m_cbPrivateKey );
  957. // close the file
  958. cfile.Close();
  959. // reading in the certificate is easy because that was done elsewhere
  960. if ( szPublic && !szPublic.IsEmpty() )
  961. {
  962. fSuccess = FInstallCertificate( szPublic, szPass );
  963. if ( fSuccess )
  964. // set the password
  965. m_szPassword = szPass;
  966. }
  967. }
  968. catch( CException e )
  969. {
  970. return FALSE;
  971. }
  972. return fSuccess;
  973. }
  974. //------------------------------------------------------------------------------
  975. void ReadWriteDWORD( CFile *pFile, DWORD *pDword, BOOL fRead );
  976. void ReadWriteString( CFile *pFile, CString &sz, BOOL fRead );
  977. void ReadWriteBlob( CFile *pFile, PVOID pBlob, DWORD cbBlob, BOOL fRead );
  978. //------------------------------------------------------------------------------
  979. BOOL CKey::FImportExportBackupFile( CString szFile, BOOL fImport )
  980. {
  981. DWORD dword;
  982. UINT nOpenFlags;
  983. CConfirmPassDlg dlgconfirm;
  984. // set up the right open flags
  985. if ( fImport )
  986. nOpenFlags = CFile::modeRead | CFile::shareDenyNone;
  987. else
  988. nOpenFlags = CFile::modeCreate | CFile::modeReadWrite | CFile::shareExclusive;
  989. // put it in a try/catch to get any errors
  990. try
  991. {
  992. CFile file( szFile, nOpenFlags );
  993. // do the backup id
  994. dword = BACKUP_ID;
  995. ReadWriteDWORD( &file, &dword, fImport );
  996. // check the backup id
  997. if ( dword != BACKUP_ID )
  998. {
  999. AfxMessageBox( IDS_KEY_FILE_INVALID );
  1000. return FALSE;
  1001. }
  1002. // start with the name of the key
  1003. CString szName = GetName();
  1004. ReadWriteString( &file, szName, fImport );
  1005. if ( fImport ) SetName( szName );
  1006. // now the private key data size
  1007. ReadWriteDWORD( &file, &m_cbPrivateKey, fImport );
  1008. // make a private key data pointer if necessary
  1009. if ( fImport && m_cbPrivateKey )
  1010. {
  1011. m_pPrivateKey = GlobalAlloc( GPTR, m_cbPrivateKey );
  1012. if ( !m_pPrivateKey ) AfxThrowMemoryException();
  1013. }
  1014. // use the private key pointer
  1015. if ( m_cbPrivateKey )
  1016. ReadWriteBlob( &file, m_pPrivateKey, m_cbPrivateKey, fImport );
  1017. // now the certificate
  1018. ReadWriteDWORD( &file, &m_cbCertificate, fImport );
  1019. // make a data pointer if necessary
  1020. if ( fImport && m_cbCertificate )
  1021. {
  1022. m_pCertificate = GlobalAlloc( GPTR, m_cbCertificate );
  1023. if ( !m_pCertificate ) AfxThrowMemoryException();
  1024. }
  1025. // use the private key pointer
  1026. if ( m_cbCertificate )
  1027. ReadWriteBlob( &file, m_pCertificate, m_cbCertificate, fImport );
  1028. // now the request
  1029. ReadWriteDWORD( &file, &m_cbCertificateRequest, fImport );
  1030. // make a data pointer if necessary
  1031. if ( fImport && m_cbCertificateRequest )
  1032. {
  1033. m_pCertificateRequest = GlobalAlloc( GPTR, m_cbCertificateRequest );
  1034. if ( !m_pCertificateRequest ) AfxThrowMemoryException();
  1035. }
  1036. // use the private key pointer
  1037. if ( m_cbCertificateRequest )
  1038. ReadWriteBlob( &file, m_pCertificateRequest, m_cbCertificateRequest, fImport );
  1039. // finally, if we are importing, we need to confirm the password
  1040. // Except if there is no Cert, which means Import of a Request
  1041. if ( m_cbCertificate && fImport )
  1042. {
  1043. //if we are importing, get the password first
  1044. if ( dlgconfirm.DoModal() != IDOK )
  1045. return FALSE;
  1046. if ( !FVerifyValidPassword(dlgconfirm.m_szPassword) )
  1047. {
  1048. // the Verify Valid Password routine puts up all
  1049. // the correct error dialogs now
  1050. return FALSE;
  1051. }
  1052. // set the password into place
  1053. m_szPassword = dlgconfirm.m_szPassword;
  1054. }
  1055. }
  1056. catch( CException e )
  1057. {
  1058. // return failure
  1059. return FALSE;
  1060. }
  1061. // return success
  1062. return TRUE;
  1063. }
  1064. // file utilities
  1065. //---------------------------------------------------------------------------
  1066. void ReadWriteDWORD( CFile *pFile, DWORD *pDword, BOOL fRead )
  1067. {
  1068. ASSERT(pFile);
  1069. ASSERT(pDword);
  1070. // read it or write it
  1071. if ( fRead )
  1072. pFile->Read( (void*)pDword, sizeof(DWORD) );
  1073. else
  1074. pFile->Write( (void*)pDword, sizeof(DWORD) );
  1075. }
  1076. //---------------------------------------------------------------------------
  1077. void ReadWriteString( CFile *pFile, CString &sz, BOOL fRead )
  1078. {
  1079. ASSERT(pFile);
  1080. ASSERT(sz);
  1081. // get the length of the string
  1082. DWORD cbLength = sz.GetLength();
  1083. ReadWriteDWORD(pFile,&cbLength,fRead );
  1084. // read or write the string
  1085. LPTSTR psz = sz.GetBuffer( cbLength+1 );
  1086. ReadWriteBlob(pFile, psz, cbLength+1, fRead);
  1087. // free the string buffer
  1088. sz.ReleaseBuffer();
  1089. }
  1090. //---------------------------------------------------------------------------
  1091. void ReadWriteBlob( CFile *pFile, PVOID pBlob, DWORD cbBlob, BOOL fRead )
  1092. {
  1093. ASSERT(pFile);
  1094. ASSERT(pBlob);
  1095. ASSERT(cbBlob);
  1096. // read it or write it
  1097. if ( fRead )
  1098. pFile->Read( pBlob, cbBlob );
  1099. else
  1100. pFile->Write( pBlob, cbBlob );
  1101. }