CertFindCertificateInStore fails to load self-signed certificates generated on different machine - c++

I'm trying to load a self-signed certificate generated on a different host and imported to my machine. Cert has been imported and shows up in mmc correctly. But CertFindCertificateInStore fails to load, when searched through SHA1 thumbprint.
Here's code:
const LPWSTR certThumbprint = L"2af92932d0164f52b20b1ccfdf0e1e4d525fbc08";
CryptStringToBinary(certThumbprint, SHA1_HASH_STRING_LENGTH, CRYPT_STRING_HEXRAW, NULL, &dwHashDataLength, NULL,NULL);
pHashData = new BYTE[dwHashDataLength];
CryptStringToBinary(certThumbprint,SHA1_HASH_STRING_LENGTH,CRYPT_STRING_HEXRAW,pHashData,&dwHashDataLength,NULL, NULL);
hashBlob.cbData = dwHashDataLength;
hashBlob.pbData = pHashData;
if ( !(pCertContext = CertFindCertificateInStore(
hSystemCertStore,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
0,
CERT_FIND_SHA1_HASH,
&hashBlob,
NULL)))
{
printf("\n finding cert in system store failed: %d \n", GetLastError());
exit(-1);
}

Related

How to check the revocation status of a x509 certificate in c++ with wincrypt.h?

