1324 lines
40 KiB
C++
1324 lines
40 KiB
C++
|
// implements much of the exported CKey
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
#include "resource.h"
|
||
|
#include "KeyObjs.h"
|
||
|
#include "passdlg.h"
|
||
|
#include "AdmnInfo.h"
|
||
|
|
||
|
#include "NKChseCA.h"
|
||
|
#include "NKDN.h"
|
||
|
#include "NKDN2.h"
|
||
|
#include "NKKyInfo.h"
|
||
|
#include "NKUsrInf.h"
|
||
|
#include "creating.h"
|
||
|
|
||
|
#include "resource.h"
|
||
|
#include "intrlkey.h"
|
||
|
|
||
|
#include <iis64.h>
|
||
|
|
||
|
#define SECURITY_WIN32
|
||
|
extern "C"
|
||
|
{
|
||
|
#include <wincrypt.h>
|
||
|
// #include <sslsp.h>
|
||
|
#include <schnlsp.h>
|
||
|
#include <sspi.h>
|
||
|
#include <ISSPERR.h>
|
||
|
}
|
||
|
|
||
|
#include "mismtchd.h"
|
||
|
|
||
|
#define CRLF "\r\n"
|
||
|
// NON_LOCALIZABLE strings for use in the request header
|
||
|
#define HEADER_ADMINISTRATOR _T(CRLF "Webmaster: ")
|
||
|
#define HEADER_PHONE _T(CRLF "Phone: ")
|
||
|
#define HEADER_SERVER _T(CRLF "Server: ")
|
||
|
#define HEADER_COMMON_NAME _T(CRLF CRLF "Common-name: ")
|
||
|
#define HEADER_ORG_UNIT _T(CRLF "Organization Unit: ")
|
||
|
#define HEADER_ORGANIZATION _T(CRLF "Organization: ")
|
||
|
#define HEADER_LOCALITY _T(CRLF "Locality: ")
|
||
|
#define HEADER_STATE _T(CRLF "State: ")
|
||
|
#define HEADER_COUNTRY _T(CRLF "Country: ")
|
||
|
#define HEADER_END_SPACING _T(CRLF CRLF )
|
||
|
|
||
|
// defines taken from the old KeyGen utility
|
||
|
#define MESSAGE_HEADER "-----BEGIN NEW CERTIFICATE REQUEST-----\r\n"
|
||
|
#define MESSAGE_TRAILER "-----END NEW CERTIFICATE REQUEST-----\r\n"
|
||
|
#define MIME_TYPE "Content-Type: application/x-pkcs10\r\n"
|
||
|
#define MIME_ENCODING "Content-Transfer-Encoding: base64\r\n\r\n"
|
||
|
|
||
|
int HTUU_encode(unsigned char *bufin, unsigned int nbytes, char *bufcoded);
|
||
|
|
||
|
|
||
|
#define BACKUP_ID 'KRBK'
|
||
|
|
||
|
|
||
|
IMPLEMENT_DYNCREATE(CKey, CTreeItem);
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
CKey::CKey():
|
||
|
m_cbPrivateKey( 0 ),
|
||
|
m_pPrivateKey( NULL ),
|
||
|
m_cbCertificate( 0 ),
|
||
|
m_pCertificate( NULL ),
|
||
|
m_cbCertificateRequest( 0 ),
|
||
|
m_pCertificateRequest( NULL )
|
||
|
{;}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
CKey::~CKey()
|
||
|
{
|
||
|
LPTSTR pBuff;
|
||
|
|
||
|
// specifically write zeros out over the password
|
||
|
try
|
||
|
{
|
||
|
pBuff = m_szPassword.GetBuffer(256);
|
||
|
}
|
||
|
catch( CException e )
|
||
|
{
|
||
|
pBuff = NULL;
|
||
|
}
|
||
|
|
||
|
if ( pBuff )
|
||
|
{
|
||
|
// zero out the buffer
|
||
|
ZeroMemory( pBuff, 256 );
|
||
|
// release the buffer
|
||
|
m_szPassword.ReleaseBuffer(0);
|
||
|
}
|
||
|
|
||
|
// zero out the private key and the certificate
|
||
|
if ( m_pPrivateKey )
|
||
|
{
|
||
|
// zero out the buffer
|
||
|
ZeroMemory( m_pPrivateKey, m_cbPrivateKey );
|
||
|
// free the pointer
|
||
|
GlobalFree( (HANDLE)m_pPrivateKey );
|
||
|
m_pPrivateKey = NULL;
|
||
|
}
|
||
|
if ( m_pCertificate )
|
||
|
{
|
||
|
// zero out the buffer
|
||
|
ZeroMemory( m_pCertificate, m_cbCertificate );
|
||
|
// free the pointer
|
||
|
GlobalFree( (HANDLE)m_pCertificate );
|
||
|
m_pCertificate = NULL;
|
||
|
}
|
||
|
if ( m_pCertificateRequest )
|
||
|
{
|
||
|
// zero out the buffer
|
||
|
ZeroMemory( m_pCertificateRequest, m_cbCertificateRequest );
|
||
|
// free the pointer
|
||
|
GlobalFree( (HANDLE)m_pCertificateRequest );
|
||
|
m_pCertificate = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
CKey* CKey::PClone( void )
|
||
|
{
|
||
|
CKey* pClone = NULL;
|
||
|
|
||
|
// TRY to make a new key object
|
||
|
try
|
||
|
{
|
||
|
pClone = new CKey();
|
||
|
// copy over all the data
|
||
|
pClone->CopyDataFrom( this );
|
||
|
}
|
||
|
catch( CException e )
|
||
|
{
|
||
|
// if the object had been made, delete it
|
||
|
if ( pClone )
|
||
|
delete pClone;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
return pClone;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
void CKey::CopyDataFrom( CKey* pKey )
|
||
|
{
|
||
|
// make sure this is ok
|
||
|
ASSERT( pKey );
|
||
|
ASSERT( pKey->IsKindOf(RUNTIME_CLASS(CKey)) );
|
||
|
if ( !pKey ) return;
|
||
|
|
||
|
// delete any data currently in this key
|
||
|
// zero out the private key and the certificate
|
||
|
if ( m_pPrivateKey )
|
||
|
{
|
||
|
ZeroMemory( m_pPrivateKey, m_cbPrivateKey );
|
||
|
GlobalFree( (HANDLE)m_pPrivateKey );
|
||
|
m_pPrivateKey = NULL;
|
||
|
}
|
||
|
if ( m_pCertificate )
|
||
|
{
|
||
|
ZeroMemory( m_pCertificate, m_cbCertificate );
|
||
|
GlobalFree( (HANDLE)m_pCertificate );
|
||
|
m_pCertificate = NULL;
|
||
|
}
|
||
|
if ( m_pCertificateRequest )
|
||
|
{
|
||
|
ZeroMemory( m_pCertificateRequest, m_cbCertificateRequest );
|
||
|
GlobalFree( (HANDLE)m_pCertificateRequest );
|
||
|
m_pCertificate = NULL;
|
||
|
}
|
||
|
|
||
|
// copy over the basic stuff
|
||
|
m_szItemName = pKey->m_szItemName;
|
||
|
m_iImage = pKey->m_iImage;
|
||
|
m_szPassword = pKey->m_szPassword;
|
||
|
m_cbPrivateKey = pKey->m_cbPrivateKey;
|
||
|
m_cbCertificate = pKey->m_cbCertificate;
|
||
|
m_cbCertificateRequest = pKey->m_cbCertificateRequest;
|
||
|
|
||
|
// now the pointer based data
|
||
|
if ( pKey->m_pPrivateKey )
|
||
|
{
|
||
|
m_pPrivateKey = GlobalAlloc( GPTR, m_cbPrivateKey );
|
||
|
if ( !m_pPrivateKey ) AfxThrowMemoryException();
|
||
|
memcpy( m_pPrivateKey, pKey->m_pPrivateKey, m_cbPrivateKey );
|
||
|
}
|
||
|
|
||
|
if ( pKey->m_pCertificate )
|
||
|
{
|
||
|
m_pCertificate = GlobalAlloc( GPTR, m_cbCertificate );
|
||
|
if ( !m_pCertificate ) AfxThrowMemoryException();
|
||
|
memcpy( m_pCertificate, pKey->m_pCertificate, m_cbCertificate );
|
||
|
}
|
||
|
|
||
|
if ( pKey->m_pCertificateRequest )
|
||
|
{
|
||
|
m_pCertificateRequest = GlobalAlloc( GPTR, m_cbCertificateRequest );
|
||
|
if ( !m_pCertificateRequest ) AfxThrowMemoryException();
|
||
|
memcpy( m_pCertificateRequest, pKey->m_pCertificateRequest,
|
||
|
m_cbCertificateRequest );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
void CKey::SetName( CString &szNewName )
|
||
|
{
|
||
|
m_szItemName = szNewName;
|
||
|
UpdateCaption();
|
||
|
SetDirty( TRUE );
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
void CKey::UpdateIcon( void )
|
||
|
{
|
||
|
// if there is no certificate, then the immature key
|
||
|
if ( !m_pCertificate )
|
||
|
{
|
||
|
m_iImage = TREE_ICON_KEY_IMMATURE;
|
||
|
FSetImage( m_iImage );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// there is a certificate, but we need to see if it has
|
||
|
// expired or not. We do that by cracking the certificate
|
||
|
// default the key to being ok
|
||
|
m_iImage = TREE_ICON_KEY_OK;
|
||
|
CKeyCrackedData cracker;
|
||
|
|
||
|
// crack the key
|
||
|
if ( cracker.CrackKey(this) )
|
||
|
{
|
||
|
// get the expiration time
|
||
|
CTime ctimeExpires( cracker.GetValidUntil() );
|
||
|
|
||
|
// get the current time
|
||
|
CTime ctimeCurrent = CTime::GetCurrentTime();
|
||
|
|
||
|
// test if it has expired first
|
||
|
if ( ctimeCurrent > ctimeExpires )
|
||
|
m_iImage = TREE_ICON_KEY_EXPIRED;
|
||
|
}
|
||
|
|
||
|
// set the image
|
||
|
FSetImage( m_iImage );
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
BOOL CKey::FInstallCertificate( CString szPath, CString szPass )
|
||
|
{
|
||
|
CFile cfile;
|
||
|
PVOID pData = NULL;
|
||
|
BOOL fSuccess =FALSE;;
|
||
|
|
||
|
// open the file
|
||
|
if ( !cfile.Open( szPath, CFile::modeRead | CFile::shareDenyNone ) )
|
||
|
return FALSE;
|
||
|
|
||
|
// how big is the file - add one so we can zero terminate the buffer
|
||
|
DWORD cbCertificate = cfile.GetLength() + 1;
|
||
|
|
||
|
// make sure the file has some size
|
||
|
if ( !cbCertificate )
|
||
|
{
|
||
|
AfxMessageBox( IDS_ERR_INVALID_CERTIFICATE, MB_OK | MB_ICONINFORMATION );
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// put the rest of the operation in a try/catch
|
||
|
// specifically write zeros out over the password
|
||
|
try
|
||
|
{
|
||
|
// allocate space for the data
|
||
|
pData = GlobalAlloc( GPTR, cbCertificate );
|
||
|
if ( !pData ) AfxThrowMemoryException();
|
||
|
|
||
|
// copy in the data from the file to the pointer - will throw and exception
|
||
|
DWORD cbRead = cfile.Read( pData, cbCertificate );
|
||
|
|
||
|
// zero terminate for decoding
|
||
|
((BYTE*)pData)[cbRead] = 0;
|
||
|
|
||
|
// great. The last thing left is to uudecode the data we got
|
||
|
uudecode_cert( (char*)pData, &cbCertificate );
|
||
|
|
||
|
// close the file
|
||
|
cfile.Close();
|
||
|
|
||
|
// install the certificate
|
||
|
fSuccess = FInstallCertificate( pData, cbCertificate, szPass );
|
||
|
}
|
||
|
catch( CException e )
|
||
|
{
|
||
|
// if the pointer was allocated, deallocate it
|
||
|
if ( pData )
|
||
|
{
|
||
|
GlobalFree( pData );
|
||
|
pData = NULL;
|
||
|
}
|
||
|
// return failure
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// return success
|
||
|
return fSuccess;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// it is up to the module to verify the certificate
|
||
|
BOOL CKey::FInstallCertificate( PVOID pCert, DWORD cbCert, CString &szPass )
|
||
|
{
|
||
|
// cache the old certificate in case the new one fails
|
||
|
DWORD old_cbCertificate = m_cbCertificate;
|
||
|
PVOID old_pCertificate = m_pCertificate;
|
||
|
|
||
|
// set the new one into place
|
||
|
m_cbCertificate = cbCert;
|
||
|
m_pCertificate = pCert;
|
||
|
|
||
|
/* // MOVED TO THE MODULE
|
||
|
// verify the password
|
||
|
if ( !FVerifyValidPassword(szPass) )
|
||
|
{
|
||
|
// resore the old values
|
||
|
m_cbCertificate = old_cbCertificate;
|
||
|
m_pCertificate = old_pCertificate;
|
||
|
|
||
|
// dispose of the new stuff
|
||
|
GlobalFree( pCert );
|
||
|
|
||
|
// return false
|
||
|
return FALSE;
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
// Re-Set the password, incase we stored a request from Backup file.
|
||
|
m_szPassword = szPass;
|
||
|
|
||
|
// it checks out ok, so we can get rid of the old stuff
|
||
|
// be careful not to get rid of the current test cert if that is whats there
|
||
|
if ( old_pCertificate && (old_pCertificate != pCert) )
|
||
|
{
|
||
|
GlobalFree( old_pCertificate );
|
||
|
old_pCertificate = NULL;
|
||
|
}
|
||
|
|
||
|
// mark the key as dirty
|
||
|
SetDirty( TRUE );
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// verfying a valid password is now a several-stop process. First we have to verify
|
||
|
// that the certificate is the correct one that was requested. Apparenly lots of
|
||
|
// users out there are attempting to install either invalid certificates, or valid
|
||
|
// certificates on the wrong key. Then, when they can't figure out that they messed
|
||
|
// it up, they call us. Or Verisign. To do this we use CAPI2 to get a certificate context
|
||
|
// from the certificate. If that fails is in an invalid cert (say... an EXE file).
|
||
|
// Then we test that certificat's public key to see if it matches the public key
|
||
|
// stored in the request (which we also have to use CAPI2 to crack) If there is no
|
||
|
// request (keyset files) then tough bannanas. They will have to rely on the errors
|
||
|
// returned by the AcquireCredentialsHandle routine.
|
||
|
|
||
|
BOOL CKey::FVerifyValidPassword( CString szPassword )
|
||
|
{
|
||
|
PVOID pRequestObject = NULL;
|
||
|
PCCERT_CONTEXT pcontextCertificate = NULL;
|
||
|
BOOL fAnswer = TRUE;
|
||
|
|
||
|
SSL_CREDENTIAL_CERTIFICATE creds;
|
||
|
CredHandle hCreds;
|
||
|
SECURITY_STATUS scRet;
|
||
|
TimeStamp ts;
|
||
|
DWORD err;
|
||
|
|
||
|
CString sz;
|
||
|
CString szErr;
|
||
|
|
||
|
// skip the private, internal request header
|
||
|
PUCHAR pRequest = NULL;
|
||
|
DWORD cbRequest = 0;
|
||
|
|
||
|
PUCHAR pcert = (PUCHAR)m_pCertificate;
|
||
|
DWORD cbcert = m_cbCertificate;
|
||
|
|
||
|
// if the request is there, get its context
|
||
|
if ( m_pCertificateRequest )
|
||
|
{
|
||
|
// see if this request has a header block in front of it. If it does, then use
|
||
|
// it to get the real request. If it doesn't then just use the request.
|
||
|
// if it does have a header the first DWORD will be REQUEST_HEADER_IDENTIFIER
|
||
|
if ( *(DWORD*)m_pCertificateRequest == REQUEST_HEADER_IDENTIFIER )
|
||
|
{
|
||
|
// get the real request that comes after the request header
|
||
|
pRequest = (PUCHAR)m_pCertificateRequest +
|
||
|
((LPREQUEST_HEADER)m_pCertificateRequest)->cbSizeOfHeader;
|
||
|
cbRequest = ((LPREQUEST_HEADER)m_pCertificateRequest)->cbRequestSize;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// there is no header
|
||
|
pRequest = (PUCHAR)m_pCertificateRequest;
|
||
|
cbRequest = m_cbCertificateRequest;
|
||
|
}
|
||
|
|
||
|
// note that if the request isn't there or if it is invalid it is still
|
||
|
// ok to try and verify the certificate
|
||
|
DWORD cbBuffSize = 0;
|
||
|
// start by decoding the request object - get the size of the required buffer
|
||
|
CryptDecodeObject( X509_ASN_ENCODING,
|
||
|
X509_CERT_REQUEST_TO_BE_SIGNED,
|
||
|
pRequest,
|
||
|
cbRequest,
|
||
|
0,
|
||
|
NULL,
|
||
|
&cbBuffSize );
|
||
|
|
||
|
// now make an attempt to decode it
|
||
|
pRequestObject = GlobalAlloc( GPTR, cbBuffSize );
|
||
|
if ( !pRequestObject )
|
||
|
goto GetCredentials;
|
||
|
if ( !CryptDecodeObject( X509_ASN_ENCODING,
|
||
|
X509_CERT_REQUEST_TO_BE_SIGNED,
|
||
|
pRequest,
|
||
|
cbRequest,
|
||
|
0,
|
||
|
pRequestObject,
|
||
|
&cbBuffSize ) )
|
||
|
{
|
||
|
GlobalFree( pRequestObject );
|
||
|
pRequestObject = NULL;
|
||
|
goto GetCredentials;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
GetCredentials:
|
||
|
|
||
|
// OK. Verisign and Certsrv and probably others too wrap the certificate in a wrapper
|
||
|
// that, while following the normal formatting convensions, causes the context routine
|
||
|
// below to fail. This means that we have to detect if the wrapper is there and, if it
|
||
|
// is, we need to skip it. Fortunately, the wrapper contains the word "certificate"
|
||
|
// yes, this is sorta grungy, but its what petesk said to do.
|
||
|
sz = pcert;
|
||
|
sz = sz.Left(20);
|
||
|
if ( sz.Find("certificate") == 6 )
|
||
|
{
|
||
|
pcert += 17;
|
||
|
}
|
||
|
|
||
|
// get the context on the certificate
|
||
|
pcontextCertificate = CertCreateCertificateContext( X509_ASN_ENCODING, pcert, cbcert );
|
||
|
// if we were unable to create the context, then fail with an appropriate error message
|
||
|
if ( !pcontextCertificate )
|
||
|
{
|
||
|
// get the error for the dialog
|
||
|
err = GetLastError();
|
||
|
|
||
|
// tell the user that they chose an invalid certificate
|
||
|
sz.LoadString( IDS_CERTERR_INVALID_CERTIFICATE );
|
||
|
sz.Format( "%s%x", sz, err );
|
||
|
AfxMessageBox( sz );
|
||
|
|
||
|
// time to leave with a failure
|
||
|
fAnswer = FALSE;
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
|
||
|
// if we have both a cert context AND a decoded request object, then we can confirm that
|
||
|
// they are in fact matched to each other.
|
||
|
if ( pcontextCertificate && pRequestObject )
|
||
|
{
|
||
|
// use CAPI2 to do the comparison between the two public key info structures
|
||
|
if ( !CertComparePublicKeyInfo( X509_ASN_ENCODING,
|
||
|
&((PCERT_REQUEST_INFO)pRequestObject)->SubjectPublicKeyInfo,
|
||
|
&pcontextCertificate->pCertInfo->SubjectPublicKeyInfo ) )
|
||
|
{
|
||
|
// The certificate is mis-matched to the request. Fail with the right message
|
||
|
CMismatchedCertDlg mismatchdlg(
|
||
|
&((PCERT_REQUEST_INFO)pRequestObject)->Subject,
|
||
|
&pcontextCertificate->pCertInfo->Subject);
|
||
|
mismatchdlg.DoModal();
|
||
|
|
||
|
fAnswer = FALSE;
|
||
|
goto cleanup;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// use SSL to finish verifying the password
|
||
|
// fill in the credentials record
|
||
|
creds.cbPrivateKey = m_cbPrivateKey;
|
||
|
creds.pPrivateKey = (PUCHAR)m_pPrivateKey;
|
||
|
creds.cbCertificate = m_cbCertificate;
|
||
|
creds.pCertificate = (PUCHAR)m_pCertificate;
|
||
|
|
||
|
// prepare the password
|
||
|
creds.pszPassword = (PSTR)LPCTSTR(szPassword);
|
||
|
|
||
|
// attempt to get the credentials
|
||
|
scRet = AcquireCredentialsHandleW( NULL, // My name (ignored)
|
||
|
UNISP_NAME_W, // Package
|
||
|
SECPKG_CRED_INBOUND, // Use
|
||
|
NULL, // Logon ID (ignored)
|
||
|
&creds, // auth data
|
||
|
NULL, // dce-stuff
|
||
|
NULL, // dce-stuff
|
||
|
&hCreds, // handle
|
||
|
&ts ); // we really get it below
|
||
|
|
||
|
// check the results
|
||
|
if ( FAILED(scRet) )
|
||
|
{
|
||
|
sz.Empty();
|
||
|
|
||
|
// add on the appropriate sub-error message
|
||
|
switch( scRet )
|
||
|
{
|
||
|
case SEC_E_UNKNOWN_CREDENTIALS:
|
||
|
case SEC_E_NO_CREDENTIALS:
|
||
|
case SEC_E_INTERNAL_ERROR:
|
||
|
// Unfortunately, SChannel returns the "internal error" when a bad password
|
||
|
// is returned. There may or may not be other circumstances under which this
|
||
|
// error is returned, but this is by far the most common. Also I taked to
|
||
|
// PeteSk about it and he agreed that this is how it should be used.
|
||
|
// bad password
|
||
|
sz.LoadString( IDS_CERTERROR_BADPASSWORD );
|
||
|
break;
|
||
|
case SEC_E_SECPKG_NOT_FOUND:
|
||
|
case SEC_E_BAD_PKGID:
|
||
|
// the system does not have the package installed
|
||
|
sz.LoadString( IDS_CERTERROR_PACKAGELOAD_ERROR );
|
||
|
break;
|
||
|
case SEC_E_INSUFFICIENT_MEMORY:
|
||
|
sz.LoadString( IDS_CERTERR_LOMEM );
|
||
|
break;
|
||
|
case SEC_E_CANNOT_INSTALL:
|
||
|
sz.LoadString( EDS_CERTERR_SCHNL_BAD_INIT );
|
||
|
break;
|
||
|
default:
|
||
|
sz.LoadString( IDS_CERTERR_SCHNL_GENERIC );
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// put up the error message
|
||
|
szErr.LoadString( IDS_CERTERR_SCHANNEL_ERR );
|
||
|
sz.Format( "%s%s%x", sz, szErr, scRet );
|
||
|
AfxMessageBox( sz );
|
||
|
|
||
|
// return failure
|
||
|
fAnswer = FALSE;
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
// close the credentials handle
|
||
|
FreeCredentialsHandle( &hCreds );
|
||
|
|
||
|
// clean up the certificate contexts
|
||
|
cleanup:
|
||
|
if ( pRequestObject )
|
||
|
GlobalFree( pRequestObject );
|
||
|
if ( pcontextCertificate )
|
||
|
CertFreeCertificateContext( pcontextCertificate );
|
||
|
|
||
|
// return success
|
||
|
return fAnswer;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
void CKey::OutputHeader( CFile* pFile, PVOID privData1, PVOID privData2 )
|
||
|
{
|
||
|
PADMIN_INFO pInfo = (PADMIN_INFO)privData1;
|
||
|
|
||
|
// we start this by getting the DN strings from either the dialog that was
|
||
|
// passed in through privData or throught cracking the certificate.
|
||
|
CString szCN, szOU, szO, szL, szS, szC;
|
||
|
CKeyCrackedData cracker;
|
||
|
// the only way to get the info is from cracking an existing cert
|
||
|
if ( cracker.CrackKey(this) )
|
||
|
{
|
||
|
cracker.GetDNNetAddress( szCN );
|
||
|
cracker.GetDNUnit( szOU );
|
||
|
cracker.GetDNOrganization( szO );
|
||
|
cracker.GetDNLocality( szL );
|
||
|
cracker.GetDNState( szS );
|
||
|
cracker.GetDNCountry( szC );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (pInfo->pCommonName) szCN = *pInfo->pCommonName;
|
||
|
if (pInfo->pOrgUnit) szOU = *pInfo->pOrgUnit;
|
||
|
if (pInfo->pOrg) szO = *pInfo->pOrg;
|
||
|
if (pInfo->pLocality) szL = *pInfo->pLocality;
|
||
|
if (pInfo->pState) szS = *pInfo->pState;
|
||
|
if (pInfo->pCountry) szC = *pInfo->pCountry;
|
||
|
}
|
||
|
|
||
|
// ok, output all the strings, starting with the administrator information
|
||
|
CString sz = HEADER_ADMINISTRATOR;
|
||
|
pFile->Write( sz, sz.GetLength() );
|
||
|
if ( pInfo->pEmail )
|
||
|
pFile->Write( *pInfo->pEmail, pInfo->pEmail->GetLength() );
|
||
|
|
||
|
sz = HEADER_PHONE;
|
||
|
pFile->Write( sz, sz.GetLength() );
|
||
|
if ( pInfo->pPhone )
|
||
|
pFile->Write( *pInfo->pPhone, pInfo->pPhone->GetLength() );
|
||
|
|
||
|
sz = HEADER_SERVER;
|
||
|
pFile->Write( sz, sz.GetLength() );
|
||
|
sz.LoadString( IDS_SERVER_INFO_STRING );
|
||
|
pFile->Write( sz, sz.GetLength() );
|
||
|
|
||
|
sz = HEADER_COMMON_NAME;
|
||
|
pFile->Write( sz, sz.GetLength() );
|
||
|
pFile->Write( szCN, szCN.GetLength() );
|
||
|
|
||
|
sz = HEADER_ORG_UNIT;
|
||
|
pFile->Write( sz, sz.GetLength() );
|
||
|
pFile->Write( szOU, szOU.GetLength() );
|
||
|
|
||
|
sz = HEADER_ORGANIZATION;
|
||
|
pFile->Write( sz, sz.GetLength() );
|
||
|
pFile->Write( szO, szO.GetLength() );
|
||
|
|
||
|
sz = HEADER_LOCALITY;
|
||
|
pFile->Write( sz, sz.GetLength() );
|
||
|
pFile->Write( szL, szL.GetLength() );
|
||
|
|
||
|
sz = HEADER_STATE;
|
||
|
pFile->Write( sz, sz.GetLength() );
|
||
|
pFile->Write( szS, szS.GetLength() );
|
||
|
|
||
|
sz = HEADER_COUNTRY;
|
||
|
pFile->Write( sz, sz.GetLength() );
|
||
|
pFile->Write( szC, szC.GetLength() );
|
||
|
|
||
|
sz = HEADER_END_SPACING;
|
||
|
pFile->Write( sz, sz.GetLength() );
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
// this routine is based on the routine "Requestify" from KeyGen
|
||
|
BOOL CKey::FOutputRequestFile( CString szFile, BOOL fMime, PVOID privData )
|
||
|
{
|
||
|
PADMIN_INFO pAdminInfo= (PADMIN_INFO)privData;
|
||
|
ADMIN_INFO AdminInfo;
|
||
|
CAdminInfoDlg aiDlg;
|
||
|
|
||
|
// ok, the priv data points to a structure that contains three strings
|
||
|
// describing the admin requesting this request. If it is null, then we
|
||
|
// must ask this information.
|
||
|
if ( !pAdminInfo )
|
||
|
{
|
||
|
if ( aiDlg.DoModal() != IDOK )
|
||
|
return FALSE;
|
||
|
|
||
|
// fill the darned thing in
|
||
|
ZeroMemory( &AdminInfo, sizeof(AdminInfo) );
|
||
|
pAdminInfo = &AdminInfo;
|
||
|
AdminInfo.pEmail = &aiDlg.m_sz_email;
|
||
|
AdminInfo.pPhone = &aiDlg.m_sz_phone;
|
||
|
}
|
||
|
|
||
|
|
||
|
PUCHAR pEncoded;
|
||
|
DWORD cbData = m_cbCertificateRequest;
|
||
|
|
||
|
// encode the request into a new pointer
|
||
|
pEncoded = PCreateEncodedRequest( m_pCertificateRequest, &cbData, FALSE );
|
||
|
|
||
|
/*
|
||
|
PUCHAR pb;
|
||
|
DWORD cb;
|
||
|
PUCHAR p;
|
||
|
DWORD Size;
|
||
|
|
||
|
PUCHAR pSource;
|
||
|
DWORD cbSource;
|
||
|
|
||
|
ASSERT( pSource );
|
||
|
ASSERT( cbSource );
|
||
|
|
||
|
// we don't actually want to change the source data, so make a copy of it first
|
||
|
pSource = (PUCHAR)GlobalAlloc( GPTR, m_cbCertificateRequest );
|
||
|
if ( !pSource )
|
||
|
{
|
||
|
AfxThrowMemoryException();
|
||
|
return FALSE;
|
||
|
}
|
||
|
cbSource = m_cbCertificateRequest;
|
||
|
// copy over the data
|
||
|
CopyMemory( pSource, m_pCertificateRequest, cbSource );
|
||
|
|
||
|
cb = (cbSource * 3 / 4) + 1024;
|
||
|
|
||
|
pb = (PUCHAR)LocalAlloc( LMEM_FIXED, cb );
|
||
|
|
||
|
if ( !pb )
|
||
|
return FALSE;
|
||
|
|
||
|
p = pb;
|
||
|
|
||
|
if ( fMime )
|
||
|
{
|
||
|
Size = strlen( MIME_TYPE );
|
||
|
CopyMemory( p, MIME_TYPE, Size );
|
||
|
p += Size;
|
||
|
|
||
|
Size = strlen( MIME_ENCODING );
|
||
|
CopyMemory( p, MIME_ENCODING, Size );
|
||
|
p += Size;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Size = strlen( MESSAGE_HEADER );
|
||
|
CopyMemory( p, MESSAGE_HEADER, Size );
|
||
|
p += Size;
|
||
|
}
|
||
|
|
||
|
do
|
||
|
{
|
||
|
Size = HTUU_encode( pSource,
|
||
|
(cbSource > 48 ? 48 : cbSource),
|
||
|
(PCHAR)p );
|
||
|
p += Size;
|
||
|
|
||
|
*p++ = '\r';
|
||
|
*p++ = '\n';
|
||
|
|
||
|
if ( cbSource < 48 )
|
||
|
break;
|
||
|
|
||
|
cbSource -= 48;
|
||
|
pSource += 48;
|
||
|
} while (cbSource);
|
||
|
|
||
|
if ( !fMime )
|
||
|
{
|
||
|
Size = strlen( MESSAGE_TRAILER );
|
||
|
CopyMemory( p, MESSAGE_TRAILER, Size );
|
||
|
p += Size;
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
// write the requestified data into the target file
|
||
|
try
|
||
|
{
|
||
|
// try to open the file
|
||
|
CFile cfile;
|
||
|
if ( !cfile.Open(szFile, CFile::modeCreate | CFile::modeWrite) )
|
||
|
{
|
||
|
AfxMessageBox( IDS_IO_ERROR );
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// write out the header stuff that simon at Verisign
|
||
|
// requested at the LAST POSSIBLE MINUTE!!!
|
||
|
OutputHeader( &cfile, pAdminInfo, NULL );
|
||
|
|
||
|
// write the data to the file
|
||
|
// cfile.Write( pb, (p - pb) );
|
||
|
cfile.Write( pEncoded, cbData );
|
||
|
|
||
|
// close the file
|
||
|
cfile.Close();
|
||
|
}
|
||
|
catch( CException e )
|
||
|
{
|
||
|
if ( pEncoded )
|
||
|
LocalFree( pEncoded );
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if ( pEncoded )
|
||
|
LocalFree( pEncoded );
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------
|
||
|
PUCHAR PCreateEncodedRequest( PVOID pRequest, DWORD* pcb, BOOL fMime )
|
||
|
{
|
||
|
PUCHAR pb;
|
||
|
DWORD cb;
|
||
|
PUCHAR p;
|
||
|
DWORD Size;
|
||
|
|
||
|
PUCHAR pSource;
|
||
|
DWORD cbSource;
|
||
|
|
||
|
DWORD cbRequest = *pcb;
|
||
|
|
||
|
ASSERT( pcb && *pcb );
|
||
|
ASSERT( pRequest );
|
||
|
|
||
|
// get the correct pointer to and size of the request, taking into account the header
|
||
|
LPREQUEST_HEADER pHeader = (LPREQUEST_HEADER)pRequest;
|
||
|
if ( pHeader->Identifier == REQUEST_HEADER_IDENTIFIER )
|
||
|
{
|
||
|
pRequest = (PUCHAR)pRequest + pHeader->cbSizeOfHeader;
|
||
|
cbRequest = *pcb = pHeader->cbRequestSize;
|
||
|
}
|
||
|
|
||
|
// we don't actually want to change the source data, so make a copy of it first
|
||
|
pSource = (PUCHAR)GlobalAlloc( GPTR, cbRequest );
|
||
|
if ( !pSource )
|
||
|
{
|
||
|
AfxThrowMemoryException();
|
||
|
return FALSE;
|
||
|
}
|
||
|
cbSource = cbRequest;
|
||
|
// copy over the data
|
||
|
CopyMemory( pSource, pRequest, cbSource );
|
||
|
|
||
|
cb = (cbSource * 3 / 4) + 1024;
|
||
|
|
||
|
pb = (PUCHAR)LocalAlloc( LMEM_FIXED, cb );
|
||
|
|
||
|
if ( !pb )
|
||
|
return FALSE;
|
||
|
|
||
|
p = pb;
|
||
|
|
||
|
if ( fMime )
|
||
|
{
|
||
|
Size = strlen( MIME_TYPE );
|
||
|
CopyMemory( p, MIME_TYPE, Size );
|
||
|
p += Size;
|
||
|
|
||
|
Size = strlen( MIME_ENCODING );
|
||
|
CopyMemory( p, MIME_ENCODING, Size );
|
||
|
p += Size;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Size = strlen( MESSAGE_HEADER );
|
||
|
CopyMemory( p, MESSAGE_HEADER, Size );
|
||
|
p += Size;
|
||
|
}
|
||
|
|
||
|
do
|
||
|
{
|
||
|
Size = HTUU_encode( pSource,
|
||
|
(cbSource > 48 ? 48 : cbSource),
|
||
|
(PCHAR)p );
|
||
|
p += Size;
|
||
|
|
||
|
*p++ = '\r';
|
||
|
*p++ = '\n';
|
||
|
|
||
|
if ( cbSource < 48 )
|
||
|
break;
|
||
|
|
||
|
cbSource -= 48;
|
||
|
pSource += 48;
|
||
|
} while (cbSource);
|
||
|
|
||
|
if ( !fMime )
|
||
|
{
|
||
|
Size = strlen( MESSAGE_TRAILER );
|
||
|
CopyMemory( p, MESSAGE_TRAILER, Size );
|
||
|
p += Size;
|
||
|
}
|
||
|
|
||
|
// set the count of bytes into place
|
||
|
*pcb = DIFF(p - pb);
|
||
|
|
||
|
//return the pointer to the encoded information
|
||
|
return pb;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Taken right out of KenGen.c
|
||
|
static char six2pr[64] =
|
||
|
{
|
||
|
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||
|
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||
|
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
||
|
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
|
||
|
};
|
||
|
|
||
|
// Taken right out of KenGen.c
|
||
|
/*--- function HTUU_encode -----------------------------------------------
|
||
|
*
|
||
|
* Encode a single line of binary data to a standard format that
|
||
|
* uses only printing ASCII characters (but takes up 33% more bytes).
|
||
|
*
|
||
|
* Entry bufin points to a buffer of bytes. If nbytes is not
|
||
|
* a multiple of three, then the byte just beyond
|
||
|
* the last byte in the buffer must be 0.
|
||
|
* nbytes is the number of bytes in that buffer.
|
||
|
* This cannot be more than 48.
|
||
|
* bufcoded points to an output buffer. Be sure that this
|
||
|
* can hold at least 1 + (4*nbytes)/3 characters.
|
||
|
*
|
||
|
* Exit bufcoded contains the coded line. The first 4*nbytes/3 bytes
|
||
|
* contain printing ASCII characters representing
|
||
|
* those binary bytes. This may include one or
|
||
|
* two '=' characters used as padding at the end.
|
||
|
* The last byte is a zero byte.
|
||
|
* Returns the number of ASCII characters in "bufcoded".
|
||
|
*/
|
||
|
|
||
|
// Now the HTUU_encode is taken from infocomm/common/fcache and has been fixed by amallet
|
||
|
// it has been modified slightly to take into account that the output buffer was resized above
|
||
|
int HTUU_encode(unsigned char *bufin, unsigned int nbytes, char *bufcoded)
|
||
|
{
|
||
|
register char *outptr = bufcoded;
|
||
|
unsigned int i;
|
||
|
BOOL fOneByteDiff = FALSE;
|
||
|
BOOL fTwoByteDiff = FALSE;
|
||
|
unsigned int iRemainder = 0;
|
||
|
unsigned int iClosestMultOfThree = 0;
|
||
|
|
||
|
iRemainder = nbytes % 3; //also works for nbytes == 1, 2
|
||
|
fOneByteDiff = (iRemainder == 1 ? TRUE : FALSE);
|
||
|
fTwoByteDiff = (iRemainder == 2 ? TRUE : FALSE);
|
||
|
iClosestMultOfThree = ((nbytes - iRemainder)/3) * 3 ;
|
||
|
|
||
|
//
|
||
|
// Encode bytes in buffer up to multiple of 3 that is closest to nbytes.
|
||
|
//
|
||
|
for (i=0; i< iClosestMultOfThree ; i += 3) {
|
||
|
*(outptr++) = six2pr[*bufin >> 2]; /* c1 */
|
||
|
*(outptr++) = six2pr[((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)]; /*c2*/
|
||
|
*(outptr++) = six2pr[((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03)];/*c3*/
|
||
|
*(outptr++) = six2pr[bufin[2] & 077]; /* c4 */
|
||
|
|
||
|
bufin += 3;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// We deal with trailing bytes by pretending that the input buffer has been padded with
|
||
|
// zeros. Expressions are thus the same as above, but the second half drops off b'cos
|
||
|
// ( a | ( b & 0) ) = ( a | 0 ) = a
|
||
|
//
|
||
|
if (fOneByteDiff)
|
||
|
{
|
||
|
*(outptr++) = six2pr[*bufin >> 2]; /* c1 */
|
||
|
*(outptr++) = six2pr[((*bufin << 4) & 060)]; /* c2 */
|
||
|
|
||
|
//pad with '='
|
||
|
*(outptr++) = '='; /* c3 */
|
||
|
*(outptr++) = '='; /* c4 */
|
||
|
}
|
||
|
else if (fTwoByteDiff)
|
||
|
{
|
||
|
*(outptr++) = six2pr[*bufin >> 2]; /* c1 */
|
||
|
*(outptr++) = six2pr[((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)]; /*c2*/
|
||
|
*(outptr++) = six2pr[((bufin[1] << 2) & 074)];/*c3*/
|
||
|
|
||
|
//pad with '='
|
||
|
*(outptr++) = '='; /* c4 */
|
||
|
}
|
||
|
|
||
|
//encoded buffer must be zero-terminated
|
||
|
*outptr = '\0';
|
||
|
|
||
|
return DIFF(outptr - bufcoded);
|
||
|
}
|
||
|
|
||
|
|
||
|
//============================ BASED ON SETKEY
|
||
|
const int pr2six[256]={
|
||
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
|
||
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63,
|
||
|
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,
|
||
|
10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27,
|
||
|
28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
|
||
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
|
||
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
|
||
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
|
||
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
|
||
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
|
||
|
64,64,64,64,64,64,64,64,64,64,64,64,64
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// We have to squirt a record into the decoded stream
|
||
|
//
|
||
|
|
||
|
#define CERT_RECORD 13
|
||
|
#define CERT_SIZE_HIBYTE 2 // Index into record of record size
|
||
|
#define CERT_SIZE_LOBYTE 3
|
||
|
|
||
|
unsigned char abCertHeader[] = {0x30, 0x82, // Record
|
||
|
0x00, 0x00, // Size of cert + buff
|
||
|
0x04, 0x0b, 0x63, 0x65,// Cert record data
|
||
|
0x72, 0x74, 0x69, 0x66,
|
||
|
0x69, 0x63, 0x61, 0x74,
|
||
|
0x65 };
|
||
|
|
||
|
void uudecode_cert(char *bufcoded, DWORD *pcbDecoded )
|
||
|
{
|
||
|
int nbytesdecoded;
|
||
|
char *bufin = bufcoded;
|
||
|
unsigned char *bufout = (unsigned char *)bufcoded;
|
||
|
unsigned char *pbuf;
|
||
|
int nprbytes;
|
||
|
char * beginbuf = bufcoded;
|
||
|
|
||
|
ASSERT(bufcoded);
|
||
|
ASSERT(pcbDecoded);
|
||
|
|
||
|
/* Strip leading whitespace. */
|
||
|
|
||
|
while(*bufcoded==' ' ||
|
||
|
*bufcoded == '\t' ||
|
||
|
*bufcoded == '\r' ||
|
||
|
*bufcoded == '\n' )
|
||
|
{
|
||
|
bufcoded++;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If there is a beginning '---- ....' then skip the first line
|
||
|
//
|
||
|
|
||
|
if ( bufcoded[0] == '-' && bufcoded[1] == '-' )
|
||
|
{
|
||
|
bufin = strchr( bufcoded, '\n' );
|
||
|
|
||
|
if ( bufin )
|
||
|
{
|
||
|
bufin++;
|
||
|
bufcoded = bufin;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
bufin = bufcoded;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
bufin = bufcoded;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Strip all cr/lf from the block
|
||
|
//
|
||
|
|
||
|
pbuf = (unsigned char *)bufin;
|
||
|
while ( *pbuf )
|
||
|
{
|
||
|
if ( *pbuf == '\r' || *pbuf == '\n' )
|
||
|
{
|
||
|
memmove( (void*)pbuf, pbuf+1, strlen( (char*)pbuf + 1) + 1 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pbuf++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Figure out how many characters are in the input buffer.
|
||
|
* If this would decode into more bytes than would fit into
|
||
|
* the output buffer, adjust the number of input bytes downwards.
|
||
|
*/
|
||
|
|
||
|
while(pr2six[*(bufin++)] <= 63);
|
||
|
nprbytes = DIFF(bufin - bufcoded) - 1;
|
||
|
nbytesdecoded = ((nprbytes+3)/4) * 3;
|
||
|
|
||
|
bufin = bufcoded;
|
||
|
|
||
|
while (nprbytes > 0) {
|
||
|
*(bufout++) =
|
||
|
(unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
|
||
|
*(bufout++) =
|
||
|
(unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
|
||
|
*(bufout++) =
|
||
|
(unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
|
||
|
bufin += 4;
|
||
|
nprbytes -= 4;
|
||
|
}
|
||
|
|
||
|
if(nprbytes & 03) {
|
||
|
if(pr2six[bufin[-2]] > 63)
|
||
|
nbytesdecoded -= 2;
|
||
|
else
|
||
|
nbytesdecoded -= 1;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now we need to add a new wrapper sequence around the certificate
|
||
|
// indicating this is a certificate
|
||
|
//
|
||
|
|
||
|
memmove( beginbuf + sizeof(abCertHeader),
|
||
|
beginbuf,
|
||
|
nbytesdecoded );
|
||
|
|
||
|
memcpy( beginbuf,
|
||
|
abCertHeader,
|
||
|
sizeof(abCertHeader) );
|
||
|
|
||
|
//
|
||
|
// The beginning record size is the total number of bytes decoded plus
|
||
|
// the number of bytes in the certificate header
|
||
|
//
|
||
|
|
||
|
beginbuf[CERT_SIZE_HIBYTE] = (BYTE) (((USHORT)nbytesdecoded+CERT_RECORD) >> 8);
|
||
|
beginbuf[CERT_SIZE_LOBYTE] = (BYTE) ((USHORT)nbytesdecoded+CERT_RECORD);
|
||
|
|
||
|
nbytesdecoded += sizeof(abCertHeader);
|
||
|
|
||
|
if ( pcbDecoded )
|
||
|
*pcbDecoded = nbytesdecoded;
|
||
|
}
|
||
|
// ============ END BASED ON SETKEY
|
||
|
|
||
|
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
BOOL CKey::FImportKeySetFiles( CString szPrivate, CString szPublic, CString &szPass )
|
||
|
{
|
||
|
BOOL fSuccess = TRUE;
|
||
|
|
||
|
// in this routine, we load the data from the file, initialize it, and ask
|
||
|
// the user for a password, which we then confirm with AcquireCredHandle.
|
||
|
|
||
|
// several things we will be doing can throw, so use a try/catch
|
||
|
try
|
||
|
{
|
||
|
// start by opening the private data file
|
||
|
CFile cfile( szPrivate, CFile::modeRead|CFile::shareDenyWrite );
|
||
|
// get the length of the file
|
||
|
m_cbPrivateKey = cfile.GetLength();
|
||
|
// create a handle to hold the data
|
||
|
m_pPrivateKey = GlobalAlloc( GPTR, m_cbPrivateKey );
|
||
|
if ( !m_pPrivateKey )
|
||
|
{
|
||
|
cfile.Close();
|
||
|
AfxThrowMemoryException();
|
||
|
};
|
||
|
// great, now read the data out of the file
|
||
|
cfile.Read( m_pPrivateKey, m_cbPrivateKey );
|
||
|
// close the file
|
||
|
cfile.Close();
|
||
|
|
||
|
|
||
|
// reading in the certificate is easy because that was done elsewhere
|
||
|
if ( szPublic && !szPublic.IsEmpty() )
|
||
|
{
|
||
|
fSuccess = FInstallCertificate( szPublic, szPass );
|
||
|
if ( fSuccess )
|
||
|
// set the password
|
||
|
m_szPassword = szPass;
|
||
|
}
|
||
|
}
|
||
|
catch( CException e )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return fSuccess;
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
void ReadWriteDWORD( CFile *pFile, DWORD *pDword, BOOL fRead );
|
||
|
void ReadWriteString( CFile *pFile, CString &sz, BOOL fRead );
|
||
|
void ReadWriteBlob( CFile *pFile, PVOID pBlob, DWORD cbBlob, BOOL fRead );
|
||
|
//------------------------------------------------------------------------------
|
||
|
BOOL CKey::FImportExportBackupFile( CString szFile, BOOL fImport )
|
||
|
{
|
||
|
DWORD dword;
|
||
|
UINT nOpenFlags;
|
||
|
CConfirmPassDlg dlgconfirm;
|
||
|
|
||
|
|
||
|
// set up the right open flags
|
||
|
if ( fImport )
|
||
|
nOpenFlags = CFile::modeRead | CFile::shareDenyNone;
|
||
|
else
|
||
|
nOpenFlags = CFile::modeCreate | CFile::modeReadWrite | CFile::shareExclusive;
|
||
|
|
||
|
// put it in a try/catch to get any errors
|
||
|
try
|
||
|
{
|
||
|
CFile file( szFile, nOpenFlags );
|
||
|
|
||
|
// do the backup id
|
||
|
dword = BACKUP_ID;
|
||
|
ReadWriteDWORD( &file, &dword, fImport );
|
||
|
|
||
|
// check the backup id
|
||
|
if ( dword != BACKUP_ID )
|
||
|
{
|
||
|
AfxMessageBox( IDS_KEY_FILE_INVALID );
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
// start with the name of the key
|
||
|
CString szName = GetName();
|
||
|
ReadWriteString( &file, szName, fImport );
|
||
|
if ( fImport ) SetName( szName );
|
||
|
|
||
|
|
||
|
// now the private key data size
|
||
|
ReadWriteDWORD( &file, &m_cbPrivateKey, fImport );
|
||
|
|
||
|
// make a private key data pointer if necessary
|
||
|
if ( fImport && m_cbPrivateKey )
|
||
|
{
|
||
|
m_pPrivateKey = GlobalAlloc( GPTR, m_cbPrivateKey );
|
||
|
if ( !m_pPrivateKey ) AfxThrowMemoryException();
|
||
|
}
|
||
|
|
||
|
// use the private key pointer
|
||
|
if ( m_cbPrivateKey )
|
||
|
ReadWriteBlob( &file, m_pPrivateKey, m_cbPrivateKey, fImport );
|
||
|
|
||
|
|
||
|
// now the certificate
|
||
|
ReadWriteDWORD( &file, &m_cbCertificate, fImport );
|
||
|
|
||
|
// make a data pointer if necessary
|
||
|
if ( fImport && m_cbCertificate )
|
||
|
{
|
||
|
m_pCertificate = GlobalAlloc( GPTR, m_cbCertificate );
|
||
|
if ( !m_pCertificate ) AfxThrowMemoryException();
|
||
|
}
|
||
|
|
||
|
// use the private key pointer
|
||
|
if ( m_cbCertificate )
|
||
|
ReadWriteBlob( &file, m_pCertificate, m_cbCertificate, fImport );
|
||
|
|
||
|
|
||
|
// now the request
|
||
|
ReadWriteDWORD( &file, &m_cbCertificateRequest, fImport );
|
||
|
|
||
|
// make a data pointer if necessary
|
||
|
if ( fImport && m_cbCertificateRequest )
|
||
|
{
|
||
|
m_pCertificateRequest = GlobalAlloc( GPTR, m_cbCertificateRequest );
|
||
|
if ( !m_pCertificateRequest ) AfxThrowMemoryException();
|
||
|
}
|
||
|
|
||
|
// use the private key pointer
|
||
|
if ( m_cbCertificateRequest )
|
||
|
ReadWriteBlob( &file, m_pCertificateRequest, m_cbCertificateRequest, fImport );
|
||
|
|
||
|
|
||
|
// finally, if we are importing, we need to confirm the password
|
||
|
// Except if there is no Cert, which means Import of a Request
|
||
|
if ( m_cbCertificate && fImport )
|
||
|
{
|
||
|
//if we are importing, get the password first
|
||
|
if ( dlgconfirm.DoModal() != IDOK )
|
||
|
return FALSE;
|
||
|
|
||
|
if ( !FVerifyValidPassword(dlgconfirm.m_szPassword) )
|
||
|
{
|
||
|
// the Verify Valid Password routine puts up all
|
||
|
// the correct error dialogs now
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// set the password into place
|
||
|
m_szPassword = dlgconfirm.m_szPassword;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
catch( CException e )
|
||
|
{
|
||
|
// return failure
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// return success
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// file utilities
|
||
|
//---------------------------------------------------------------------------
|
||
|
void ReadWriteDWORD( CFile *pFile, DWORD *pDword, BOOL fRead )
|
||
|
{
|
||
|
ASSERT(pFile);
|
||
|
ASSERT(pDword);
|
||
|
|
||
|
// read it or write it
|
||
|
if ( fRead )
|
||
|
pFile->Read( (void*)pDword, sizeof(DWORD) );
|
||
|
else
|
||
|
pFile->Write( (void*)pDword, sizeof(DWORD) );
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
void ReadWriteString( CFile *pFile, CString &sz, BOOL fRead )
|
||
|
{
|
||
|
ASSERT(pFile);
|
||
|
ASSERT(sz);
|
||
|
|
||
|
// get the length of the string
|
||
|
DWORD cbLength = sz.GetLength();
|
||
|
ReadWriteDWORD(pFile,&cbLength,fRead );
|
||
|
|
||
|
// read or write the string
|
||
|
LPTSTR psz = sz.GetBuffer( cbLength+1 );
|
||
|
ReadWriteBlob(pFile, psz, cbLength+1, fRead);
|
||
|
|
||
|
// free the string buffer
|
||
|
sz.ReleaseBuffer();
|
||
|
}
|
||
|
|
||
|
//---------------------------------------------------------------------------
|
||
|
void ReadWriteBlob( CFile *pFile, PVOID pBlob, DWORD cbBlob, BOOL fRead )
|
||
|
{
|
||
|
ASSERT(pFile);
|
||
|
ASSERT(pBlob);
|
||
|
ASSERT(cbBlob);
|
||
|
|
||
|
// read it or write it
|
||
|
if ( fRead )
|
||
|
pFile->Read( pBlob, cbBlob );
|
||
|
else
|
||
|
pFile->Write( pBlob, cbBlob );
|
||
|
}
|
||
|
|