windows-nt/Source/XPSP1/NT/inetsrv/iis/ui/admin/certmap/addcert.cpp
2020-09-26 16:20:57 +08:00

427 lines
13 KiB
C++

// AddCert.cpp : implementation file
//
#include "stdafx.h"
#include "certmap.h"
// persistence and mapping includes
#include "WrapMaps.h"
#include "wrapmb.h"
#include "ListRow.h"
#include "ChkLstCt.h"
// mapping page includes
#include "brwsdlg.h"
#include "EdtOne11.h"
#include "Ed11Maps.h"
#include "Map11Pge.h"
extern "C"
{
#include <wincrypt.h>
#include <sslsp.h>
}
#include <iismap.hxx>
#include <iiscmr.hxx>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define COL_NUM_NAME 0
#define COL_NUM_NTACCOUNT 1
#define CERT_HEADER "-----BEGIN CERTIFICATE-----"
// the code that reads the certificate file is pretty much lifted from the
// keyring application. Which pretty much lifted it from the setkey application
// 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"
void uudecode_cert(char *bufcoded, DWORD *pcbDecoded );
//---------------------------------------------------------------------------
// originally from keyring - modified to fit
BOOL CMap11Page::FAddCertificateFile( CString szFile )
{
CFile cfile;
PVOID pData = NULL;
BOOL fSuccess =FALSE;;
// open the file
if ( !cfile.Open( szFile, 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 );
return FALSE;
}
// put the rest of the operation in a try/catch
try
{
PCCERT_CONTEXT pCertContext=NULL; //used to determine whether cert file is binary DER encoded
// 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;
// close the file
cfile.Close();
//certificate file may be either be binary DER file or BASE64 encoded file
// try binary DER encoded first
pCertContext= CertCreateCertificateContext(X509_ASN_ENCODING, (const BYTE *)pData, cbRead);
if(pCertContext != NULL)
{
// we created certificate context only to verify that file is binary DER encoded
// free it now
CertFreeCertificateContext(pCertContext);
pCertContext=NULL;
}
else // now try BASE64 encoded
{
// we don't care about header ----BEGIN CERTIFICATE----- or trailer-----END CERTIFICATE-----,
// uudecode will take care of that
uudecode_cert( (PCHAR)pData, &cbRead );
}
// we now have a pointer to a certificate. Lets keep it clean looking
// call another subroutine to finish the job.
fSuccess = FAddCertificate( (PUCHAR)pData, cbRead );
}catch( CException e )
{
// return failure
fSuccess = FALSE;
// if the pointer was allocated, deallocate it
if ( pData )
{
GlobalFree( pData );
pData = NULL;
}
}
// return success
return fSuccess;
}
#define CERT_HEADER_LEN 17
CHAR CertTag[ 13 ] = { 0x04, 0x0b, 'c', 'e', 'r', 't', 'i', 'f', 'i', 'c', 'a', 't', 'e' };
//---------------------------------------------------------------------------
// we are passed in a complete certificate. We need to parse out the subject
// and the issuer fields so we can add the mapping. Then add the mapping.
BOOL CMap11Page::FAddCertificate( PUCHAR pCertificate, DWORD cbCertificate )
{
BOOL fSuccess = FALSE;
// thankfully, the certificate is already in the correct format.
// this means that, for now at least, we don't have to do anything
// special to it to store it. However, we should crack it once just
// to see that we can to prove that it is a valid cert.
ASSERT( pCertificate );
if ( !pCertificate ) return FALSE;
// crack the certificate to prove that we can
PX509Certificate p509 = NULL;
fSuccess = SslCrackCertificate( pCertificate, cbCertificate, CF_CERT_FROM_FILE, &p509 );
if ( fSuccess )
{
SslFreeCertificate( p509 );
}
else
{
// we were not able to crack the certificate. Alert the user and fail
AfxMessageBox( IDS_ERR_INVALID_CERTIFICATE );
return FALSE;
}
// by this point we know we have a valid certificate, make the new mapping and fill it in
// make the new mapping object
C11Mapping* pMapping = PNewMapping();
ASSERT( pMapping );
if( !pMapping )
{
AfxThrowMemoryException(); // seems fairly appropriate
return FALSE;
}
// one more thing before we add the certificate. Skip the header if it is there
PUCHAR pCert = pCertificate;
DWORD cbCert = cbCertificate;
if ( memcmp( pCert + 4, CertTag, sizeof( CertTag ) ) == 0 )
{
pCert += CERT_HEADER_LEN;
cbCert -= CERT_HEADER_LEN;
}
// install the certificate into the mapping
fSuccess &= pMapping->SetCertificate( pCert, cbCert );
// by default, the mapping is enabled
fSuccess &= pMapping->SetMapEnabled( TRUE );
// install a default name
CString sz;
sz.LoadString( IDS_DEFAULT_11MAP );
fSuccess &= pMapping->SetMapName( sz );
// install a blank mapping
fSuccess &= pMapping->SetNTAccount( "" );
if ( !fSuccess )
AfxThrowMemoryException(); // seems fairly appropriate
// now edit the newly created mapping object. If the user cancels,
// then do not add it to the mapper object nor the list
if ( !EditOneMapping( pMapping) )
{
DeleteMapping( pMapping );
return FALSE;
}
// add the mapping item to the list control
fSuccess = FAddMappingToList( pMapping );
// one more test for success
if ( !fSuccess )
{
DeleteMapping( pMapping );
ASSERT( FALSE );
}
// mark the mapping to be saved
if ( fSuccess )
MarkToSave( pMapping );
// return the answer
return fSuccess;
}
// ==============================================================
// The function 'uudecode_cert' IS THE SAME function that is
// found in file: Addcert.cpp if we make the following code
// have a FALSE for bAddWrapperAroundCert -- surely we can unify
// these 2 functions. Having 2 functions named 'uudecode_cert'
// was causing me LINKING errors. + we have 2 instances of
// the external tables: uudecode_cert and pr2six
//
// Since I am linking both Addcert.cpp and CKey.cpp I choose to
// leave the defintions intact for CKey.cpp [ and have extended
// uudecode_cert by adding conditional code as shown below] Further
// work needs to be done after identification as to why I need both
// Addcert.cpp and CKey.cpp to pass bAddWrapperAroundCert as a
// parameter so that both files can be supported.
// ==============================================================
// BOOL bAddWrapperAroundCert = TRUE;
// if (bAddWrapperAroundCert) {
// //
// // 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);
// }
// #ifdef WE_ARE_USING_THE_VERSION_IN__CKey_cpp__NOT_THIS_ONE__ITS_JUST_LIKE_THIS_ONE_WITH_1SMALL_CHANGE
//============================ 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 == ' ') || (*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
//#endif /* WE_ARE_USING_THE_VERSION_IN__CKey_cpp__NOT_THIS_ONE__ITS_JUST_LIKE_THIS_ONE_WITH_1SMALL_CHANGE */