I'm trying to check the revocation state of a X509 certificate in a c++ program with the use of wincrypt.h. Sadly I'm not able to find a comprehensive example. In c# the code would be the following:
X509Certificate2 certificate = new X509Certificate2();
//Create X509Certificate2 object from .cer file.
byte[] rawData = ReadFile(#"C:\Users\z002m76a\Desktop\cert.pem");
certificate.Import(rawData);
X509Chain ch = new X509Chain();
ch.ChainPolicy.RevocationMode = X509RevocationMode.Online;
ch.Build(certificate);
Console.WriteLine("Chain revocation flag: {0}", ch.ChainPolicy.RevocationFlag);
Based on the excellent comment by #crypt32 I created the following c++ program. Probably it is not the most beautiful c++ code in the world (mine c++ is pretty rusty) but it seems so work
// ValidationCheckCPP.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
#include <windows.h>
#include <wincrypt.h>
#include "ValidationCheckCPP.h"
int main()
{
char keyFile[] = "C:\\Users\\z002m76a\\Desktop\\2698514447.crt";
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = FALSE;
HANDLE hKeyFile;
hKeyFile = CreateFile(keyFile, GENERIC_READ, FILE_SHARE_READ, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hKeyFile) {
BYTE lp[65536];
DWORD flags;
DWORD bytes;
if (ReadFile(hKeyFile, lp, GetFileSize(hKeyFile, NULL), &bytes, NULL) && bytes > 0) {
BYTE* p;
p = lp + bytes;
if (CryptStringToBinary((char*)lp, p - lp, CRYPT_STRING_BASE64_ANY, p, &bytes, NULL, &flags) && bytes > 0) {
PCCERT_CONTEXT pCertContext;
pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING, p, bytes);
if (pCertContext)
{
printf("Certificate loaded");
CERT_ENHKEY_USAGE EnhkeyUsage;
EnhkeyUsage.cUsageIdentifier = 0;
EnhkeyUsage.rgpszUsageIdentifier = NULL;
CERT_USAGE_MATCH CertUsage;
CertUsage.dwType = USAGE_MATCH_TYPE_AND;
CertUsage.Usage = EnhkeyUsage;
CERT_CHAIN_PARA ChainPara;
ChainPara.cbSize = sizeof(CERT_CHAIN_PARA);
ChainPara.RequestedUsage = CertUsage;
PCCERT_CHAIN_CONTEXT pChainContext;
if (CertGetCertificateChain(
NULL, // use the default chain engine
pCertContext, // pointer to the end certificate
NULL, // use the default time
NULL, // search no additional stores
&ChainPara,
CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
NULL, // currently reserved
&pChainContext)) // return a pointer to the chain created
{
printf("Chain built with %d certificates.\n", pChainContext->rgpChain[0]->cElement);
CERT_CHAIN_POLICY_PARA ChainPolicy = { 0 };
ChainPolicy.cbSize = sizeof(ChainPolicy);
CERT_CHAIN_POLICY_STATUS PolicyStatus = { 0 };
PolicyStatus.cbSize = sizeof(PolicyStatus);
CertVerifyCertificateChainPolicy(
CERT_CHAIN_POLICY_BASE,
pChainContext, // pointer to the chain
&ChainPolicy,
&PolicyStatus);
CERT_REVOCATION_STATUS revocationStatus;
revocationStatus.cbSize = sizeof(CERT_REVOCATION_STATUS);
PCERT_CONTEXT* pCerts = new PCERT_CONTEXT[pChainContext->cChain];
for (DWORD i = 0; i < pChainContext->cChain; i++) {
pCerts[i] = (PCERT_CONTEXT)(pChainContext->rgpChain[i]->rgpElement[0]->pCertContext);
}
// CERT_VERIFY_REV_CHAIN_FLAG
// Verification of the chain of certificates is done assuming each certificate except the first certificate is the issuer of the certificate that precedes it.If dwRevType is not CERT_CONTEXT_REVOCATION_TYPE, no assumptions are made about the order of the contexts.
// CERT_VERIFY_CACHE_ONLY_BASED_REVOCATION
// Prevents the revocation handler from accessing any network - based resources for revocation checking.
// CERT_VERIFY_REV_ACCUMULATIVE_TIMEOUT_FLAG
// When set, dwUrlRetrievalTimeout is the cumulative time - out across all URL wire retrievals.
// CERT_VERIFY_REV_SERVER_OCSP_FLAG
// When set, this function only uses online certificate status protocol(OCSP) for revocation checking.If the certificate does not have any OCSP AIA URLs, the dwError member of the pRevStatus parameter is set to CRYPT_E_NOT_IN_REVOCATION_DATABASE.
DWORD revocationCheckType = CERT_VERIFY_REV_CHAIN_FLAG;
BOOL bRc = CertVerifyRevocation(
X509_ASN_ENCODING,
CERT_CONTEXT_REVOCATION_TYPE,
pChainContext->cChain,
(void**)pCerts,
revocationCheckType,
NULL,
&revocationStatus);
printf("The size of the chain context is %d. \n", pChainContext->cbSize);
printf("%d simple chains found.\n", pChainContext->cChain);
printf("\nError status for the chain:\n");
switch (pChainContext->TrustStatus.dwErrorStatus)
{
case CERT_TRUST_NO_ERROR:
printf("No error found for this certificate or chain.\n");
break;
case CERT_TRUST_IS_NOT_TIME_VALID:
printf("This certificate or one of the certificates in the certificate chain is not time-valid.\n");
break;
case CERT_TRUST_IS_REVOKED:
printf("Trust for this certificate or one of the certificates in the certificate chain has been revoked.\n");
break;
case CERT_TRUST_IS_NOT_SIGNATURE_VALID:
printf("The certificate or one of the certificates in the certificate chain does not have a valid signature.\n");
break;
case CERT_TRUST_IS_NOT_VALID_FOR_USAGE:
printf("The certificate or certificate chain is not valid in its proposed usage.\n");
break;
case CERT_TRUST_IS_UNTRUSTED_ROOT:
printf("The certificate or certificate chain is based on an untrusted root.\n");
break;
case CERT_TRUST_REVOCATION_STATUS_UNKNOWN:
printf("The revocation status of the certificate or one of the certificates in the certificate chain is unknown.\n");
break;
case CERT_TRUST_IS_CYCLIC:
printf("One of the certificates in the chain was issued by a certification authority that the original certificate had certified.\n");
break;
case CERT_TRUST_IS_PARTIAL_CHAIN:
printf("The certificate chain is not complete.\n");
break;
case CERT_TRUST_CTL_IS_NOT_TIME_VALID:
printf("A CTL used to create this chain was not time-valid.\n");
break;
case CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID:
printf("A CTL used to create this chain did not have a valid signature.\n");
break;
case CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE:
printf("A CTL used to create this chain is not valid for this usage.\n");
}
printf("Info status for the chain:\n");
switch (pChainContext->TrustStatus.dwInfoStatus)
{
case 0:
printf("No information status reported.\n");
break;
case CERT_TRUST_HAS_EXACT_MATCH_ISSUER:
printf("An exact match issuer certificate has been found for this certificate.\n");
break;
case CERT_TRUST_HAS_KEY_MATCH_ISSUER:
printf("A key match issuer certificate has been found for this certificate.\n");
break;
case CERT_TRUST_HAS_NAME_MATCH_ISSUER:
printf("A name match issuer certificate has been found for this certificate.\n");
break;
case CERT_TRUST_IS_SELF_SIGNED:
printf("This certificate is self-signed.\n");
break;
case CERT_TRUST_IS_COMPLEX_CHAIN:
printf("The certificate chain created is a complex chain.\n");
break;
} // end switch
}
CertFreeCertificateContext(pCertContext);
}
else {
printf("Could not convert certificate to internal form\n");
}
}
else {
printf("Failed to convert from PEM\n");
}
}
else {
printf("Failed to read key file: %s\n", keyFile);
}
}
else {
printf("Failed to open key file: %s\n", keyFile);
}
CloseHandle(hKeyFile);
return 0;
}
In C++, you use CertGetCertificateChain function. Along with call result, the function returns a a pointer to CERT_CHAIN_CONTEXT (via ppChainContext member). This CERT_CHAIN_CONTEXT structure stores a pointer to a CERT_SIMPLE_CHAIN structure (rgpChain member) which represents an array of chain elements (this is what X509Chain.ChainElements represents in .NET). Essentially, you need to check the very first element in rgpChain, which is a pointer to a CERT_SIMPLE_CHAIN structure. And examine TrustStatus member for revocation status flags (two flags).
The example provided by #Rufus Buschart is quite lovely. If checking OCSP in his example, simply change revocationCheckType to CERT_VERIFY_REV_SERVER_OCSP_FLAG.
Here I'd like to provide an example using another api CertOpenServerOcspResponse()
// after construct the PCCERT_CHAIN_CONTEXT ppChainContext, which can be the same as #Rufus
// If async operation is required, change second parameter 0 to 1 (available since Win8.1, but not announced on official documentations)
HCERT_SERVER_OCSP_RESPONSE hServerOcspResponse = CertOpenServerOcspResponse(ppChainContext, 0, nullptr);
PCCERT_SERVER_OCSP_RESPONSE_CONTEXT recvdResponseCtx = CertGetServerOcspResponseContext(hServerOcspResponse, 0, nullptr);
if (recvdResponseCtx == nullptr)
{
printf("Receive OCSP server response failed\n");
showStrError("CertGetServerOcspResponseContext"); // show the description about GetLastError()
return 1;
}
POCSP_RESPONSE_INFO pocspResponseInfo = nullptr;
DWORD ocspResponseSize = 0; // X509_SEQUENCE_OF_ANY
ret = CryptDecodeObjectEx(PKCS_7_ASN_ENCODING, OCSP_RESPONSE, recvdResponseCtx->pbEncodedOcspResponse, recvdResponseCtx->cbEncodedOcspResponse, CRYPT_DECODE_ALLOC_FLAG, nullptr, &pocspResponseInfo, &ocspResponseSize);
if (!ret)
{
printf("Error decode ocsp response info from CERT_SERVER_OCSP_RESPONSE_CONTEXT.\n");
showStrError("DecodeOcspServerResponse");
return 1;
}
if (pocspResponseInfo->dwStatus != OCSP_SUCCESSFUL_RESPONSE)
{
printf("Unsuccessfully ocsp response. The status value is %d, which means %s\n", pocspResponseInfo->dwStatus, "OCSP_MALFORMED_REQUEST_RESPONSE if it is 1");
return 1;
}
if (strcmp(szOID_PKIX_OCSP_BASIC_SIGNED_RESPONSE, pocspResponseInfo->pszObjId))
{
printf("Ocsp response info is %s\n, but it should be %s\n", pocspResponseInfo->pszObjId, szOID_PKIX_OCSP_BASIC_SIGNED_RESPONSE);
return 1;
}
POCSP_BASIC_SIGNED_RESPONSE_INFO pocspBasicSignedResponseInfo = nullptr;
DWORD ocspBasicSignedResponseSize = 0;
ret = CryptDecodeObjectEx(PKCS_7_ASN_ENCODING, OCSP_BASIC_SIGNED_RESPONSE, pocspResponseInfo->Value.pbData, pocspResponseInfo->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, nullptr, &pocspBasicSignedResponseInfo, &ocspBasicSignedResponseSize);
if (!ret)
{
showStrError("DecodeOCSP_BASIC_SIGNED_RESPONSE");
return 1;
}
POCSP_BASIC_RESPONSE_INFO pocspBasicResponseInfo = nullptr;
DWORD ocspBasicResponseSize = 0;
ret = CryptDecodeObjectEx(PKCS_7_ASN_ENCODING, OCSP_BASIC_RESPONSE, pocspBasicSignedResponseInfo->ToBeSigned.pbData, pocspBasicSignedResponseInfo->ToBeSigned.cbData, CRYPT_DECODE_ALLOC_FLAG, nullptr, &pocspBasicResponseInfo, &ocspBasicResponseSize);
if (!ret)
{
showStrError("DecodeOCSP_BASIC_RESPONSE");
return 1;
}
DWORD certStatus = pocspBasicResponseInfo->rgResponseEntry->dwCertStatus;
printf("cert status is %d", certStatus); // good:0, revoked:1, unknown:2
return 0;
The showStrError() is modified from WinCrypt examples as below:
void showStrError(const char* lpszFunction)
{
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMsgBuf,
0, NULL);
// Display the error message and exit the process
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
printf("%s failed with error %d: %ws\n", lpszFunction, dw, (LPCTSTR)lpMsgBuf);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
}

