locked
How can I read a .cer file with windows sdk and VC++? RRS feed

  • Question

  • Hello:

    I have a VC++ MFC application that needs to be upgraded. My problem is: I have to load a ".cer"  file (NOT the certificate from a store, but the file itself) and retrieve some attributes, like serial number.   I know it would be easier using .NET, but I have the full code in VC++ . I have read it could be done using CAPICOM : something like Certificate.Load("file.cer"),  but I can not find the headers. I have tried  wincrypt.h functions but none suits my needs... could you give me some suggestions?

    Thanks very much!!

    • Moved by Jesse Jiang Monday, February 28, 2011 8:54 AM (From:Visual C++ General)
    Thursday, February 24, 2011 3:27 PM

All replies

  • Are you aware that a .cer file can be accessed as a certificate store?

    Consider using CertOpenStore() as follows:

    HCERTSTORE mycer = CertOpenStore (CERT_STORE_PROV_FILENAME, X509_ASN_ENCODING, NULL, (CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG), TEXT("myfile.cer") );
    

    and then enumerating the store's contents.

    Unfortunately there are (at least) two different formats of .cer files; they both contain the same underlying data, but one form is a base-64 encoding of the other.


    Answering policy: see profile.
    Thursday, February 24, 2011 11:26 PM
  •  

    Hello,

     

    I think your issue should be raised in the Security for Applications in Microsoft Windows forum. I believe they will know more information of this issue than us, and I will move this one to that forum.

     

    Thanks for your understanding,

     

    Best regards,

    Jesse


    Jesse Jiang [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Monday, February 28, 2011 8:55 AM
  • Look at CryptQueryObject to load from a file and give you a certificate context.
    Tuesday, April 12, 2011 7:06 PM
  •  

    Check with http://support.microsoft.com/kb/323809 for how to use CryptQueryObject function.

    You can also use X509Certificate2 Class for open and get all the certificate information using C++ .NET application. 

     


    Thanks and Regards Selvam http://www15.brinkster.om/selvamselvam/
    Wednesday, April 13, 2011 7:53 AM
  • Hi David,

     

    Can I retrive public key using above CertOpenStore API if I provide a certificate to it. How can I retive a public key from it.

    How to use enumeration on it to retrive the information.

     

    Please guide me.

     

    Thanks,

    Prashant.




    Friday, July 15, 2011 11:03 AM
  • // Constructor of a public key from a certificate.
    //
    cspkey( Cspprov & prov, PCCERT_CONTEXT certcon )
    {
    	PCERT_PUBLIC_KEY_INFO pNewPubKeyinfo; 
    	pNewPubKeyinfo = &(certcon->pCertInfo->SubjectPublicKeyInfo);
    
    	m_valid_key= CryptImportPublicKeyInfo( prov.getHCryptProv(), X509_ASN_ENCODING,
    										 pNewPubKeyinfo, &m_hKey ) 
    			? true : false;
    }
    
    


    Gives you the public key for cryptoapi:    HCRYPTKEY m_hKey; 

    You can get a certificate from memory using:

    Load the .cer data into a PCCERT_CONTEXT
    
    
    // Constructor for certificate in memory
    //
    bool Certif::construct( unsigned char cert[], long cert_len )
    {		
    	PCCERT_CONTEXT itsCertContext = ::CertCreateCertificateContext( X509_ASN_ENCODING, cert, cert_len );
    	itsValid= ( NULL != itsCertContext );
    	return ( itsValid );
    }
    
    
    //----------------------------------------------------------------------------
    
    void Certif::showSerial( SmartUtil::tostream &o )
    {
    	cryptInteger2StreamLE( o, itsCertContext->pCertInfo->SerialNumber );
    }
    
    //----------------------------------------------------------------------------
    
    void Certif::cryptInteger2StreamLE( SmartUtil::tostream &o, const CRYPT_INTEGER_BLOB & cib )
    {
    	vector< unsigned char > vectLE( cib.pbData, &cib.pbData[cib.cbData] ); 
    	HexDump::vect2StreamLE( o, vectLE );
    }
    
    
    //----------------------------------------------------------------------------
    
    
    // Takes	vector< unsigned char > val = { 0x12, 0x34, 0x56 }
    // and streams "56 34 12" since val is assumed little endian.
    //
    static void vect2StreamLE( SmartUtil::tostream &ss, const vector< unsigned char > &val )
    {
      ss << hex;
    
    for( int i= (int)val.size()-1; i >= 0; i-- ) { 
      if ( ios::hex & ss.flags() ) {
    	if ( (int)val[i] < 0x10 ) ss << '0';
      }
      ss << (int)val[i] << " ";
    }
    
      ss << dec;
    }
    
    
    
    

    • Proposed as answer by Prashant 1986 Monday, July 18, 2011 9:54 AM
    Friday, July 15, 2011 4:08 PM
  • Hi Andrew,

     

    Thanks for you valuable help, it works.

    Tell me two thinks:

    1. Is retrived public key is in Big endian or Little Endian format.

    2. How can we retrive private key if we have .cert file open. (I can open and read .pfx file as well) Or there is another way to extract private key.

     

    Please guide me on this topic.


    Monday, July 18, 2011 9:54 AM
  • 1) The format of the retrieved public key depends on how you get the bits.

    PCERT_PUBLIC_KEY_INFO points to a public key that is DER encoded with format:

    30 81 89 universal Sequence of len 89

    02 81 81 universal Integer of len 81 ,

    00 mantissa in Big Endian, with leading 00 to ensure positive.
    b3 a6 54 b4 6d a5 68 ce d2 2b 81 c7 3d 2b 8c f6
    e2 40 6c a9 29 a4 53 f9 e3 33 c5 eb 22 f9 36 86
    b2 29 8f 2a 1a f4 96 27 eb 4d 4e 3d eb 8f df d5
    f3 45 49 7b 74 d9 98 39 ee 6a 22 b0 ff 8b 20 a7
    8a a4 4b 97 27 ab b4 51 33 db 79 a2 fe 5b a3 e2
    77 38 43 57 83 32 1a f6 07 e4 27 31 d5 77 eb 61
    d7 da 16 52 2e 07 2c 66 d5 16 cb 3a 31 54 1e ac
    3d 6e 35 28 49 4d 04 b3 bf 85 10 4f e3 21 73 c5

    02 03 01 00 01 universal Integer of len 3 , val=10001 : exponent

    If you use CryptExportKey on a HCRYPTKEY hKey that has a public key you will get a Microsoft specific key blob,

    http://msdn.microsoft.com/en-us/library/aa387459(VS.85).aspx

    which has the little endian format documented above, and shown below:

    06 02 00 00 00 a4 00 00 52 53 41 31 00 04 00 00

    01 00 01 00

    c5 73 21 e3 4f 10 85 bf b3 04 4d 49 28 35 6e 3d ac 1e 54 31 3a cb 16 d5 66 2c 07 2e 52 16 da d7

    61 eb 77 d5 31 27 e4 07 f6 1a 32 83 57 43 38 77 e2 a3 5b fe a2 79 db 33 51 b4 ab 27 97 4b a4 8a

    a7 20 8b ff b0 22 6a ee 39 98 d9 74 7b 49 45 f3 d5 df 8f eb 3d 4e 4d eb 27 96 f4 1a 2a 8f 29 b2

    86 36 f9 22 eb c5 33 e3 f9 53 a4 29 a9 6c 40 e2 f6 8c 2b 3d c7 81 2b d2 ce 68 a5 6d b4 54 a6 b3

     

    2) A certificate may have a link to a private key, See http://msdn.microsoft.com/en-us/library/aa379936(v=VS.85).aspx , but the certificate file format itself does not have a private key.

    A PFX or .p12 file which has a private key may be used with PFXImportCertStore

    See  http://msdn.microsoft.com/en-us/library/aa387314(VS.85).aspx

    Monday, July 18, 2011 6:19 PM
  • Ok thanks again for valuable help.

    Yes the given public key is in Little Endian if you extract using CryptoAPI. If you are using other way it might have different format. I have checked with OpenSSL tool, it gives you all the data you extract in big endian format.

     

    Few more dobouts:

    1. Is there any need of .crt (certificate file) at client side for verification process.

        I know that it contents a public key, but can we store public key from .crt file at development stage in some storage (variable).

        My intention is, I dont want to give certificate file to client. Can we do verification without disrtibution of certificate file.

    If yes then will it affect with verisigns like their expiry date,  etc.


    Thursday, July 21, 2011 8:30 AM
  • The CryptStringToBinary Function  ( http://msdn.microsoft.com/en-us/library/aa380285(VS.85).aspx )

    will convert the data from a .crt file into the data for a .cer.  And then you can get the public key with methods shown above.

     

    The possession of a certificate means nothing, unless you can prove the possession of the private key that matches the public key in the certificate.

    You can use the private key to sign or decrypt some data, thus proving you hold the private key.

    The significance of holding the private key is determined by its certificate;  Who issued it, and what attributes are in that certificate.

     

    I'm not sure what you are asking. Who are you verifing to whom?  Why should the client not have a certificate?   What are your trying to do?

    Thursday, July 21, 2011 3:48 PM
  •  

    I just wanted to verify the integrity of Data. and dont have any other intention. Thats why I am asking that whether there is any need of givening .crt file to client.

    At client side we will just requires public key for verifying whether data is modified or not?

    There will be one xml file at client side (FYI: which is a embeded resource) and our program at client side will just check whether that file has been modified or not by intruder. We have already added a digital signature into that xml file. by our server side digital signature tool.

     

    Thanks,

    Prashant.


    Friday, July 22, 2011 5:31 AM
  • Sure, the public key is sufficient to verify a signature.
    BOOL WINAPI CryptVerifySignature(
     __in HCRYPTHASH hHash,
     __in BYTE *pbSignature,
     __in DWORD dwSigLen,
     __in HCRYPTKEY hPubKey,
     __in LPCTSTR sDescription,
     __in DWORD dwFlags
    );
    
    Friday, July 22, 2011 10:40 AM
  • Hi Prashant,

    I am also facing the same problem. My *.cer file is also at some physical location and want to read public key out of that. But i am not able to undersatnd from above code how you did the same. Can you if possible give some more detail or your code sample here.

    Thanks,

    Nikhil.

    Thursday, October 18, 2012 2:35 PM
  • Well, actually I could not read it with Win32 API.

    What I did was a port from this c# code:

    http://www.jensign.com/opensslkey/opensslkey.cs

    I ported it to VC++ (as managed) and it works fine.

    Thursday, October 18, 2012 9:58 PM
  • Hi,

    You can use below code

    String^ Certificate = L"D:\\02020202.crt";

       // Load the certificate into an X509Certificate object.
       X509Certificate^ cert = gcnew X509Certificate(Certificate);

    cert objects will contain all information like Serial Number etc.

    • Proposed as answer by RohanMohite Thursday, May 21, 2015 2:16 PM
    Tuesday, November 19, 2013 7:20 PM
  • Hi, 

    Is there a way to load a PFX file which has a password protected private key into PCCERT_CONTEXT  using CryptQueryObject API? I tried the usual way 

          PCCERT_CONTEXT Context = nullptr;

    BOOL bRetVal = CryptQueryObject(
    CERT_QUERY_OBJECT_FILE,
    pfxfilepath,
    CERT_QUERY_CONTENT_FLAG_ALL,
    CERT_QUERY_FORMAT_FLAG_ALL,
    0,
    &dwEncoding,
    &dwContentType,
    &dwFormatType,
    nullptr,
    nullptr,
    (const void **)&Context
    );

    The API returns TRUE but the Context is still NULL. The dwEncodding,dwContentType,dwFormatType variables are filled up correctly to indicate it is a PFX file. 

    Many thanks

    Friday, September 30, 2016 10:30 AM
  • First, open a CertStore from the PFX.

    // Convert the P12 data into a memory certstore
    HCERTSTORE Crypto::getCertStoreForP12(std::ostream & outs,
    	std::vector<BYTE> & p12Data, const std::string & password )
    {
    	bool ok = false;
    	HCERTSTORE  itsStore = NULL;
    	if (0 != p12Data.size()) {
    		CRYPT_DATA_BLOB pfx;
    		pfx.cbData = p12Data.size();
    		pfx.pbData = (BYTE *)p12Data.data();
    
    		if (::PFXIsPFXBlob(&pfx)) {
    			std::wstring wpass = VectUtil::to_wstring(password);
    
    			if (::PFXVerifyPassword(&pfx, wpass.c_str(), 0)) {
    				DWORD dwFlags = CRYPT_EXPORTABLE;
    				itsStore = ::PFXImportCertStore(&pfx, wpass.c_str(), dwFlags);
    				if (NULL != itsStore) {
    					ok = true;
    				}
    				else {
    					outs << "P12 Import failed" << std::endl;
    				}
    			}
    			else {
    				outs << "Incorrect password" << std::endl;
    			}
    		}
    		else {
    			outs << "Not a proper .p12/pfx" << std::endl;
    		}
    	}
    	else {
    		outs << _T("No data present") << std::endl;
    	}
    	if (!ok) return false;
    	outs << "P12 converted into certstore." << std::endl;
    	return itsStore;
    }
    

    Then loop to get the  PCCERT_CONTEXT

    PCCERT_CONTEXT  pcontext = NULL;
    
    while (pcontext = ::CertEnumCertificatesInStore(itsStore, pcontext)){
       Do something
    }
    

    Friday, September 30, 2016 5:17 PM