Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //---------------------------------------------------------------------------
- // Módulo de certificados digitais
- //
- #pragma hdrstop
- #include "CertUtil.h"
- #include <string.h>
- #include <ctype.h>
- #pragma comment(lib, "crypt32.lib")
- #pragma comment(lib, "cryptxml.lib")
- #pragma package(smart_init)
- //---------------------------------------------------------------------------
- // Estrutura para o buffer de dados
- //
- struct CertUtil_Buffer {
- BYTE *pbData;
- ULONG cbData;
- ULONG cbMaxData;
- };
- //---------------------------------------------------------------------------
- // Gravação em buffer de memória
- //
- static HRESULT CALLBACK CertUtil_writeXmlToBuffer( void *param,
- const BYTE *pbData, ULONG cbData )
- {
- HRESULT hr = S_FALSE;
- CertUtil_Buffer *buffer = (CertUtil_Buffer*)param;
- if (buffer == NULL)
- hr = E_INVALIDARG;
- else
- {
- if (buffer->pbData == NULL || buffer->cbData + cbData > buffer->cbMaxData)
- {
- ULONG md = buffer->cbMaxData;
- BYTE *pb;
- while (md < buffer->cbData + cbData + 256)
- md += 512;
- if ((pb = (PBYTE)LocalAlloc( LPTR, (SIZE_T)md )) == NULL)
- {
- hr = HRESULT_FROM_WIN32( GetLastError() );
- if (hr == S_OK)
- hr = E_OUTOFMEMORY;
- return hr;
- }
- if (buffer->pbData != NULL)
- {
- memcpy( (void*)pb, (void*)buffer->pbData,
- (size_t)(buffer->cbData * sizeof(BYTE)) );
- LocalFree( buffer->pbData );
- }
- else
- buffer->cbData = 0;
- buffer->pbData = pb;
- buffer->cbMaxData = md;
- }
- memcpy( (void*)(buffer->pbData + buffer->cbData), (void*)pbData,
- (size_t)(cbData * sizeof(BYTE)) );
- buffer->cbData += cbData;
- hr = S_OK;
- }
- return hr;
- }
- //---------------------------------------------------------------------------
- // Gravação em arquivo
- //
- static HRESULT CALLBACK CertUtil_writeXmlToFile( void *param,
- const BYTE *pbData, ULONG cbData )
- {
- HRESULT hr = S_FALSE;
- DWORD bw = 0;
- HANDLE hFile = (HANDLE)param;
- if (INVALID_HANDLE_VALUE == hFile)
- hr = E_INVALIDARG;
- else
- {
- if (!WriteFile( hFile, pbData, cbData, &bw, NULL ))
- {
- hr = HRESULT_FROM_WIN32( GetLastError() );
- if (hr == S_OK)
- hr = E_FAIL;
- }
- else if (bw != cbData)
- hr = E_FAIL;
- else
- hr = S_OK;
- }
- return hr;
- }
- //---------------------------------------------------------------------------
- // Converte resultado (HRESULT) para o código erro do Windows
- //
- static DWORD CertUtil_Win32FromHResult( HRESULT hr )
- {
- if ((HRESULT)(hr & 0xFFFF0000) == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, 0))
- return HRESULT_CODE(hr);
- if (hr == S_OK)
- return ERROR_SUCCESS;
- // Not a Win32 HRESULT so return a generic error code.
- return ERROR_CAN_NOT_COMPLETE;
- }
- //---------------------------------------------------------------------------
- // Converte data de arquivo (FILETIME) para TDateTime
- //
- System::TDateTime CertUtil_FileTimeToDateTime( FILETIME *ft )
- {
- SYSTEMTIME stUTC, stLocal;
- System::TDateTime result;
- if (FileTimeToSystemTime( ft, &stUTC )
- && SystemTimeToTzSpecificLocalTime( NULL, &stUTC, &stLocal ))
- {
- result = System::TDateTime( (unsigned short)stLocal.wYear,
- (unsigned short)stLocal.wMonth, (unsigned short)stLocal.wDay )
- + System::TDateTime( (unsigned short)stLocal.wHour,
- (unsigned short)stLocal.wMinute, (unsigned short)stLocal.wSecond,
- (unsigned short)stLocal.wMilliseconds );
- }
- return result;
- }
- //---------------------------------------------------------------------------
- // Contrutor
- //
- Cert::Cert()
- {
- hStore = NULL;
- ctxCert = NULL;
- hPrvProv = NULL;
- dwKeySpec = AT_SIGNATURE;
- bFreeProv = FALSE;
- ctxChain = NULL;
- pfxData.pbData = NULL;
- pfxData.cbData = 0;
- }
- //---------------------------------------------------------------------------
- // Destrutor
- //
- Cert::~Cert()
- {
- freeStore( true );
- }
- //---------------------------------------------------------------------------
- // Define o último erro / contexto
- //
- void Cert::error( DWORD err, const System::WideString msg, const System::WideString ctx )
- {
- LPVOID lpMsgBuf = NULL;
- if (err != 0 && err != ERROR_CAN_NOT_COMPLETE
- && FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
- NULL, err, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL ) != 0)
- errMsg = (msg.IsEmpty()? System::WideString(): msg + ":\n") + (LPSTR)lpMsgBuf;
- else
- errMsg = msg;
- errCtx = ctx;
- if (lpMsgBuf != NULL)
- LocalFree( lpMsgBuf );
- }
- //---------------------------------------------------------------------------
- // Abre o repositório de certificados do sistema se nenhum aberto
- //
- bool Cert::openSystemStore()
- {
- if (hStore == NULL && (hStore = CertOpenStore(
- CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING, NULL,
- CERT_SYSTEM_STORE_CURRENT_USER|CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG,
- L"My" )) == NULL)
- {
- error( GetLastError(), "Falha abrindo repositório de certificados do sistema",
- __FUNC__ "() : CertOpenStore()" );
- return false;
- }
- return (hStore != NULL);
- }
- //---------------------------------------------------------------------------
- // Obtém a chave privada e cadeia de certificação do certificado atual
- //
- bool Cert::openPrivateKey()
- {
- if (ctxCert == NULL)
- {
- error( 0, "Falha obtendo chave privada: nenhum certificado aberto",
- __FUNC__ "()" );
- return false;
- }
- if (hPrvProv == NULL || ctxChain == NULL)
- {
- CERT_CHAIN_PARA chainPara;
- if (hPrvProv == NULL && !CryptAcquireCertificatePrivateKey( ctxCert,
- CRYPT_ACQUIRE_CACHE_FLAG, NULL, &hPrvProv, &dwKeySpec, &bFreeProv ))
- {
- error( GetLastError(), "Falha obtendo chave privada do certificado",
- __FUNC__ "() : CryptAcquireCertificatePrivateKey()" );
- return false;
- }
- memset( (void*)&chainPara, '\0', sizeof(CERT_CHAIN_PARA) );
- chainPara.cbSize = sizeof(CERT_CHAIN_PARA);
- if (ctxChain == NULL && !CertGetCertificateChain( NULL, ctxCert,
- NULL, NULL, &chainPara, 0, NULL, &ctxChain ))
- {
- error( GetLastError(), "Falha obtendo cadeia de certificação",
- __FUNC__ "() : CertGetCertificateChain()" );
- return false;
- }
- }
- return (hPrvProv != NULL && ctxChain != NULL);
- }
- //---------------------------------------------------------------------------
- // Libera todos os recursos e fecha o repositório de certificados
- //
- bool Cert::freeStore( bool closeStore )
- {
- bool result = true;
- // Contexto do certificado
- if (ctxCert != NULL)
- {
- if (ctxChain != NULL)
- {
- CertFreeCertificateChain( ctxChain );
- ctxChain = NULL;
- }
- if (hPrvProv != NULL && bFreeProv && !CryptReleaseContext( hPrvProv, 0 ))
- {
- error( GetLastError(), "Falha fechando provedor criptográfico",
- __FUNC__ "() : CryptReleaseContext()" );
- result = false;
- }
- hPrvProv = NULL;
- dwKeySpec = AT_SIGNATURE;
- bFreeProv = FALSE;
- CertFreeCertificateContext( ctxCert );
- ctxCert = NULL;
- certFile = System::WideString();
- certName = System::WideString();
- certType = System::WideString();
- name = System::WideString();
- doc = System::WideString();
- loc = System::WideString();
- email = System::WideString();
- validFrom = System::TDateTime();
- validTo = System::TDateTime();
- }
- // Repositório de certificados
- if (closeStore && hStore != NULL)
- {
- if (!CertCloseStore( hStore, 0 ))
- {
- error( GetLastError(), "Falha fechando repositório de certificados",
- __FUNC__ "() : CertCloseStore()" );
- result = false;
- }
- hStore = NULL;
- if (pfxData.pbData != NULL)
- {
- LocalFree( pfxData.pbData );
- pfxData.pbData = NULL;
- pfxData.cbData = 0;
- }
- }
- return result;
- }
- //---------------------------------------------------------------------------
- // Retorna e limpa a última mensagem de erro
- //
- System::WideString Cert::lastError()
- {
- System::WideString msg;
- msg = errMsg;
- if (!errCtx.IsEmpty())
- {
- if (!msg.IsEmpty())
- msg += "\nContexto: " + errCtx;
- else
- msg = "Falha executando " + errCtx;
- }
- errMsg = System::WideString();
- errCtx = System::WideString();
- return msg;
- }
- //---------------------------------------------------------------------------
- // Abre um repositório de certificados em arquivo
- //
- bool Cert::openFileStore( const System::WideString &fileName, const wchar_t *password )
- {
- // Fecha o repositório atualmente aberto
- if (!freeStore( true ))
- return false;
- if (pfxData.pbData != NULL)
- {
- LocalFree( pfxData.pbData );
- pfxData.pbData = NULL;
- pfxData.cbData = 0;
- }
- // Carrega o arquivo de entrada na memória
- if (!loadFile( fileName, &pfxData.pbData, &pfxData.cbData ))
- return false;
- // Verifica o arquivo PFX
- if (!PFXIsPFXBlob( &pfxData ))
- {
- error( 0, "Não é um arquivo PFX válido: " + fileName,
- __FUNC__ "() : PFXIsPFXBlob()" );
- LocalFree( pfxData.pbData );
- pfxData.pbData = NULL;
- pfxData.cbData = 0;
- return false;
- }
- if (!PFXVerifyPassword( &pfxData, password, 0 ))
- {
- error( 0, "Senha inválida para o arquivo PFX",
- __FUNC__ "() : PFXVerifyPassword()" );
- LocalFree( pfxData.pbData );
- pfxData.pbData = NULL;
- pfxData.cbData = 0;
- return false;
- }
- // Abre o arquivo PFX
- if ((hStore = PFXImportCertStore( &pfxData, password, 0 )) == NULL
- && password[0] != L'\0' && (hStore = PFXImportCertStore( &pfxData, NULL, 0 )) == NULL)
- {
- error( GetLastError(), "Falha abrindo arquivo de certificados",
- __FUNC__ "() : PFXImportCertStore()" );
- LocalFree( pfxData.pbData );
- pfxData.pbData = NULL;
- pfxData.cbData = 0;
- return false;
- }
- certFile = fileName;
- return true;
- }
- //---------------------------------------------------------------------------
- // Lista os certificados no repositório aberto ou do sistema
- //
- bool Cert::listCert( Classes::TStrings &lst )
- {
- int n = 0;
- PCCERT_CONTEXT ctx = NULL;
- wchar_t szName[MAX_PATH];
- szName[MAX_PATH-1] = '\0';
- if (!openSystemStore())
- return false;
- lst.Clear();
- while ((ctx = CertEnumCertificatesInStore( hStore, ctx )) != NULL)
- {
- ++n;
- if (n > 99)
- {
- lst.Add( "..." );
- break;
- }
- if (CertGetNameString( ctx, CERT_NAME_SIMPLE_DISPLAY_TYPE,
- 0, NULL, szName, MAX_PATH-1 ))
- lst.Add( System::WideString( szName ) );
- else
- {
- error( 0, "Falha obtendo nome do certificado",
- __FUNC__ "() : CertGetNameString()" );
- CertFreeCertificateContext( ctx );
- return false;
- }
- }
- if (ctx != NULL)
- CertFreeCertificateContext( ctx );
- return true;
- }
- //---------------------------------------------------------------------------
- // Abre um certificado no repositório aberto ou do sistema
- //
- bool Cert::openCert( const System::WideString &cert )
- {
- int n = 0;
- PCCERT_CONTEXT ctx = NULL;
- wchar_t szName[MAX_PATH], *ptr, *ep;
- szName[MAX_PATH-1] = '\0';
- // Fecha o contexto atualmente aberto
- if (!freeStore( false ))
- return false;
- // Abre o repositório de certificados do sistema se nenhum aberto
- if (!openSystemStore())
- return false;
- // Localiza um certificado que seja válido na data atual
- while ((ctx = CertFindCertificateInStore(
- hStore, X509_ASN_ENCODING, 0, (cert.IsEmpty()? CERT_FIND_ANY: CERT_FIND_SUBJECT_STR),
- (cert.IsEmpty()? NULL: cert.c_bstr()), ctx )) != NULL)
- {
- ++n;
- if (n > 99)
- break;
- validFrom = CertUtil_FileTimeToDateTime( &ctx->pCertInfo->NotBefore );
- validTo = CertUtil_FileTimeToDateTime( &ctx->pCertInfo->NotAfter );
- if (validFrom < TDateTime::CurrentDateTime() && validTo > TDateTime::CurrentDateTime())
- break;
- }
- // Nenhum certificado encontrado
- if (n == 0)
- {
- error( GetLastError(), "Falha localizando certificado",
- __FUNC__ "() : CertFindCertificateInStore()" );
- return false;
- }
- // Se nenhum certificado é válido na data atual, pega o primeiro
- if (ctx == NULL)
- {
- if ((ctxCert = CertFindCertificateInStore(
- hStore, X509_ASN_ENCODING, 0, (cert.IsEmpty()? CERT_FIND_ANY: CERT_FIND_SUBJECT_STR),
- (cert.IsEmpty()? NULL: cert.c_bstr()), NULL )) == NULL)
- {
- error( GetLastError(), "Falha localizando certificado",
- __FUNC__ "() : CertFindCertificateInStore()" );
- return false;
- }
- validFrom = CertUtil_FileTimeToDateTime( &ctxCert->pCertInfo->NotBefore );
- validTo = CertUtil_FileTimeToDateTime( &ctxCert->pCertInfo->NotAfter );
- }
- else
- ctxCert = ctx;
- // Dados restantes do certificado
- if (CertGetNameString( ctxCert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
- 0, NULL, szName, MAX_PATH-1 ))
- certName = System::WideString( szName );
- else
- {
- error( 0, "Falha obtendo nome do requerente do certificado",
- __FUNC__ "() : CertGetNameString()" );
- return false;
- }
- if (CertGetNameString( ctxCert, CERT_NAME_EMAIL_TYPE,
- 0, NULL, szName, MAX_PATH-1 ))
- email = System::WideString( szName );
- else
- email = System::WideString();
- // Dados do emissor do certificado
- if (CertGetNameString( ctxCert, CERT_NAME_SIMPLE_DISPLAY_TYPE,
- CERT_NAME_ISSUER_FLAG, NULL, szName, MAX_PATH-1 ))
- issuerName = System::WideString( szName );
- else
- {
- error( 0, "Falha obtendo nome do emissor do certificado",
- __FUNC__ "() : CertGetNameString()" );
- return false;
- }
- // Distinguished Name
- if (CertNameToStr( X509_ASN_ENCODING, &ctxCert->pCertInfo->Subject,
- CERT_X500_NAME_STR, szName, MAX_PATH-1 ) == 0)
- {
- error( 0, "Falha obtendo Distinguished Name do certificado",
- __FUNC__ "() : CertNameToStr()" );
- return false;
- }
- //C=BR,
- //S=<UF>,
- //L=<CIDADE>,
- //O=ICP-Brasil,
- //OU=Secretaria da Receita Federal do Brasil - RFB,
- //OU=<RFB e-*** **>,
- //[OU=<Domínio do certificado>]
- //OU=<Identificação da AR>,
- //CN=<Nome Empresarial><:><número de inscrição no CPF/CNPJ>
- // Tipo de certificado
- if ((ptr = wcsstr( szName, L"OU=" )) != NULL
- && (ptr = wcsstr( ptr+3, L"OU=" )) != NULL)
- {
- ptr += 3;
- if ((ep = wcsstr( ptr, L", " )) != NULL)
- *ep = L'\0';
- certType = System::WideString( ptr );
- if (ep != NULL)
- *ep = L',';
- }
- else
- certType = System::WideString();
- // Nome Empresarial/Pessoa Física e número de inscrição no CPF/CNPJ
- if ((ptr = wcsstr( szName, L"CN=" )) != NULL
- && (ep = wcschr( ptr, L':' )) != NULL)
- {
- ptr += 3;
- *ep = L'\0';
- name = System::WideString( ptr );
- *ep = L':';
- ptr = ep + 1;
- if ((ep = wcsstr( ptr, L", " )) != NULL)
- *ep = L'\0';
- doc = System::WideString( ptr );
- if (ep != NULL)
- *ep = L',';
- }
- else
- {
- name = System::WideString();
- doc = System::WideString();
- }
- // Localização
- if ((ptr = wcsstr( szName, L"L=" )) != NULL)
- {
- ptr += 2;
- if ((ep = wcsstr( ptr, L", " )) != NULL)
- *ep = L'\0';
- loc = System::WideString( ptr );
- if (ep != NULL)
- *ep = L',';
- if ((ptr = wcsstr( szName, L"S=" )) != NULL
- || (ptr = wcsstr( szName, L"ST=" )) != NULL)
- {
- if (ptr[1] == L'=')
- ptr += 2;
- else
- ptr += 3;
- if ((ep = wcsstr( ptr, L", " )) != NULL)
- *ep = L'\0';
- loc += System::WideString( L"-" );
- loc += System::WideString( ptr );
- if (ep != NULL)
- *ep = L',';
- }
- }
- else
- loc = System::WideString();
- return true;
- }
- //---------------------------------------------------------------------------
- // Carrega o arquivo na memória
- //
- bool Cert::loadFile( const System::WideString &fileName,
- BYTE **ppbData, DWORD *pcbData )
- {
- HANDLE hFile;
- DWORD br = 0;
- *ppbData = NULL;
- *pcbData = 0;
- if ((hFile = CreateFile( fileName.c_bstr(), GENERIC_READ, 0, NULL,
- OPEN_EXISTING, 0, NULL )) == INVALID_HANDLE_VALUE)
- {
- error( GetLastError(), "Falha abrindo o arquivo " + fileName,
- __FUNC__ "() : CreateFile()" );
- return false;
- }
- if ((*pcbData = GetFileSize( hFile, NULL )) == INVALID_FILE_SIZE)
- {
- error( GetLastError(), "Falha obtendo tamanho do arquivo " + fileName,
- __FUNC__ "() : GetFileSize()" );
- CloseHandle( hFile );
- return false;
- }
- else if (*pcbData == 0)
- {
- error( 0, "Arquivo de entrada vazio: " + fileName,
- __FUNC__ "()" );
- CloseHandle( hFile );
- return false;
- }
- if ((*ppbData = (PBYTE)LocalAlloc( LPTR, (SIZE_T)*pcbData )) == NULL)
- {
- DWORD err = GetLastError();
- error( (err == 0? ERROR_OUTOFMEMORY: err), "", __FUNC__ "() : LocalAlloc()" );
- CloseHandle( hFile );
- return false;
- }
- if (!ReadFile( hFile, *ppbData, *pcbData, &br, NULL ))
- {
- error( GetLastError(), "Falha lendo o arquivo " + fileName,
- __FUNC__ "() : ReadFile()" );
- CloseHandle( hFile );
- LocalFree( *ppbData );
- *ppbData = NULL;
- return false;
- }
- else if (br != *pcbData)
- {
- error( 0, "Falha lendo o arquivo " + fileName
- + ":\nO tamanho do arquivo difere dos bytes lidos",
- __FUNC__ "() : ReadFile()" );
- CloseHandle( hFile );
- LocalFree( *ppbData );
- *ppbData = NULL;
- return false;
- }
- CloseHandle( hFile );
- return true;
- }
- //---------------------------------------------------------------------------
- // Salva o conteúdo da memória em um arquivo
- //
- bool Cert::writeFile( const System::WideString &fileOut,
- BYTE *pbData, DWORD cbData )
- {
- HANDLE hFile;
- DWORD bw = 0;
- // Cria o arquivo de saída
- if ((hFile = CreateFile( fileOut.c_bstr(), GENERIC_WRITE, 0, NULL,
- CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL )) == INVALID_HANDLE_VALUE)
- {
- error( GetLastError(), "Falha criando o arquivo " + fileOut,
- __FUNC__ "() : CreateFile()" );
- return false;
- }
- // Grava o arquivo de saída
- if (!WriteFile( hFile, pbData, cbData, &bw, NULL ) || bw != cbData)
- {
- error( GetLastError(), "Falha gravando o arquivo " + fileOut,
- __FUNC__ "() : WriteFile()" );
- CloseHandle( hFile );
- return false;
- }
- CloseHandle( hFile );
- return true;
- }
- //---------------------------------------------------------------------------
- // Localiza e monta o caminho XPath de uma TAG e extrai sua propriedade Id
- //
- bool Cert::loadTagXPathId( const BYTE *pbData, const DWORD cbData,
- const System::WideString &tag, System::WideString &tag_xpath,
- System::WideString &tag_id )
- {
- System::WideString xpath[CERTUTIL_LEVEL_MAX];
- char t[CERTUTIL_TAG_SIZE];
- int i, j, level;
- level = 0;
- for (i = 0; i < (int)cbData; ++i)
- {
- // Início de uma marcação
- if (pbData[i] == '<')
- {
- // TAG inicial
- if (isalpha( pbData[++i] ) || pbData[i] == '_')
- {
- // Obtém o nome da TAG, incluindo o 'namespace'
- for (j = 0; i < (int)cbData && j < CERTUTIL_TAG_SIZE-1
- && (isalnum( pbData[i] ) || pbData[i] == '_' || pbData[i] == '-'
- || pbData[i] == '.' || pbData[i] == ':'); ++i, ++j)
- t[j] = pbData[i];
- t[j] = '\0';
- // Salva o caminho da TAG
- if (level < CERTUTIL_LEVEL_MAX)
- xpath[level++] = t;
- // Se for a TAG selecionada
- if (tag == t)
- {
- tag_xpath = "";
- for (j = 0; j < level; ++j)
- tag_xpath += "/" + xpath[j];
- while (i < (int)cbData && pbData[i] != '>')
- {
- // Atributo da TAG
- if (isalpha( pbData[i] ) || pbData[i] == '_')
- {
- // Identificação da TAG
- if (strnicmp( &pbData[i], "Id=\"", 4 ) == 0)
- {
- i += 4;
- for (j = 0; i < (int)cbData && j < CERTUTIL_TAG_SIZE-1
- && pbData[i] != '\"' && pbData[i] != '>'; ++i, ++j)
- t[j] = pbData[i];
- t[j] = '\0';
- tag_id = System::WideString("#") + t;
- return true;
- }
- // Outros atributos
- else
- {
- while (i < (int)cbData && (isalnum( pbData[i] ) || pbData[i] == '_'
- || pbData[i] == '-' || pbData[i] == '.' || pbData[i] == ':'))
- ++i;
- }
- }
- // Cadeia de caracteres
- else if (pbData[i] == '\"')
- {
- do
- ++i;
- while (i < (int)cbData && pbData[i] != '\"' && pbData[i] != '>');
- if (pbData[i] != '>')
- ++i;
- }
- else
- ++i;
- }
- // TAG sem Id
- tag_id = "";
- return true;
- }
- // Outras TAGs
- else
- {
- while (i < (int)cbData && pbData[i] != '>')
- ++i;
- }
- }
- // TAG final
- else if (pbData[i] == '/')
- {
- if (isalpha( pbData[++i] ) || pbData[i] == '_')
- {
- for (j = 0; i < (int)cbData && j < CERTUTIL_TAG_SIZE-1
- && (isalnum( pbData[i] ) || pbData[i] == '_' || pbData[i] == '-'
- || pbData[i] == '.' || pbData[i] == ':'); ++i, ++j)
- t[j] = pbData[i];
- t[j] = '\0';
- for (j = level-1; j >= 0 && xpath[j] != t; --j)
- ;
- if (j >= 0)
- level = j;
- }
- while (i < (int)cbData && pbData[i] != '>')
- ++i;
- }
- // Outros tipos de marcação
- else
- {
- while (i < (int)cbData && pbData[i] != '>')
- ++i;
- }
- }
- }
- return false;
- }
- //---------------------------------------------------------------------------
- // Assina um arquivo XML (de um arquivo para outro)
- //
- bool Cert::signXMLFile( const System::WideString &fileOut,
- const System::WideString &fileIn, const System::WideString &tag )
- {
- BYTE *pbData;
- DWORD cbData;
- // Carrega o arquivo de entrada na memória
- if (!loadFile( fileIn, &pbData, &cbData ))
- return false;
- // Assina o conteúdo do arquivo
- if (!signXMLBuffer( &pbData, &cbData, tag, true ))
- {
- LocalFree( pbData );
- return false;
- }
- // Grava o arquivo de saída
- if (!writeFile( fileOut, pbData, cbData ))
- {
- LocalFree( pbData );
- return false;
- }
- LocalFree( pbData );
- return true;
- }
- //---------------------------------------------------------------------------
- // Assina um arquivo XML (da memória para um arquivo)
- //
- bool Cert::signXMLBufferToFile( const System::WideString &fileOut,
- BYTE *pbData, DWORD cbData, const System::WideString &tag )
- {
- // Assina o conteúdo da memória
- if (!signXMLBuffer( &pbData, &cbData, tag, false ))
- return false;
- // Grava o arquivo de saída
- if (!writeFile( fileOut, pbData, cbData ))
- {
- LocalFree( pbData );
- return false;
- }
- LocalFree( pbData );
- return true;
- }
- //---------------------------------------------------------------------------
- // Assina um arquivo XML (num buffer de memória)
- //
- bool Cert::signXMLBuffer( BYTE **ppbData, DWORD *pcbData,
- const System::WideString &tag, bool freeData )
- {
- HRESULT hr;
- HCRYPTXML hSig = NULL;
- HCRYPTXML hRef = NULL;
- CRYPT_XML_ALGORITHM xmlAlg_CanonicalizationMethod = {
- sizeof(CRYPT_XML_ALGORITHM),
- wszURI_CANONICALIZATION_C14N,
- CRYPT_XML_CHARSET_AUTO,
- 0,
- NULL
- };
- CRYPT_XML_ALGORITHM xmlAlg_DigestMethod = {
- sizeof( CRYPT_XML_ALGORITHM ),
- wszURI_XMLNS_DIGSIG_SHA1,
- CRYPT_XML_CHARSET_AUTO,
- 0,
- NULL
- };
- CRYPT_XML_ALGORITHM xmlAlg_SignatureMethod = {
- sizeof( CRYPT_XML_ALGORITHM ),
- wszURI_XMLNS_DIGSIG_RSA_SHA1,
- CRYPT_XML_CHARSET_AUTO,
- 0,
- NULL
- };
- ULONG trans_cnt = 2;
- CRYPT_XML_ALGORITHM trans[] = {
- {
- sizeof( CRYPT_XML_ALGORITHM ),
- wszURI_XMLNS_TRANSFORM_ENVELOPED,
- CRYPT_XML_CHARSET_AUTO,
- 0,
- NULL
- },
- {
- sizeof(CRYPT_XML_ALGORITHM),
- wszURI_CANONICALIZATION_C14N,
- CRYPT_XML_CHARSET_AUTO,
- 0,
- NULL
- }
- };
- CRYPT_XML_BLOB encoded = { CRYPT_XML_CHARSET_AUTO, 0, NULL };
- ULONG loc_prop_cnt = 0;
- //DWORD out_len = 76;
- CRYPT_XML_PROPERTY loc_prop[] = {
- {
- CRYPT_XML_PROPERTY_SIGNATURE_LOCATION,
- NULL,
- sizeof(LPCWSTR)
- }/*,
- {
- CRYPT_XML_PROPERTY_HMAC_OUTPUT_LENGTH,
- NULL,
- sizeof(DWORD)
- }*/
- };
- BOOL enc_decl = TRUE;
- ULONG enc_prop_cnt = 0;
- CRYPT_XML_PROPERTY enc_prop[] = {
- {
- CRYPT_XML_PROPERTY_DOC_DECLARATION,
- NULL,
- sizeof(BOOL)
- }
- };
- ULONG chain_cnt;
- //CERT_BLOB chain[CERTUTIL_CHAIN_MAX];
- CERT_BLOB chain[1];
- CRYPT_XML_KEYINFO_PARAM keyInfo;
- CertUtil_Buffer buffer;
- System::WideString tag_xpath, tag_id;
- LPCWSTR wszLoc, wszUri;
- wchar_t tag_loc[CERTUTIL_TAG_SIZE];
- wchar_t tag_ref[CERTUTIL_TAG_SIZE];
- enc_prop[0].pvValue = &enc_decl;
- enc_prop_cnt = 1;
- // Obtém a chave privada do certificado atualmente aberto
- if (!openPrivateKey())
- return false;
- // Localiza e monta o caminho da TAG e extrai a propriedade Id
- if (!loadTagXPathId( *ppbData, *pcbData, tag, tag_xpath, tag_id ))
- {
- error( 0, "Não foi localizada a TAG " + tag,
- __FUNC__ "() : loadTagXPathId()" );
- return false;
- }
- else if (tag_id.IsEmpty())
- {
- error( 0, "Não foi localizada o atributo Id da TAG " + tag,
- __FUNC__ "() : loadTagXPathId()" );
- return false;
- }
- wcscpy( tag_loc, tag_xpath.c_bstr() );
- wcscpy( tag_ref, tag_id.c_bstr() );
- wszLoc = tag_loc;
- wszUri = tag_ref;
- loc_prop[0].pvValue = &wszLoc;
- //loc_prop[1].pvValue = &out_len;
- loc_prop_cnt = 1;
- // Inicializa a assinatura do arquivo XML
- encoded.pbData = *ppbData;
- encoded.cbData = *pcbData;
- if ((hr = CryptXmlOpenToEncode( NULL, 0, L"", loc_prop, loc_prop_cnt, &encoded, &hSig )) != S_OK)
- {
- error( CertUtil_Win32FromHResult(hr), "Falha criando assinatura XML",
- __FUNC__ "() : CryptXmlOpenToEncode()" );
- return false;
- }
- // Cria a referência
- if ((hr = CryptXmlCreateReference( hSig, 0, NULL, wszUri, NULL,
- &xmlAlg_DigestMethod, trans_cnt, trans, &hRef )) != S_OK)
- {
- error( CertUtil_Win32FromHResult(hr), "Falha criando referência da assinatura XML",
- __FUNC__ "() : CryptXmlCreateReference()" );
- CryptXmlClose( hSig );
- return false;
- }
- // Monta a cadeia de certificados
- //memset( (void*)chain, '\0', sizeof(CERT_BLOB)*CERTUTIL_CHAIN_MAX );
- memset( (void*)chain, '\0', sizeof(CERT_BLOB) );
- memset( (void*)&keyInfo, '\0', sizeof(CRYPT_XML_KEYINFO_PARAM) );
- chain[0].pbData = ctxChain->rgpChain[0]->rgpElement[0]->pCertContext->pbCertEncoded;
- chain[0].cbData = ctxChain->rgpChain[0]->rgpElement[0]->pCertContext->cbCertEncoded;
- chain_cnt = 1;
- keyInfo.cCertificate = chain_cnt;
- keyInfo.rgCertificate = chain;
- // Gera a assinatura digital
- if ((hr = CryptXmlSign( hSig, hPrvProv, dwKeySpec, 0,
- CRYPT_XML_KEYINFO_SPEC_PARAM, &keyInfo,
- &xmlAlg_SignatureMethod, &xmlAlg_CanonicalizationMethod )) != S_OK)
- {
- error( CertUtil_Win32FromHResult(hr), "Falha gerando assinatura XML",
- __FUNC__ "() : CryptXmlSign()" );
- CryptXmlClose( hSig );
- return false;
- }
- // Cria o buffer de dados
- if ((buffer.pbData = (PBYTE)LocalAlloc( LPTR, (SIZE_T)(*pcbData+CERTUTIL_SIGN_SIZE) )) == NULL)
- {
- DWORD err = GetLastError();
- error( (err == 0? ERROR_OUTOFMEMORY: err), "", __FUNC__ "() : LocalAlloc()" );
- CryptXmlClose( hSig );
- return false;
- }
- buffer.cbData = 0;
- buffer.cbMaxData = (ULONG)(*pcbData+CERTUTIL_SIGN_SIZE);
- // Grava o arquivo XML com a assinatura no buffer de dados
- if ((hr = CryptXmlEncode( hSig, CRYPT_XML_CHARSET_UTF8,
- enc_prop, enc_prop_cnt, (void*)&buffer, CertUtil_writeXmlToBuffer )) != S_OK)
- {
- error( CertUtil_Win32FromHResult(hr), "Falha codificando arquivo XML assinado",
- __FUNC__ "() : CryptXmlEncode()" );
- LocalFree( buffer.pbData );
- CryptXmlClose( hSig );
- return false;
- }
- CryptXmlClose( hSig );
- // Corrige os dados do buffer
- // a biblioteca CryptXML coloca o elemento <Signature>
- // antes da TAG de fechamento </infNFe> e não depois
- if (strncmp( buffer.pbData, "<?xml", 5 ) == 0)
- {
- const char *signt = "<Signature";
- char endt[CERTUTIL_TAG_SIZE];
- char *p, *q;
- int n;
- strcpy( endt, System::AnsiString("</"+tag+">").c_str() );
- n = strlen( endt );
- p = strstr( (char*)buffer.pbData, endt );
- q = strstr( (char*)buffer.pbData, signt );
- if (p != NULL && q != NULL && p > q)
- {
- memmove( q+n, q, p-q );
- memcpy( q, endt, n );
- }
- }
- // Libera a memória originalmente apontada por *ppbData, se necessário
- if (freeData)
- LocalFree( *ppbData );
- // Retorna o conteúdo assinado
- *ppbData = buffer.pbData;
- *pcbData = buffer.cbData;
- return true;
- }
- //---------------------------------------------------------------------------
- // Verifica se um arquivo XML tem assinatura
- //
- bool Cert::signedXMLFile( const System::WideString &fileName )
- {
- BYTE *pbData;
- DWORD cbData;
- // Carrega o arquivo na memória
- if (!loadFile( fileName, &pbData, &cbData ))
- return false;
- // Verifica a(s) assinatura(s) do arquivo XML
- if (!signedXMLBuffer( pbData, cbData ))
- {
- LocalFree( pbData );
- return false;
- }
- LocalFree( pbData );
- return true;
- }
- //---------------------------------------------------------------------------
- // Verifica a assinatura de um arquivo XML
- //
- bool Cert::verifyXMLFile( const System::WideString &fileName )
- {
- BYTE *pbData;
- DWORD cbData;
- // Carrega o arquivo na memória
- if (!loadFile( fileName, &pbData, &cbData ))
- return false;
- // Verifica a(s) assinatura(s) do arquivo XML
- if (!verifyXMLBuffer( pbData, cbData ))
- {
- LocalFree( pbData );
- return false;
- }
- LocalFree( pbData );
- return true;
- }
- //---------------------------------------------------------------------------
- // Verifica se uma cadeia XML tem assinatura
- //
- bool Cert::signedXMLBuffer( BYTE *pbData, DWORD cbData )
- {
- HRESULT hr;
- HCRYPTXML hDoc = NULL;
- const CRYPT_XML_DOC_CTXT *pDoc = NULL;
- CRYPT_XML_BLOB encoded = { CRYPT_XML_CHARSET_AUTO, 0, NULL };
- encoded.pbData = pbData;
- encoded.cbData = cbData;
- // Carrega a(s) assinatura(s) da cadeia XML
- if ((hr = CryptXmlOpenToDecode( NULL, 0, NULL, 0, &encoded, &hDoc )) != S_OK)
- {
- error( CertUtil_Win32FromHResult(hr), "Falha verificando arquivo XML",
- __FUNC__ "() : CryptXmlOpenToDecode()" );
- return false;
- }
- if ((hr = CryptXmlGetDocContext( hDoc, &pDoc )) != S_OK)
- {
- error( CertUtil_Win32FromHResult(hr), "Falha verificando arquivo XML",
- __FUNC__ "() : CryptXmlGetDocContext()" );
- CryptXmlClose( hDoc );
- return false;
- }
- if (pDoc->cSignature > 0)
- hr = S_OK;
- else
- hr = S_FALSE;
- CryptXmlClose( hDoc );
- return (hr == S_OK);
- }
- //---------------------------------------------------------------------------
- // Verifica a assinatura de uma cadeia XML
- //
- bool Cert::verifyXMLBuffer( BYTE *pbData, DWORD cbData )
- {
- HRESULT hr;
- HCRYPTXML hDoc = NULL;
- const CRYPT_XML_DOC_CTXT *pDoc = NULL;
- const CRYPT_XML_SIGNATURE *pSig = NULL;
- const CRYPT_XML_REFERENCE *pRef = NULL;
- BCRYPT_KEY_HANDLE hKey = NULL;
- PCCERT_CONTEXT pCert = NULL;
- CRYPT_XML_BLOB encoded = { CRYPT_XML_CHARSET_AUTO, 0, NULL };
- CRYPT_XML_STATUS status;
- DWORD i, j, k;
- encoded.pbData = pbData;
- encoded.cbData = cbData;
- // Carrega a(s) assinatura(s) da cadeia XML
- if ((hr = CryptXmlOpenToDecode( NULL, 0, NULL, 0, &encoded, &hDoc )) != S_OK)
- {
- error( CertUtil_Win32FromHResult(hr), "Falha verificando arquivo XML",
- __FUNC__ "() : CryptXmlOpenToDecode()" );
- return false;
- }
- if ((hr = CryptXmlGetDocContext( hDoc, &pDoc )) != S_OK)
- {
- error( CertUtil_Win32FromHResult(hr), "Falha verificando arquivo XML",
- __FUNC__ "() : CryptXmlGetDocContext()" );
- CryptXmlClose( hDoc );
- return false;
- }
- if (pDoc->cSignature < 1)
- {
- error( 0, "O arquivo XML não tem assinatura", __FUNC__ "()" );
- CryptXmlClose( hDoc );
- return false;
- }
- // Verifica a(s) assinatura(s)
- for (i = 0; hr == S_OK && i < pDoc->cSignature; ++i)
- {
- // Localiza o certificado da assinatura
- for (j = 0; j < pDoc->rgpSignature[i]->pKeyInfo->cKeyInfo && hKey == NULL; ++j)
- {
- if (pDoc->rgpSignature[i]->pKeyInfo->rgKeyInfo[j].dwType == CRYPT_XML_KEYINFO_TYPE_X509DATA)
- {
- for (k = 0; k < pDoc->rgpSignature[i]->pKeyInfo->rgKeyInfo[j].X509Data.cX509Data; ++k)
- {
- CRYPT_XML_X509DATA_ITEM *pX
- = &pDoc->rgpSignature[i]->pKeyInfo->rgKeyInfo[j].X509Data.rgX509Data[k];
- if (pX->dwType == CRYPT_XML_X509DATA_TYPE_CERTIFICATE)
- {
- // Cria o contexto do certificado e importa a chave pública
- if ((pCert = CertCreateCertificateContext( X509_ASN_ENCODING,
- pX->Certificate.pbData, pX->Certificate.cbData )) != NULL)
- {
- if (CryptImportPublicKeyInfoEx2(
- X509_ASN_ENCODING, &pCert->pCertInfo->SubjectPublicKeyInfo,
- CRYPT_OID_INFO_PUBKEY_SIGN_KEY_FLAG, NULL, &hKey ))
- {
- hr = S_OK;
- break;
- }
- hr = HRESULT_FROM_WIN32( GetLastError() );
- if (hKey != NULL)
- {
- //BCryptDestroyKey( hKey ); // Requer Bcrypt.lib
- hKey = NULL;
- }
- CertFreeCertificateContext( pCert );
- pCert = NULL;
- }
- }
- else
- hr = HRESULT_FROM_WIN32( GetLastError() );
- }
- }
- }
- if (hKey == NULL)
- {
- error( CertUtil_Win32FromHResult(hr),
- "Não foi possível localizar a chave pública no arquivo XML", __FUNC__ "()" );
- if (hr == S_OK)
- hr = S_FALSE;
- break;
- }
- // TODO: Verificar cadeia de certificados obtido via CertGetCertificateChain()
- // Valida a assinatura
- hr = CryptXmlVerifySignature( pDoc->rgpSignature[i]->hSignature, hKey, 0 );
- // Verifica a(s) referência(s)
- if (hr == S_OK)
- {
- hr = CryptXmlGetSignature( pDoc->rgpSignature[i]->hSignature, &pSig );
- for (j = 0; hr == S_OK && j < pSig->SignedInfo.cReference; ++j)
- {
- if ((hr = CryptXmlGetReference( pSig->SignedInfo.rgpReference[j]->hReference, &pRef)) != S_OK)
- break;
- memset( (void*)&status, '\0', sizeof(CRYPT_XML_STATUS) );
- if ((hr = CryptXmlGetStatus( pSig->SignedInfo.rgpReference[j]->hReference, &status )) != S_OK)
- break;
- if ((status.dwErrorStatus & CRYPT_XML_STATUS_ERROR_NOT_RESOLVED) != 0)
- {
- // TODO: Resolver referências externas ou não resolvidas
- // via HrSampleResolveExternalXmlReference, CryptXmlDigestReference e CryptXmlGetStatus
- hr = CRYPT_XML_E_UNRESOLVED_REFERENCE;
- break;
- }
- if ((status.dwErrorStatus & CRYPT_XML_STATUS_ERROR_DIGEST_INVALID) != 0)
- {
- hr = CRYPT_XML_E_INVALID_DIGEST;
- break;
- }
- }
- }
- // Verifica o resultado da assinatura
- if (hr == S_OK)
- {
- if ((hr = CryptXmlGetStatus( pDoc->rgpSignature[i]->hSignature, &status )) == S_OK)
- {
- if ((status.dwErrorStatus & CRYPT_XML_STATUS_ERROR_DIGEST_INVALID) != 0)
- hr = CRYPT_XML_E_INVALID_DIGEST;
- if ((status.dwErrorStatus & CRYPT_XML_STATUS_ERROR_NOT_RESOLVED) != 0)
- hr = CRYPT_XML_E_UNRESOLVED_REFERENCE;
- }
- }
- if (hKey != NULL)
- {
- //BCryptDestroyKey( hKey ); // Requer Bcrypt.lib
- hKey = NULL;
- }
- if (pCert != NULL)
- {
- CertFreeCertificateContext( pCert );
- pCert = NULL;
- }
- }
- if (hr != S_OK)
- {
- System::WideString ctx;
- if (hr == CRYPT_XML_E_INVALID_SIGNATURE)
- ctx = ":\nAssinatura inválida";
- else if (hr == CRYPT_XML_E_VERIFY_FAILED)
- ctx = ":\nAssinatura não confere";
- else if (hr == CRYPT_XML_E_INVALID_DIGEST)
- ctx = ":\nResumo (digest hash) não confere";
- else if (hr == CRYPT_XML_E_UNRESOLVED_REFERENCE)
- ctx = ":\nReferência não resolvida";
- else if ((hr & CRYPT_XML_E_BASE) == CRYPT_XML_E_BASE)
- ctx = ":\nErro do CryptXML nº " + IntToStr( (int)(hr & ~CRYPT_XML_E_BASE) );
- error( CertUtil_Win32FromHResult(hr), "Assinatura não validada" + ctx, __FUNC__ "()" );
- }
- CryptXmlClose( hDoc );
- return (hr == S_OK);
- }
- //---------------------------------------------------------------------------
- // Nome do arquivo de certificados atual
- //
- System::WideString Cert::getFileName()
- {
- return certFile;
- }
- //---------------------------------------------------------------------------
- // Nome do certificado atual
- //
- System::WideString Cert::getCertName()
- {
- return certName;
- }
- //---------------------------------------------------------------------------
- // Tipo de certificado
- //
- System::WideString Cert::getCertType()
- {
- return certType;
- }
- //---------------------------------------------------------------------------
- // Nome Empresarial/Pessoa Física
- //
- System::WideString Cert::getName()
- {
- return name;
- }
- //---------------------------------------------------------------------------
- // Número de inscrição no CPF/CNPJ
- //
- System::WideString Cert::getDoc()
- {
- return doc;
- }
- //---------------------------------------------------------------------------
- // Localização
- //
- System::WideString Cert::getLoc()
- {
- return loc;
- }
- //---------------------------------------------------------------------------
- // E-mail do requerente
- //
- System::WideString Cert::getEmail()
- {
- return email;
- }
- //---------------------------------------------------------------------------
- // Data do início da validade
- //
- System::TDateTime Cert::getValidFrom()
- {
- return validFrom;
- }
- //---------------------------------------------------------------------------
- // Data do fim da validade
- //
- System::TDateTime Cert::getValidTo()
- {
- return validTo;
- }
- //---------------------------------------------------------------------------
- // Nome do emissor certificado
- //
- System::WideString Cert::getIssuerName()
- {
- return issuerName;
- }
- //---------------------------------------------------------------------------
Advertisement
Add Comment
Please, Sign In to add comment