Alternatives to LsaLogonUser with KERB_S4U_LOGON have Network access?

Are there any alternatives to LsaLogonUser for impersonating given account in order to access network resources? I'm looking for the method of impersonation which would let me call a remote machine via UNC in the same domain.
For initial data I have: domain\username.
I have no password, because this I am using LsaRegisterLogonProcess and LsaLogonUser with Kerberos package. Locally everything is working and I can impersonate and call applications using a different username, however, when trying to access a remote machine using.. \\remotemachine\shared\somefile.bat I have Access Denied.
Basically I call cmd.exe as command.. and then a Console opens with a new user impersonated, but if a Try to call the UNC path, Access Denied.
If I open a basic console with my own user, I execute this UNC path successfully. Is not Folder permissions because is a public Share.
This is a part of my working code:
...
NTSTATUS Status = STATUS_SUCCESS;
LSA_OPERATIONAL_MODE unused;
LSA_STRING lsaString;
lsaString.Buffer = "User Impersonated LogonProcess";
lsaString.Length = strlen(lsaString.Buffer);
lsaString.MaximumLength = lsaString.Length + 1;
Status = LsaRegisterLogonProcess(&lsaString, &lsa, &unused);
if (Status != STATUS_SUCCESS) {
printf("LsaRegisterLogonProcess failed: %x\n", Status);
}
...
NTSTATUS status = LsaLogonUser(
lsa,
&origin,
Network,
packageId,
authInfo,
authInfoSize,
0,
&source,
&profileBuffer,
&profileBufLen,
&luid,
&token,
&qlimits,
&subStatus
);
if (status != ERROR_SUCCESS)
{
ULONG err = LsaNtStatusToWinError(status);
printf("LsaLogonUser failed: %x\n", status);
return 1;
}
...
DuplicateTokenEx(token, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &tokenDuplicate);
if (CreateProcessWithTokenW(
tokenDuplicate,
LOGON_WITH_PROFILE,
command,
command_arguments,
CREATE_NEW_CONSOLE,
NULL,
NULL,
&si,
&pi))
{
pi.hThread = NULL;
pi.hProcess = NULL;
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}

