Form of SubjectName text in PDF export

Stimulsoft Reports.NET discussion
LukasT
Posts: 306
Joined: Mon May 03, 2010 2:50 am
Location: Czech Republic

Form of SubjectName text in PDF export

Post by LukasT »

Hello,
how looks form of subjectName for Subject name string in PDF export? I have tried to put SubjectName from cert store but stimulsoft returned exception - DigitalSign error at step 2: Certificate is not found .
Thank you...
Ivan
Posts: 960
Joined: Thu Aug 10, 2006 1:37 am

Form of SubjectName text in PDF export

Post by Ivan »

Hello,

There are two ways to create the digital signature for PDF file:
- using the interface of the system library of cryptograph;
- directly by specifying the string - certificate identifier.

In the first case it is necessary to set the Get Certificate From CryptoUI property to true. When
exporting, the menu for selecting certificate from the current storage of certificates will be displayed.
It is necessary to select one certificate from the list of available ones.

In the second way, it is necessary to use the "SubjectNameString" property and write in it the
string - certificate identifier. Identifier is the name of the certificate owner (full string) or a part of the
name (substring).

Also please try to set the UseLocalMachineCertificates property in export settings to true or false.

Thank you.
LukasT
Posts: 306
Joined: Mon May 03, 2010 2:50 am
Location: Czech Republic

Form of SubjectName text in PDF export

Post by LukasT »

Sorry Ivan, but some problems exists...
I am using X509Certificate class, and there is property SubjectName which contains several parameters as CN, OU, DC etc. But I thing, that finding certificate using only CN is wrong way... because I can have more certificates with the same CN in cert store... if I know, for finding certificate is common used this function:

Code: Select all

(X509Certificate2Collection)store.Certificates.Find(X509FindType.FindBySubjectDistinguishedName, subject, false);

as subject must be whole subjectName...
I have tried tu put into ((StiPdfExportSettings)sett).SubjectNameString both - only CN value or whole subjectName and both caused exception...
Second strange issue is in export dialog in viewer... if I don't have checked using Crpto UI, i can put into field for subject name only 33 characters... that is not enough to put whole subjectName... but even if I put only CN value, certificate is not found :-(
Ivan
Posts: 960
Joined: Thu Aug 10, 2006 1:37 am

Form of SubjectName text in PDF export

Post by Ivan »

Hello,
LukasT wrote:I am using X509Certificate class, and there is property SubjectName which contains several parameters as CN, OU, DC etc. But I thing, that finding certificate using only CN is wrong way... because I can have more certificates with the same CN in cert store... if I know, for finding certificate is common used this function: ...
For working with certificates we use Crypt32.dll and CryptUI.dll libraries.
For getting the certificate the CertFindCertificateInStore command is used and the CryptSignMessage command is used for signing the document.
These commands are universal and work with majority of certificates on the basic level and know nothing about options of the certificate types.
Unfortunately, we do not plan to work further on this functionality.
LukasT wrote:as subject must be whole subjectName... I have tried tu put into ((StiPdfExportSettings)sett).SubjectNameString both - only CN value or whole subjectName and both caused exception...
Second strange issue is in export dialog in viewer... if I don't have checked using Crpto UI, i can put into field for subject name only 33 characters... that is not enough to put whole subjectName... but even if I put only CN value, certificate is not found :-(
We fixed the issue. Fields length is increased up to 256 symbols.

Thank you.
LukasT
Posts: 306
Joined: Mon May 03, 2010 2:50 am
Location: Czech Republic

Form of SubjectName text in PDF export

Post by LukasT »

Thank you for fix...

