1160 lines
30 KiB
C++
1160 lines
30 KiB
C++
/*++
|
||
|
||
Copyright (c) 1997-1999 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
efscert.cxx
|
||
|
||
Abstract:
|
||
|
||
EFS Certificate management code
|
||
|
||
Author:
|
||
|
||
Robert Reichel (RobertRe) July 4, 1997
|
||
Robert Gu (RobertG) Dec. 4, 1997
|
||
|
||
Environment:
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include <lsapch.hxx>
|
||
|
||
extern "C" {
|
||
#include <nt.h>
|
||
#include <ntdef.h>
|
||
#include <ntrtl.h>
|
||
#include <nturtl.h>
|
||
#include <windows.h>
|
||
#include <stdio.h>
|
||
#include <wincrypt.h>
|
||
#include <efsstruc.h>
|
||
#include "lsasrvp.h"
|
||
#include "debug.h"
|
||
#include "efssrv.hxx"
|
||
#include "userkey.h"
|
||
}
|
||
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////////
|
||
// /
|
||
// /
|
||
// Helper Functions /
|
||
// /
|
||
// /
|
||
/////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
PCCERT_CONTEXT
|
||
GetCertContextFromCertHash(
|
||
IN PBYTE pbHash,
|
||
IN DWORD cbHash,
|
||
IN DWORD dwFlags
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Finds the cert with the passed cert hash in the user's MY store
|
||
and returns a context pointer.
|
||
|
||
Arguments:
|
||
|
||
pbHash - Supplies a pointer to the hash to be matched.
|
||
|
||
cbHash - Supplies the length in bytes of the passed hash.
|
||
|
||
dwFlags - Supplies flags to CertOpenStore
|
||
|
||
Return Value:
|
||
|
||
Returns a pointer to a certificate context, or NULL.
|
||
The returned context must be freed via CertFreeCertificateContext()
|
||
|
||
--*/
|
||
|
||
{
|
||
CRYPT_HASH_BLOB hashBlob;
|
||
PCCERT_CONTEXT pCertContext = NULL;
|
||
|
||
//HCERTSTORE hStore = CertOpenSystemStoreW( NULL, L"MY");
|
||
|
||
HCERTSTORE hStore = CertOpenStore(
|
||
CERT_STORE_PROV_SYSTEM_REGISTRY_W,
|
||
0, // dwEncodingType
|
||
0, // hCryptProv,
|
||
dwFlags,
|
||
L"My"
|
||
);
|
||
|
||
if (hStore != NULL) {
|
||
|
||
//
|
||
// Find our cert via the hash
|
||
//
|
||
|
||
hashBlob.cbData = cbHash;
|
||
hashBlob.pbData = pbHash;
|
||
|
||
pCertContext = CertFindCertificateInStore( hStore,
|
||
CRYPT_ASN_ENCODING,
|
||
0,
|
||
CERT_FIND_HASH,
|
||
&hashBlob,
|
||
NULL
|
||
);
|
||
CertCloseStore( hStore, 0 );
|
||
}
|
||
|
||
return( pCertContext );
|
||
}
|
||
|
||
|
||
LPWSTR
|
||
EfspGetCertDisplayInformation(
|
||
IN PCCERT_CONTEXT pCertContext
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Returns the display string from the passed certificate context.
|
||
|
||
Arguments:
|
||
|
||
pCertContext - Supplies a pointer to an open certificate context.
|
||
|
||
Return Value:
|
||
|
||
On success, pointer to display string. Caller must call
|
||
LsapFreeLsaHeap() to free.
|
||
|
||
NULL on failure.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD rc;
|
||
LPWSTR UserDispName = NULL;
|
||
|
||
rc = EfsGetCertNameFromCertContext(
|
||
pCertContext,
|
||
&UserDispName
|
||
);
|
||
|
||
if (rc == ERROR_SUCCESS) {
|
||
return UserDispName;
|
||
} else {
|
||
SetLastError(rc);
|
||
return NULL;
|
||
}
|
||
|
||
}
|
||
|
||
PBYTE
|
||
GetCertHashFromCertContext(
|
||
IN PCCERT_CONTEXT pCertContext,
|
||
OUT PDWORD pcbHash
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Helper routine, takes a cert context and extracts the hash.
|
||
|
||
Arguments:
|
||
|
||
pCertContext - Supplies the cert context.
|
||
|
||
pcbHash - Returns the length in bytes of the returned hash.
|
||
|
||
Return Value:
|
||
|
||
Returns a pointer to a hash block allocated out of heap memory,
|
||
or NULL if either the attempt to get the hash failed or the attempt
|
||
to allocate memory failed.
|
||
|
||
Call GetLastError() for more details in case of failure.
|
||
|
||
--*/
|
||
{
|
||
PBYTE pbHash = NULL;
|
||
*pcbHash = 0;
|
||
|
||
if (CertGetCertificateContextProperty(
|
||
pCertContext,
|
||
CERT_HASH_PROP_ID,
|
||
NULL,
|
||
pcbHash
|
||
)) {
|
||
|
||
pbHash = (PBYTE)LsapAllocateLsaHeap( *pcbHash );
|
||
|
||
if (pbHash != NULL) {
|
||
|
||
if (!CertGetCertificateContextProperty(
|
||
pCertContext,
|
||
CERT_HASH_PROP_ID,
|
||
pbHash,
|
||
pcbHash
|
||
)) {
|
||
|
||
LsapFreeLsaHeap( pbHash );
|
||
pbHash = NULL;
|
||
*pcbHash = 0;
|
||
}
|
||
|
||
} else {
|
||
|
||
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
||
}
|
||
}
|
||
|
||
return( pbHash );
|
||
}
|
||
|
||
PCERT_PUBLIC_KEY_INFO
|
||
ExportPublicKeyInfo(
|
||
IN HCRYPTPROV hProv,
|
||
IN DWORD dwKeySpec,
|
||
IN DWORD dwCertEncodingType,
|
||
IN OUT DWORD *pcbInfo
|
||
)
|
||
{
|
||
PCERT_PUBLIC_KEY_INFO pPubKeyInfo = NULL;
|
||
|
||
if ( CryptExportPublicKeyInfo(
|
||
hProv,
|
||
dwKeySpec,
|
||
dwCertEncodingType,
|
||
NULL,
|
||
pcbInfo)) {
|
||
|
||
pPubKeyInfo = (PCERT_PUBLIC_KEY_INFO) LsapAllocateLsaHeap(*pcbInfo);
|
||
|
||
if (pPubKeyInfo) {
|
||
|
||
if (!CryptExportPublicKeyInfo( hProv,
|
||
dwKeySpec,
|
||
dwCertEncodingType,
|
||
pPubKeyInfo,
|
||
pcbInfo)) {
|
||
|
||
LsapFreeLsaHeap( pPubKeyInfo );
|
||
pPubKeyInfo = NULL;
|
||
*pcbInfo = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
return ( pPubKeyInfo );
|
||
}
|
||
|
||
BOOL
|
||
EncodeAndAlloc(
|
||
DWORD dwEncodingType,
|
||
LPCSTR lpszStructType,
|
||
const void * pvStructInfo,
|
||
PBYTE * pbEncoded,
|
||
PDWORD pcbEncoded
|
||
)
|
||
{
|
||
BOOL b = FALSE;
|
||
|
||
if (CryptEncodeObject(
|
||
dwEncodingType,
|
||
lpszStructType,
|
||
pvStructInfo,
|
||
NULL,
|
||
pcbEncoded )) {
|
||
|
||
*pbEncoded = (PBYTE)LsapAllocateLsaHeap( *pcbEncoded );
|
||
|
||
if (*pbEncoded) {
|
||
|
||
if (CryptEncodeObject(
|
||
dwEncodingType,
|
||
lpszStructType,
|
||
pvStructInfo,
|
||
*pbEncoded,
|
||
pcbEncoded )) {
|
||
|
||
b = TRUE;
|
||
|
||
} else {
|
||
|
||
LsapFreeLsaHeap( *pbEncoded );
|
||
*pbEncoded = NULL;
|
||
}
|
||
|
||
} else {
|
||
|
||
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
||
}
|
||
}
|
||
|
||
return( b );
|
||
}
|
||
|
||
DWORD
|
||
EfsMakeCertNames(
|
||
IN PEFS_USER_INFO pEfsUserInfo,
|
||
OUT LPWSTR *DispInfo,
|
||
OUT LPWSTR *SubjectName,
|
||
OUT LPWSTR *UPNName
|
||
)
|
||
{
|
||
DWORD rc = ERROR_SUCCESS;
|
||
|
||
*DispInfo = NULL;
|
||
*UPNName = NULL;
|
||
|
||
if (pEfsUserInfo->bDomainAccount) {
|
||
|
||
//
|
||
// Domain Account
|
||
//
|
||
|
||
HRESULT hr;
|
||
HANDLE hDS = NULL;
|
||
DS_NAME_RESULT* UserName = NULL;
|
||
|
||
hr = DsBind(NULL, NULL, &hDS);
|
||
if (hr == NO_ERROR) {
|
||
|
||
rc = DsCrackNames(
|
||
hDS,
|
||
DS_NAME_NO_FLAGS,
|
||
DS_SID_OR_SID_HISTORY_NAME,
|
||
DS_USER_PRINCIPAL_NAME,
|
||
1,
|
||
&(pEfsUserInfo->lpUserSid),
|
||
&UserName
|
||
);
|
||
|
||
if (ERROR_SUCCESS == rc) {
|
||
|
||
if (UserName->rItems[0].status == DS_NAME_NO_ERROR) {
|
||
|
||
*UPNName = (LPWSTR) LsapAllocateLsaHeap((wcslen(UserName->rItems[0].pName) + 1) * sizeof (WCHAR));
|
||
*DispInfo = (LPWSTR) LsapAllocateLsaHeap(
|
||
(wcslen(UserName->rItems[0].pName) +
|
||
wcslen(pEfsUserInfo->lpUserName) +
|
||
3) * sizeof (WCHAR));
|
||
*SubjectName = (LPWSTR) LsapAllocateLsaHeap((wcslen(pEfsUserInfo->lpUserName)+4) * sizeof (WCHAR));
|
||
|
||
if (*UPNName && *DispInfo && *SubjectName ){
|
||
wcscpy(*UPNName, UserName->rItems[0].pName);
|
||
wcscpy(*DispInfo, pEfsUserInfo->lpUserName);
|
||
wcscat(*DispInfo, L"(");
|
||
wcscat(*DispInfo, *UPNName);
|
||
wcscat(*DispInfo, L")");
|
||
wcscpy(*SubjectName, L"CN=");
|
||
wcscat(*SubjectName, pEfsUserInfo->lpUserName);
|
||
} else {
|
||
|
||
if (*UPNName) {
|
||
LsapFreeLsaHeap( *UPNName );
|
||
*UPNName = NULL;
|
||
}
|
||
if (*DispInfo) {
|
||
LsapFreeLsaHeap( *DispInfo );
|
||
*DispInfo = NULL;
|
||
}
|
||
if (*SubjectName) {
|
||
LsapFreeLsaHeap( *SubjectName );
|
||
*SubjectName = NULL;
|
||
}
|
||
rc = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
if (UserName){
|
||
DsFreeNameResult(UserName);
|
||
UserName = NULL;
|
||
}
|
||
|
||
}
|
||
|
||
DsUnBindW( &hDS );
|
||
|
||
}
|
||
}
|
||
|
||
|
||
if (NULL == *UPNName) {
|
||
|
||
//
|
||
// If Local Account, let the UPNNmae be User@Computer. DispInfo be User(User@Computer).
|
||
// Else let the UPNName be User@Domain. DispInfo be User(User@Domain)
|
||
//
|
||
|
||
*UPNName = (LPWSTR) LsapAllocateLsaHeap(
|
||
(wcslen(pEfsUserInfo->lpUserName) +
|
||
wcslen(pEfsUserInfo->lpDomainName) +
|
||
2) * sizeof (WCHAR));
|
||
*DispInfo = (LPWSTR) LsapAllocateLsaHeap(
|
||
(wcslen(pEfsUserInfo->lpDomainName) +
|
||
wcslen(pEfsUserInfo->lpUserName) * 2 +
|
||
4) * sizeof (WCHAR));
|
||
*SubjectName = (LPWSTR) LsapAllocateLsaHeap(
|
||
(wcslen(pEfsUserInfo->lpUserName)+
|
||
4) * sizeof (WCHAR));
|
||
|
||
if (*UPNName && *DispInfo && *SubjectName){
|
||
wcscpy(*UPNName, pEfsUserInfo->lpUserName);
|
||
wcscat(*UPNName, L"@");
|
||
wcscat(*UPNName, pEfsUserInfo->lpDomainName);
|
||
wcscpy(*DispInfo, pEfsUserInfo->lpUserName);
|
||
wcscat(*DispInfo, L"(");
|
||
wcscat(*DispInfo, *UPNName);
|
||
wcscat(*DispInfo, L")");
|
||
wcscpy(*SubjectName, L"CN=");
|
||
wcscat(*SubjectName, pEfsUserInfo->lpUserName);
|
||
} else {
|
||
|
||
if (*UPNName) {
|
||
LsapFreeLsaHeap( *UPNName );
|
||
*UPNName = NULL;
|
||
}
|
||
if (*DispInfo) {
|
||
LsapFreeLsaHeap( *DispInfo );
|
||
*DispInfo = NULL;
|
||
}
|
||
if (*SubjectName) {
|
||
LsapFreeLsaHeap( *SubjectName );
|
||
*SubjectName = NULL;
|
||
}
|
||
rc = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
}
|
||
return rc;
|
||
}
|
||
|
||
|
||
#if 0
|
||
|
||
LPWSTR
|
||
MakeDNName(
|
||
BOOLEAN RecoveryKey,
|
||
IN PEFS_USER_INFO pEfsUserInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Fabricates a display name for a locally built self-signed cert
|
||
|
||
Arguments:
|
||
|
||
RecoveryKey - Specifies if this is a recovery key or not.
|
||
|
||
Return Value:
|
||
|
||
Returns a string containing a display name, or NULL.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
LPWSTR DNName = NULL;
|
||
LPCWSTR DNNameTemplate = L"CN=%ws,L=EFS,OU=EFS File Encryption Certificate";
|
||
DWORD cbDNName = 0;
|
||
|
||
if (RecoveryKey) {
|
||
|
||
|
||
cbDNName = (wcslen( DNNameTemplate ) + 1) * sizeof( WCHAR ) + (wcslen( EfsComputerName ) + 1) * sizeof( WCHAR );
|
||
|
||
DNName = (LPWSTR)LsapAllocateLsaHeap( cbDNName );
|
||
|
||
if (DNName) {
|
||
|
||
swprintf( DNName, DNNameTemplate, EfsComputerName );
|
||
|
||
} else {
|
||
|
||
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
||
}
|
||
|
||
} else {
|
||
|
||
|
||
//
|
||
// This will be an overestimate, but only by a little.
|
||
//
|
||
|
||
cbDNName = (wcslen( DNNameTemplate ) * sizeof( WCHAR )) + (wcslen( pEfsUserInfo->lpUserName ) + 1) * sizeof( WCHAR );
|
||
|
||
DNName = (LPWSTR)LsapAllocateLsaHeap( cbDNName );
|
||
|
||
if (DNName != NULL) {
|
||
|
||
swprintf( DNName, DNNameTemplate, pEfsUserInfo->lpUserName );
|
||
|
||
} else {
|
||
|
||
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
||
}
|
||
|
||
|
||
}
|
||
|
||
return( DNName );
|
||
}
|
||
|
||
#endif
|
||
|
||
|
||
DWORD
|
||
EfsFindCertOid(
|
||
IN LPSTR pEfsCertOid,
|
||
IN PCCERT_CONTEXT pCertContext,
|
||
OUT BOOL *OidFound
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine takes a cert context and an Efs Oid. It will check if the cert has the Efs Oid or not.
|
||
|
||
Arguments:
|
||
|
||
pEfsCertOid - Efs Oid to be searched for.
|
||
|
||
pCertContext - The cert to be searched for.
|
||
|
||
OidFound - The result. TRUE if the oid is found.
|
||
|
||
Return Value:
|
||
|
||
Win32 Error code.
|
||
|
||
--*/
|
||
{
|
||
BOOL bRet;
|
||
PCERT_ENHKEY_USAGE pUsage;
|
||
DWORD pcbUsage = 0;
|
||
DWORD rc = ERROR_SUCCESS;
|
||
DWORD ii;
|
||
|
||
*OidFound = FALSE;
|
||
|
||
bRet = CertGetEnhancedKeyUsage(
|
||
pCertContext,
|
||
0,
|
||
NULL,
|
||
&pcbUsage
|
||
);
|
||
if (bRet) {
|
||
pUsage = (PCERT_ENHKEY_USAGE) LsapAllocateLsaHeap(pcbUsage);
|
||
if (pUsage) {
|
||
bRet = CertGetEnhancedKeyUsage(
|
||
pCertContext,
|
||
0,
|
||
pUsage,
|
||
&pcbUsage
|
||
);
|
||
if (bRet){
|
||
for (ii=0; ii<pUsage->cUsageIdentifier;ii++) {
|
||
if (!strcmp(pUsage->rgpszUsageIdentifier[ii], pEfsCertOid)){
|
||
|
||
//
|
||
// We found the OID
|
||
//
|
||
*OidFound = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
} else {
|
||
rc = GetLastError();
|
||
}
|
||
|
||
LsapFreeLsaHeap(pUsage);
|
||
|
||
} else {
|
||
rc = ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
} else {
|
||
rc = GetLastError();
|
||
}
|
||
return rc;
|
||
}
|
||
|
||
|
||
DWORD
|
||
GetKeyInfoFromCertHash(
|
||
IN OUT PEFS_USER_INFO pEfsUserInfo,
|
||
IN PBYTE pbHash,
|
||
IN DWORD cbHash,
|
||
OUT HCRYPTKEY * hKey OPTIONAL,
|
||
OUT HCRYPTPROV * hProv OPTIONAL,
|
||
OUT LPWSTR * ContainerName OPTIONAL,
|
||
OUT LPWSTR * ProviderName OPTIONAL,
|
||
OUT LPWSTR * DisplayInformation OPTIONAL,
|
||
OUT PBOOLEAN pbIsValid OPTIONAL
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine takes a certificate hash and extracts from it information
|
||
about the key it represents. If the key information from this
|
||
cert does not exist in the current context, it will return an error.
|
||
|
||
Arguments:
|
||
|
||
pEfsUserInfo - User Information
|
||
|
||
pbHash - Takes a pointer to the certificate hash.
|
||
|
||
cbHash - The length in bytes of the certificate hash.
|
||
|
||
hKey - Returns the handle to the key corresponding to this
|
||
certificate. Must be passed of hProv is passed.
|
||
|
||
hProv - Returns the handle to the context corresponding to this
|
||
certificate. Must be passed of hKey is passed.
|
||
|
||
ContainerName - Returns a string with the name of the container of the
|
||
key in this certificate.
|
||
|
||
ProviderName - Returns a string with the name of the provider of the
|
||
key in this certificate.
|
||
|
||
DisplayInformation - Returns the display information for the certificate.
|
||
|
||
pbIsValid - If present, causes the cert to be validity checked and the
|
||
results returned.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS - The passed certificate is in the current user's MY
|
||
store and the key it represents is in his context.
|
||
|
||
!ERROR_SUCCESS - Either the certificate could not be found in the
|
||
user's MY store, or the key in the certificate could not be
|
||
instantiated.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCCERT_CONTEXT pCertContext;
|
||
|
||
//
|
||
// Don't trust CryptoAPI to set last error properly,
|
||
// keep track of success and failure on our own.
|
||
//
|
||
|
||
BOOLEAN b = TRUE;
|
||
BOOLEAN CreateCache = FALSE;
|
||
BOOLEAN LocalCertValidated = FALSE;
|
||
BOOLEAN DataNotCached = TRUE;
|
||
DWORD rc = ERROR_SUCCESS;
|
||
DWORD rc2 = ERROR_SUCCESS;
|
||
|
||
HCRYPTKEY hLocalKey = NULL;
|
||
HCRYPTPROV hLocalProv = NULL;
|
||
LPWSTR LocalContainerName = NULL;
|
||
LPWSTR LocalProviderName = NULL;
|
||
LPWSTR LocalDisplayInformation = NULL;
|
||
|
||
//
|
||
// Output parameters
|
||
//
|
||
|
||
if (ARGUMENT_PRESENT(ContainerName)) {
|
||
*ContainerName = NULL;
|
||
}
|
||
|
||
if (ARGUMENT_PRESENT(ProviderName)) {
|
||
*ProviderName = NULL;
|
||
}
|
||
|
||
if (ARGUMENT_PRESENT(DisplayInformation)) {
|
||
*DisplayInformation = NULL;
|
||
}
|
||
|
||
if (ARGUMENT_PRESENT(hProv)) {
|
||
*hProv = NULL;
|
||
}
|
||
|
||
if (ARGUMENT_PRESENT(hKey)) {
|
||
*hKey = NULL;
|
||
}
|
||
|
||
if (ARGUMENT_PRESENT( pbIsValid )){
|
||
*pbIsValid = FALSE;
|
||
}
|
||
|
||
//
|
||
// Check if a cache node is available
|
||
//
|
||
|
||
if (!pEfsUserInfo->UserCacheStop) {
|
||
if (pEfsUserInfo->pUserCache) {
|
||
|
||
//
|
||
// The user has a cache, check if the Hash matches
|
||
//
|
||
|
||
if ( pEfsUserInfo->pUserCache->cbHash == cbHash ) {
|
||
|
||
if(RtlEqualMemory( pEfsUserInfo->pUserCache->pbHash, pbHash, cbHash)){
|
||
|
||
//
|
||
// Cache is valid. Use the cache
|
||
//
|
||
|
||
|
||
if (ARGUMENT_PRESENT( pbIsValid )){
|
||
*pbIsValid = (pEfsUserInfo->pUserCache->CertValidated == CERT_VALIDATED);
|
||
}
|
||
return ERROR_SUCCESS;
|
||
|
||
}
|
||
|
||
//
|
||
// User might use an old key, do not put in the cache.
|
||
//
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
CreateCache = TRUE;
|
||
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Find our cert via the hash
|
||
//
|
||
|
||
pCertContext = GetCertContextFromCertHash(
|
||
pbHash,
|
||
cbHash,
|
||
CERT_SYSTEM_STORE_CURRENT_USER
|
||
);
|
||
|
||
if (pCertContext != NULL) {
|
||
|
||
PCRYPT_KEY_PROV_INFO pCryptKeyProvInfo = GetKeyProvInfo( pCertContext );
|
||
|
||
if (pCryptKeyProvInfo != NULL) {
|
||
|
||
//
|
||
// Copy out the container name and provider name if requested.
|
||
//
|
||
|
||
|
||
if (pCryptKeyProvInfo->pwszContainerName) {
|
||
LocalContainerName = (LPWSTR)LsapAllocateLsaHeap( wcslen(pCryptKeyProvInfo->pwszContainerName) * sizeof( WCHAR ) + sizeof( UNICODE_NULL ));
|
||
if (LocalContainerName != NULL) {
|
||
wcscpy( LocalContainerName, pCryptKeyProvInfo->pwszContainerName );
|
||
} else {
|
||
rc = ERROR_NOT_ENOUGH_MEMORY;
|
||
b = FALSE;
|
||
}
|
||
}
|
||
if (b && pCryptKeyProvInfo->pwszProvName) {
|
||
LocalProviderName = (LPWSTR)LsapAllocateLsaHeap( wcslen(pCryptKeyProvInfo->pwszProvName) * sizeof( WCHAR ) + sizeof( UNICODE_NULL ));
|
||
if (LocalProviderName != NULL) {
|
||
wcscpy( LocalProviderName, pCryptKeyProvInfo->pwszProvName );
|
||
}
|
||
else {
|
||
rc = ERROR_NOT_ENOUGH_MEMORY;
|
||
b = FALSE;
|
||
}
|
||
}
|
||
if (!(LocalDisplayInformation = EfspGetCertDisplayInformation( pCertContext ))) {
|
||
|
||
//
|
||
// At least for now, we do not accept Cert without display name
|
||
//
|
||
|
||
rc = GetLastError();
|
||
b = FALSE;
|
||
}
|
||
|
||
//
|
||
// Get the key information
|
||
//
|
||
|
||
if (b) {
|
||
|
||
if (CryptAcquireContext( &hLocalProv, pCryptKeyProvInfo->pwszContainerName, pCryptKeyProvInfo->pwszProvName, PROV_RSA_FULL, CRYPT_SILENT)) {
|
||
|
||
if (!CryptGetUserKey(hLocalProv, AT_KEYEXCHANGE, &hLocalKey)) {
|
||
|
||
rc = GetLastError();
|
||
b = FALSE;
|
||
}
|
||
|
||
} else {
|
||
|
||
rc = GetLastError();
|
||
b = FALSE;
|
||
}
|
||
|
||
}
|
||
|
||
if (b) {
|
||
|
||
if ( ARGUMENT_PRESENT( pbIsValid ) || CreateCache ) {
|
||
|
||
//
|
||
// Do cert validity checking. Check time and usage.
|
||
//
|
||
|
||
if ( CertVerifyTimeValidity(
|
||
NULL,
|
||
pCertContext->pCertInfo
|
||
)){
|
||
|
||
rc2 = CERT_E_EXPIRED;
|
||
|
||
//b = FALSE;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Test the cert usage here.
|
||
// CERT_E_WRONG_USAGE
|
||
//
|
||
|
||
BOOL OidFound;
|
||
|
||
|
||
rc = EfsFindCertOid(
|
||
szOID_KP_EFS,
|
||
pCertContext,
|
||
&OidFound
|
||
);
|
||
|
||
if (ERROR_SUCCESS == rc) {
|
||
if (OidFound) {
|
||
|
||
LocalCertValidated = TRUE;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
b = FALSE;
|
||
|
||
}
|
||
|
||
|
||
}
|
||
|
||
|
||
if (ARGUMENT_PRESENT( pbIsValid )) {
|
||
|
||
//
|
||
// We need the validation info.
|
||
//
|
||
|
||
*pbIsValid = LocalCertValidated;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if ( CreateCache ) {
|
||
|
||
DWORD certFlag;
|
||
|
||
//
|
||
// Todetermine if we can put the data in cache.
|
||
//
|
||
|
||
if (CurrentHashOK(pEfsUserInfo, pbHash, cbHash, &certFlag)) {
|
||
|
||
//
|
||
// This pbHash is in the user's key or has been put in. Let's create the cache node.
|
||
//
|
||
|
||
PUSER_CACHE pCacheNode;
|
||
PBYTE pbWkHash;
|
||
DWORD ImpersonationError = 0;
|
||
|
||
if (certFlag != CERTINLMTRUSTEDSTORE) {
|
||
|
||
DWORD sevRc;
|
||
|
||
//
|
||
// The cert is not in the LM Trusted store. Upgrade system from Win2K, or Beta 1 Whistler.
|
||
//
|
||
|
||
if (ERROR_SUCCESS == (sevRc = EfsAddCertToTrustStoreStore(pCertContext, &ImpersonationError))) {
|
||
EfsMarkCertAddedToStore(pEfsUserInfo);
|
||
} else {
|
||
if (ImpersonationError) {
|
||
|
||
//
|
||
// Got in trouble. We could not impersonate back.
|
||
//
|
||
|
||
ASSERT(FALSE);
|
||
rc = sevRc;
|
||
b = FALSE;
|
||
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
if (!ImpersonationError) {
|
||
|
||
pCacheNode = (PUSER_CACHE) LsapAllocateLsaHeap(sizeof(USER_CACHE));
|
||
|
||
pbWkHash = (PBYTE) LsapAllocateLsaHeap(cbHash);
|
||
|
||
if (pCacheNode && pbWkHash) {
|
||
|
||
memset( pCacheNode, 0, sizeof( USER_CACHE ));
|
||
RtlCopyMemory(pbWkHash, pbHash, cbHash);
|
||
|
||
|
||
if (NT_SUCCESS( NtQuerySystemTime(&(pCacheNode->TimeStamp)))){
|
||
|
||
if (EfspInitUserCacheNode(
|
||
pCacheNode,
|
||
pbWkHash,
|
||
cbHash,
|
||
LocalContainerName,
|
||
LocalProviderName,
|
||
LocalDisplayInformation,
|
||
pCertContext,
|
||
hLocalKey,
|
||
hLocalProv,
|
||
&(pEfsUserInfo->AuthId),
|
||
LocalCertValidated? CERT_VALIDATED:CERT_VALIDATION_FAILED
|
||
)){
|
||
|
||
//
|
||
// Cache node created and ready for use. Do not delete or close the info
|
||
// we just got.
|
||
//
|
||
|
||
LocalContainerName = NULL;
|
||
LocalProviderName = NULL;
|
||
LocalDisplayInformation = NULL;
|
||
hLocalKey = NULL;
|
||
hLocalProv = NULL;
|
||
pEfsUserInfo->pUserCache = pCacheNode;
|
||
|
||
pCertContext = NULL;
|
||
DataNotCached = FALSE;
|
||
rc = ERROR_SUCCESS;
|
||
b = TRUE; // We can have a non-validated cache node for the use of open file
|
||
|
||
} else {
|
||
|
||
LsapFreeLsaHeap(pCacheNode);
|
||
LsapFreeLsaHeap(pbWkHash);
|
||
pbWkHash = NULL;
|
||
pCacheNode = NULL;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
LsapFreeLsaHeap(pCacheNode);
|
||
LsapFreeLsaHeap(pbWkHash);
|
||
pbWkHash = NULL;
|
||
pCacheNode = NULL;
|
||
|
||
}
|
||
|
||
} else {
|
||
if (pCacheNode) {
|
||
LsapFreeLsaHeap(pCacheNode);
|
||
pCacheNode = NULL;
|
||
}
|
||
if (pbWkHash) {
|
||
LsapFreeLsaHeap(pbWkHash);
|
||
pbWkHash = NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
if (DataNotCached && b) {
|
||
|
||
//
|
||
// We need to returned the data to outside
|
||
//
|
||
|
||
|
||
if (ARGUMENT_PRESENT(ContainerName)) {
|
||
|
||
*ContainerName = LocalContainerName;
|
||
LocalContainerName = NULL;
|
||
|
||
}
|
||
|
||
if (ARGUMENT_PRESENT(ProviderName)) {
|
||
*ProviderName = LocalProviderName;
|
||
LocalProviderName = NULL;
|
||
}
|
||
|
||
if (ARGUMENT_PRESENT(DisplayInformation)) {
|
||
*DisplayInformation = LocalDisplayInformation;
|
||
LocalDisplayInformation = NULL;
|
||
}
|
||
|
||
if (ARGUMENT_PRESENT(hKey)) {
|
||
*hKey = hLocalKey;
|
||
hLocalKey = NULL;
|
||
|
||
}
|
||
|
||
if (ARGUMENT_PRESENT(hProv)) {
|
||
*hProv = hLocalProv;
|
||
hLocalProv = NULL;
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
LsapFreeLsaHeap( pCryptKeyProvInfo );
|
||
|
||
|
||
} else {
|
||
|
||
rc = GetLastError();
|
||
b = FALSE;
|
||
}
|
||
|
||
if (pCertContext) {
|
||
|
||
CertFreeCertificateContext( pCertContext );
|
||
|
||
}
|
||
|
||
|
||
} else {
|
||
|
||
rc = GetLastError();
|
||
b = FALSE;
|
||
}
|
||
|
||
if (!b) {
|
||
|
||
ASSERT( rc != ERROR_SUCCESS );
|
||
|
||
//
|
||
// Something failed, cleanup the stuff we were going to return
|
||
//
|
||
|
||
if ( LocalContainerName) {
|
||
LsapFreeLsaHeap( LocalContainerName );
|
||
}
|
||
|
||
if (LocalProviderName) {
|
||
LsapFreeLsaHeap( LocalProviderName );
|
||
}
|
||
|
||
if (LocalDisplayInformation) {
|
||
LsapFreeLsaHeap( LocalDisplayInformation );
|
||
}
|
||
|
||
if (hLocalKey) {
|
||
CryptDestroyKey( hLocalKey );
|
||
}
|
||
|
||
if (hLocalProv) {
|
||
CryptReleaseContext( hLocalProv, 0 );
|
||
}
|
||
}
|
||
|
||
if (ARGUMENT_PRESENT( pbIsValid ) && !LocalCertValidated ) {
|
||
if (rc == ERROR_SUCCESS) {
|
||
rc = rc2;
|
||
}
|
||
}
|
||
|
||
return( rc );
|
||
}
|
||
|
||
|
||
PCRYPT_KEY_PROV_INFO
|
||
GetKeyProvInfo(
|
||
PCCERT_CONTEXT pCertContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine will extract the Key Provider Information from
|
||
the passed certificate context.
|
||
|
||
Arguments:
|
||
|
||
pCertContext - Supplies a pointer to a certificate context.
|
||
|
||
Return Value:
|
||
|
||
Returns a pointer to a PCRYPT_KEY_PROV_INFO structure on success,
|
||
otherwise returns NULL, which usually means that the certificate
|
||
did not have the context property we were looking for (meaning
|
||
that it probably isn't an EFS certificate).
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD cbData = 0;
|
||
BOOL b;
|
||
PCRYPT_KEY_PROV_INFO pCryptKeyProvInfo = NULL;
|
||
|
||
b = CertGetCertificateContextProperty(
|
||
pCertContext,
|
||
CERT_KEY_PROV_INFO_PROP_ID,
|
||
NULL,
|
||
&cbData
|
||
);
|
||
|
||
if (b) {
|
||
|
||
pCryptKeyProvInfo = (PCRYPT_KEY_PROV_INFO)LsapAllocateLsaHeap( cbData );
|
||
|
||
if (pCryptKeyProvInfo != NULL) {
|
||
|
||
b = CertGetCertificateContextProperty(
|
||
pCertContext,
|
||
CERT_KEY_PROV_INFO_PROP_ID,
|
||
pCryptKeyProvInfo,
|
||
&cbData
|
||
);
|
||
|
||
if (!b) {
|
||
|
||
LsapFreeLsaHeap( pCryptKeyProvInfo );
|
||
pCryptKeyProvInfo = NULL;
|
||
}
|
||
|
||
} else {
|
||
|
||
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
||
}
|
||
}
|
||
|
||
return ( pCryptKeyProvInfo );
|
||
}
|