Extract Certificate Chain from SChannel with C++ and CryptoApi/SChannel

Is it possible to extract the certificate chain sent by the remote computer in TLS 1.0 Handshake?
The API QueryContextAttributes with SECPKG_ATTR_REMOTE_CERT_CONTEXT value, returns only the end certificate.
Is possible to extract all the chain certificates using some methods?
Environment Windows and C++ using CryptoApi and SChannel.
Thanks!
Yes, it is.
Use QueryContextAttributes() with SECPKG_ATTR_REMOTE_CERT_CONTEXT and server certificate returned will have hCertStore member set to a certificate store containing all server's intermediate CA certificates. (See remarks at MSDN.)
See the code snippet below (Source: WebClient.c, Microsoft Platform SDK) how you can parse the chain:
static
void
DisplayCertChain(
PCCERT_CONTEXT pServerCert,
BOOL fLocal)
{
CHAR szName[1000];
PCCERT_CONTEXT pCurrentCert;
PCCERT_CONTEXT pIssuerCert;
DWORD dwVerificationFlags;
printf("\n");
// display leaf name
if(!CertNameToStr(pServerCert->dwCertEncodingType,
&pServerCert->pCertInfo->Subject,
CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
szName, sizeof(szName)))
{
printf("**** Error 0x%x building subject name\n", GetLastError());
}
if(fLocal)
{
printf("Client subject: %s\n", szName);
}
else
{
printf("Server subject: %s\n", szName);
}
if(!CertNameToStr(pServerCert->dwCertEncodingType,
&pServerCert->pCertInfo->Issuer,
CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
szName, sizeof(szName)))
{
printf("**** Error 0x%x building issuer name\n", GetLastError());
}
if(fLocal)
{
printf("Client issuer: %s\n", szName);
}
else
{
printf("Server issuer: %s\n\n", szName);
}
// display certificate chain
pCurrentCert = pServerCert;
while(pCurrentCert != NULL)
{
dwVerificationFlags = 0;
pIssuerCert = CertGetIssuerCertificateFromStore(pServerCert->hCertStore,
pCurrentCert,
NULL,
&dwVerificationFlags);
if(pIssuerCert == NULL)
{
if(pCurrentCert != pServerCert)
{
CertFreeCertificateContext(pCurrentCert);
}
break;
}
if(!CertNameToStr(pIssuerCert->dwCertEncodingType,
&pIssuerCert->pCertInfo->Subject,
CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
szName, sizeof(szName)))
{
printf("**** Error 0x%x building subject name\n", GetLastError());
}
printf("CA subject: %s\n", szName);
if(!CertNameToStr(pIssuerCert->dwCertEncodingType,
&pIssuerCert->pCertInfo->Issuer,
CERT_X500_NAME_STR | CERT_NAME_STR_NO_PLUS_FLAG,
szName, sizeof(szName)))
{
printf("**** Error 0x%x building issuer name\n", GetLastError());
}
printf("CA issuer: %s\n\n", szName);
if(pCurrentCert != pServerCert)
{
CertFreeCertificateContext(pCurrentCert);
}
pCurrentCert = pIssuerCert;
pIssuerCert = NULL;
}
}