I have tried everything possible, but still no success :-(

My code is:

Code: Select all

...
            sett = new StiPdfExportSettings();
            ((StiPdfExportSettings)sett).UseDigitalSignature = true;
            ((StiPdfExportSettings)sett).GetCertificateFromCryptoUI = false;
            ((StiPdfExportSettings)sett).UseLocalMachineCertificates = true;
            ((StiPdfExportSettings)sett).SubjectNameString = subjectName;
            rep.CompiledReport.ExportDocument(format, filename, sett);
...
Subject name is valid because I am using it correctly in my function for signing other exported formats...

Is possible to send me any part of your code which you use for getting certificate from store?

And I have found one interesting unanswered question... that is the same using Crypt32.dll like you have, isn't it?
http://social.msdn.microsoft.com/Forums ... f29d560a1c
Ivan
Posts: 960
Joined: Thu Aug 10, 2006 1:37 am

Form of SubjectName text in PDF export

Post by Ivan »

Hello,
LukasT wrote:Is possible to send me any part of your code which you use for getting certificate from store?
We use the following code:

Code: Select all

            [StructLayout(LayoutKind.Sequential)]
            public struct CERT_CONTEXT
            {
                public uint dwCertEncodingType;
                public IntPtr pbCertEncoded;
                public uint cbCertEncoded;
                public IntPtr pCertInfo;
                public IntPtr hCertStore;
            }

Code: Select all

			uint ENCODING_TYPE = Win32.PKCS_7_ASN_ENCODING | Win32.X509_ASN_ENCODING; 
			string CERT_STORE_NAME = "MY";
			uint CERT_SYSTEM_STORE = Win32.CERT_SYSTEM_STORE_CURRENT_USER;
			if (useLocalMachineCertificates)
			{
				CERT_SYSTEM_STORE = Win32.CERT_SYSTEM_STORE_LOCAL_MACHINE;
			}

			#region Open store
			IntPtr hStoreHandle = Win32.CertOpenStore(
				(IntPtr)Win32.CERT_STORE_PROV_SYSTEM,
				0,
				IntPtr.Zero, 
				CERT_SYSTEM_STORE, 
				Encoding.Unicode.GetBytes(CERT_STORE_NAME));
			if (hStoreHandle == IntPtr.Zero) ThrowDigitalSignError(1);
			#endregion

			#region FindCertificateInStore
			if ((certificateID != null) && (certificateID != string.Empty))
			{
				IntPtr SIGNER_NAME = Marshal.StringToBSTR(certificateID); 
				int certificateIsValid = 0;
				do
				{
					pCertContext = Win32.CertFindCertificateInStore(
						hStoreHandle, 
						ENCODING_TYPE,
						0,
						Win32.CERT_FIND_SUBJECT_STR,
						SIGNER_NAME,
						pCertContext);
						if (pCertContext == IntPtr.Zero) ThrowDigitalSignError(2, "Certificate is not found", true);

					SignerCert = (Win32.CERT_CONTEXT)Marshal.PtrToStructure(pCertContext, typeof(Win32.CERT_CONTEXT)); 

					certificateIsValid = Win32.CertVerifyTimeValidity(IntPtr.Zero, SignerCert.pCertInfo);
				}
				while (certificateIsValid != 0);
			}
			else
			{
				ThrowDigitalSignError(2, "Subject name string is empty");
			}
			#endregion
Thank you.
LukasT
Posts: 306
Joined: Mon May 03, 2010 2:50 am
Location: Czech Republic

Form of SubjectName text in PDF export

Post by LukasT »

Thank you Ivan...
so, now I have the same method as you use (probably you have code from pinvoke.net... it seems)... If I call CertEnumCertificatesInStore method, it returns me all certificates in store ... that is OK. But than I call CertFindCertificateInStore method with subjectName from first function and it returns me zero pointer :-( Really strange issue... So I will test it and debug it and get to know you where is the problem ;-)

And Ivan, are you shure, that your code is running correctly in runtime? Please check it and try to sign PDF document in runtime using some certificate without CryptoUI...
LukasT
Posts: 306
Joined: Mon May 03, 2010 2:50 am
Location: Czech Republic

Form of SubjectName text in PDF export

Post by LukasT »

So...
I have realized what is going on. Parameter CERT_FIND_SUBJECT_STR in function CertFindCertificateInStore is really only for finding certificates in store by CN value... even so your engine returns exception DigitalSign error at step 2: Certificate is not found... looks really your code is not all right...

My correct example:

Code: Select all

 public class Simplecert
    {
        const string MY = "MY";
        const string OTHERS = "AddressBook";
        const uint PKCS_7_ASN_ENCODING = 0x00010000;
        const uint X509_ASN_ENCODING = 0x00000001;
        const uint CERT_FIND_SUBJECT_STR = 0x00080007;
        const uint CERT_FIND_SUBJECT_NAME = 0x00020007;


        static uint MY_ENCODING_TYPE = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;

        static string lpszCertSubject = "..."; //value from CN in SubjectName

        public static void Main()
        {
            IntPtr hSysStore = IntPtr.Zero;
            IntPtr hCertCntxt = IntPtr.Zero;
            IntPtr SIGNER_NAME = Marshal.StringToBSTR(lpszCertSubject);

            hSysStore = Crypt.CertOpenSystemStore(IntPtr.Zero, MY);
            Console.WriteLine("Store Handle:\t0x{0:X}", hSysStore.ToInt32());
            X509Certificate cert;
            IntPtr currentCertContext = Crypt.CertEnumCertificatesInStore(hSysStore, (IntPtr)0);
            while (currentCertContext != (IntPtr)0)
            {
                cert = new X509Certificate(currentCertContext);
                // Do something with the certificate...
                Console.WriteLine(cert.ToString(true));
                currentCertContext = Crypt.CertEnumCertificatesInStore(hSysStore, currentCertContext);
            }

            if (hSysStore != IntPtr.Zero)
            {
                hCertCntxt = Crypt.CertFindCertificateInStore(
                    hSysStore,
                    MY_ENCODING_TYPE,
                    0,
                    CERT_FIND_SUBJECT_NAME,
                    SIGNER_NAME,
                    IntPtr.Zero);                
                if (hCertCntxt != IntPtr.Zero)
                {  //use certcontext from managed code
                    Console.WriteLine("CertContext:\t0x{0:X}", hCertCntxt.ToInt32());
                    X509Certificate foundcert = new X509Certificate(hCertCntxt);
                    Console.WriteLine("\nFound certificate with SubjectName string \"{0}\"", lpszCertSubject);
                    Console.WriteLine("SubjectName:\t{0}", foundcert.Subject);
                    Console.WriteLine("Serial No:\t{0}", foundcert.GetSerialNumberString());
                    Console.WriteLine("HashString:\t{0}", foundcert.GetCertHashString());
                }
                else
                    Console.WriteLine("Could not find SubjectName containing string \"{0}\"", lpszCertSubject);
            }
            Console.ReadKey();
        }
        
    }
Second issue is not mistake, but only not implemented feature - finding certificate by whole subjectName using CERT_FIND_SUBJECT_NAME and CertNameToStr function... I thing this is better way, because than I can have more certificates with one CN (what is quite common) and than function will find right certificate which I want...
LukasT
Posts: 306
Joined: Mon May 03, 2010 2:50 am
Location: Czech Republic

Form of SubjectName text in PDF export

Post by LukasT »

Is any progress in this issue, please?
Ivan
Posts: 960
Joined: Thu Aug 10, 2006 1:37 am

Form of SubjectName text in PDF export

Post by Ivan »

Hello,

We made some improvements in that direction.
Please check the next prerelease build from 23-Aug-2010 when it will be available and let us know about the result.

Thank you.
Post Reply