SCHANNEL TLS Server side cannot CertFindCertificateInStore

I am adding TLS encryption to a server side application. I am using the Schannel API to add the TLS. I am having a problem with CertFindCertificateInStore. It does not ever find the certificate that I am searching for. As criteria for the search I am using the name of the certificate. I have spent many hours on this now and do not understand why it is not working. Any help would be immensely appreciated. The function I am using this in is found below. Thanks,
int ServerCreateCredentials() {
//- get the certificate store
HCERTSTORE myCertStore = NULL;
myCertStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM,
X509_ASN_ENCODING,
NULL,
CERT_SYSTEM_STORE_LOCAL_MACHINE,
L"My");
// check for the failure to find the appropriate store
if (myCertStore == NULL) {
return 1;
}
// find the certificate in the store
m_CertificateContext = CertFindCertificateInStore(
myCertStore,
X509_ASN_ENCODING,
0,
CERT_FIND_SUBJECT_STR_A,
(LPVOID) CertificateName,
NULL);
if (m_CertificateContext == NULL) {
// try unicode
m_CertificateContext = CertFindCertificateInStore(
myCertStore,
X509_ASN_ENCODING,
0,
CERT_FIND_SUBJECT_STR_W,
CertificateName,
NULL);
if (m_CertificateContext == NULL ) {
// free the store
CertCloseStore(myCertStore, CERT_CLOSE_STORE_CHECK_FLAG);
return 2;
}
}
TimeStamp life;
// get the credentials
SCHANNEL_CRED SchannelCredentials;
ZeroMemory(&SchannelCredentials, sizeof(SchannelCredentials));
SchannelCredentials.dwVersion = SCHANNEL_CRED_VERSION;
SchannelCredentials.cCreds = 1; // number of credentials
SchannelCredentials.paCred = &m_CertificateContext; // credentials
SchannelCredentials.hRootStore = myCertStore; // certificate store location
SchannelCredentials.dwMinimumCipherStrength = 80; // minimum encryption allowed
SchannelCredentials.grbitEnabledProtocols = 0; // let the dll decide
SchannelCredentials.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION
| SCH_CRED_NO_SERVERNAME_CHECK
| SCH_CRED_REVOCATION_CHECK_CHAIN;
DWORD Status = SEC_E_OK;
Status = m_securityFunctionTable.AcquireCredentialsHandle(
NULL,
UNISP_NAME,
SECPKG_CRED_INBOUND,
NULL,
&SchannelCredentials,
NULL,
NULL,
&m_credentials,
&life);
// at this point we should be good
// free the store
CertCloseStore(myCertStore, CERT_CLOSE_STORE_CHECK_FLAG);
if (Status != SEC_E_OK) {
return 3;
}
return 0;
I have figured out that I was not searching on the correct parameters. You need to search based on the subject name and then it will work.

verify digital signature using public key in openssl

I have signed a data in windows using wincrypt cryptoapi (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING) and in linux, I have x509 certificate and the signed message which i have to verify
Code in windows to sign :
hStoreHandle = CertOpenStore(
CERT_STORE_PROV_SYSTEM,
0,
NULL,
CERT_SYSTEM_STORE_CURRENT_USER,
CERT_PERSONAL_STORE_NAME
);
CheckError((BOOL)hStoreHandle, L"CertOpenStore....................... ");
// Get signer's certificate with access to private key.
do {
// Get a certificate that matches the search criteria
pSignerCert = CertFindCertificateInStore(
hStoreHandle,
MY_TYPE,
0,
CERT_FIND_SUBJECT_STR,
SignerName,
pSignerCert
);
CheckError((BOOL)pSignerCert, L"CertFindCertificateInStore.......... ");
// Get the CSP, and check if we can sign with the private key
bResult = CryptAcquireCertificatePrivateKey(
pSignerCert,
0,
NULL,
&hCryptProv,
&dwKeySpec,
NULL
);
CheckError(bResult, L"CryptAcquireCertificatePrivateKey... ");
} while ((dwKeySpec & AT_SIGNATURE) != AT_SIGNATURE);
// Create the hash object.
bResult = CryptCreateHash(
hCryptProv,
CALG_MD5,
0,
0,
&hHash
);
CheckError(bResult, L"CryptCreateHash..................... ");
// Open the file with the content to be signed
hDataFile = CreateFileW(DataFileName,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL
);
CheckError((hDataFile != INVALID_HANDLE_VALUE), L"CreateFile.......................... ");
// Compute the cryptographic hash of the data.
while (bResult = ReadFile(hDataFile, rgbFile, BUFSIZE, &cbRead, NULL))
{
if (cbRead == 0)
{
break;
}
CheckError(bResult, L"ReadFile............................ ");
bResult = CryptHashData(
hHash,
rgbFile,
cbRead,
0
);
CheckError(bResult, L"CryptHashData....................... ");
}
CheckError(bResult, L"ReadFile............................ ");
// Sign the hash object
dwSigLen = 0;
bResult = CryptSignHash(
hHash,
AT_SIGNATURE,
NULL,
0,
NULL,
&dwSigLen
);
CheckError(bResult, L"CryptSignHash....................... ");
pbSignature = (BYTE *)malloc(dwSigLen);
CheckError((BOOL)pbSignature, L"malloc.............................. ");
bResult = CryptSignHash(
hHash,
AT_SIGNATURE,
NULL,
0,
pbSignature,
&dwSigLen
);
CheckError(bResult, L"CryptSignHash....................... ");
// Create a file to save the signature
hSignatureFile = CreateFileW(
SignatureFileName,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
CheckError((hSignatureFile != INVALID_HANDLE_VALUE), L"CreateFile.......................... ");
// Write the signature to the file
bResult = WriteFile(
hSignatureFile,
(LPCVOID)pbSignature,
dwSigLen,
&lpNumberOfBytesWritten,
NULL
);
CheckError(bResult, L"WriteFile........................... ");
In openssl i tried:
openssl rsautl -verify -inkey pubkey.pem -keyform PEM -pubin -in signedmessage
it is throwing error::
RSA operation error
4296:error:0406706C:rsa routines:RSA_EAY_PUBLIC_DECRYPT:data greater than modlen:fips_rsa_eay.c:709:
and this error if the signedmessage is hashed
RSA operation error
4432:error:0407006A:rsa routines:RSA_padding_check_PKCS1_type_1:block type is not 01:rsa_pk1.c:100:
4432:error:04067072:rsa routines:RSA_EAY_PUBLIC_DECRYPT:padding check failed:fips_rsa_eay.c:748:
i also tried :
openssl dgst -verify pubkey.pem -signature signedmessage
but program goes into infinite loop
I also find one command:
int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store, BIO *indata, BIO *out, int flags);
but it require too many argument of which i am not aware of.e.g there is no x509_store, crlfile used in this
. can any one tell me how to verify the signed message
I get x509 pem certificate and signedmessage as input in linux which i have to verify
After some example by mail, we got to the following recipe
setup:
we have a x509 certificate cert.p7b to start with, a file message.txt, a Windows produced signed.dat, and using sha1 for definiteness.
openssl pkcs7 -inform DER -outform PEM -in cert.p7b -out cert.pem -print_certs
openssl x509 -in cert.pem -noout -pubkey > pubkey.pem
(this need only be done once for a certificate, to get a public key in PEM format)
then reverse signed.dat bytewise to signed.dat.rev
(using a simple C program, or output the bytes differently on Windows, in alternative form)
and finally
openssl dgst -sha1 -verify pubkey.pem -signature signed.dat.rev message.txt
The main problem was the reverse byte order on Windows (which I have seen before)