Example #1
0
        /// <summary>
        /// Encode and sign a CERT_INFO structure
        /// </summary>
        /// <param name="key">Key to sign the certificate with</param>
        /// <param name="certInfo">The CERT_INFO structure to sign</param>
        /// <param name="hashAlgorithm"></param>
        /// <returns></returns>
        private byte[] EncodeAndSignCertInfo(RSACryptoServiceProvider key, CryptoApiMethods.CERT_INFO certInfo, CertificateHashAlgorithm hashAlgorithm)
        {
            byte[] ret = null;
            CryptoApiMethods.SafeCryptProviderHandle hProv = new CryptoApiMethods.SafeCryptProviderHandle();

            try
            {
                hProv = OpenRSAProvider(key.CspKeyContainerInfo.ProviderName, key.CspKeyContainerInfo.KeyContainerName);

                ret = EncodeAndSignCertInfo(hProv, certInfo, key.CspKeyContainerInfo.KeyNumber == KeyNumber.Signature ? true : false, hashAlgorithm);
            }
            finally
            {
                if (!hProv.IsInvalid)
                {
                    hProv.Close();
                }
            }

            return(ret);
        }
Example #2
0
        /// <summary>
        /// Create a new certificate
        /// </summary>
        /// <param name="issuer">Issuer certificate, if null then self-sign</param>
        /// <param name="subjectName">Subject name</param>
        /// <param name="serialNumber">Serial number of certificate, if null then will generate a new one</param>
        /// <param name="signature">If true create an AT_SIGNATURE key, otherwise AT_EXCHANGE</param>
        /// <param name="keySize">Size of RSA key</param>
        /// <param name="notBefore">Start date of certificate</param>
        /// <param name="notAfter">End date of certificate</param>
        /// <param name="extensions">Array of extensions, if null then no extensions</param>
        /// <param name="hashAlgorithm">Specify the signature hash algorithm</param>
        /// <returns>The created X509 certificate</returns>
        public X509Certificate2 CreateCert(X509Certificate2 issuer, X500DistinguishedName subjectName, byte[] serialNumber, bool signature, int keySize, CertificateHashAlgorithm hashAlgorithm, DateTime notBefore, DateTime notAfter, X509ExtensionCollection extensions)
        {
            CryptoApiMethods.CERT_INFO certInfo   = new CryptoApiMethods.CERT_INFO();
            RSACryptoServiceProvider   key        = CreateRSAKey(keySize, signature);
            IntPtr               publicKeyInfoPtr = IntPtr.Zero;
            X509Certificate2     cert             = null;
            List <X509Extension> newExts          = null;

            if (extensions != null)
            {
                foreach (X509Extension ext in extensions)
                {
                    if (ext.RawData == null)
                    {
                        throw new ArgumentException(Properties.Resources.CreateCert_NeedEncodedData);
                    }
                }
            }

            try
            {
                if (serialNumber == null)
                {
                    serialNumber = Guid.NewGuid().ToByteArray();
                }

                certInfo.dwVersion    = (uint)CryptoApiMethods.CertVersion.CERT_V3;
                certInfo.SerialNumber = new CryptoApiMethods.CRYPTOAPI_BLOB(serialNumber);
                certInfo.Subject      = new CryptoApiMethods.CRYPTOAPI_BLOB(subjectName.RawData);

                if (issuer == null)
                {
                    // Self-signed
                    certInfo.Issuer = new CryptoApiMethods.CRYPTOAPI_BLOB(subjectName.RawData);
                }
                else
                {
                    certInfo.Issuer = new CryptoApiMethods.CRYPTOAPI_BLOB(issuer.SubjectName.RawData);
                }

                // Never seems to need these set to anything valid?
                certInfo.SubjectUniqueId = new CryptoApiMethods.CRYPT_BIT_BLOB();
                certInfo.IssuerUniqueId  = new CryptoApiMethods.CRYPT_BIT_BLOB();

                certInfo.NotBefore = DateTimeToFileTime(notBefore);
                certInfo.NotAfter  = DateTimeToFileTime(notAfter);

                certInfo.SignatureAlgorithm = new CryptoApiMethods.CRYPT_ALGORITHM_IDENTIFIER();
                // Doesn't seem to work properly with standard szOID_RSA_SHA1RSA
                //certInfo.SignatureAlgorithm.pszObjId = CryptoApiMethods.szOID_OIWSEC_sha1RSASign;
                //certInfo.SignatureAlgorithm.pszObjId = CryptoApiMethods.szOID_RSA_SHA1RSA;
                //certInfo.SignatureAlgorithm.pszObjId = CryptoApiMethods.szOID_RSA_SHA512RSA;
                certInfo.SignatureAlgorithm.pszObjId = HashAlgorithmToOID(hashAlgorithm);

                // Add extension fields
                publicKeyInfoPtr = ExportPublicKeyInfo(key);
                certInfo.SubjectPublicKeyInfo = (CryptoApiMethods.CERT_PUBLIC_KEY_INFO)Marshal.PtrToStructure(publicKeyInfoPtr, typeof(CryptoApiMethods.CERT_PUBLIC_KEY_INFO));

                newExts = new List <X509Extension>();

                if (extensions != null)
                {
                    // Filter out some extensions we don't want
                    newExts.AddRange(
                        extensions.Cast <X509Extension>().Where(
                            x =>
                            !x.Oid.Value.Equals(CryptoApiMethods.szOID_AUTHORITY_KEY_IDENTIFIER) &&
                            !x.Oid.Value.Equals(CryptoApiMethods.szOID_SUBJECT_KEY_IDENTIFIER) &&
                            !x.Oid.Value.Equals(CryptoApiMethods.szOID_AUTHORITY_KEY_IDENTIFIER2)));
                }

                if (issuer != null)
                {
                    newExts.Add(CreateAuthorityKeyInfo2(issuer.GetSerialNumber(), issuer.SubjectName, (RSACryptoServiceProvider)issuer.PrivateKey));
                }
                else
                {
                    newExts.Add(CreateAuthorityKeyInfo2(serialNumber, subjectName, key));
                }

                newExts.Add(new X509SubjectKeyIdentifierExtension(HashPublicKeyInfo(key), false));

                certInfo.rgExtension = MarshalExtensions(newExts.ToArray());
                certInfo.cExtension  = (uint)newExts.Count;

                byte[] certData = EncodeAndSignCertInfo(issuer != null ? issuer.PrivateKey as RSACryptoServiceProvider : key, certInfo, hashAlgorithm);

                cert            = new X509Certificate2(certData, (string)null, X509KeyStorageFlags.Exportable);
                cert.PrivateKey = key;
            }
            finally
            {
                if (certInfo.rgExtension != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(certInfo.rgExtension);
                }

                if (certInfo.Subject != null)
                {
                    certInfo.Subject.Release();
                }

                if (certInfo.Issuer != null)
                {
                    certInfo.Issuer.Release();
                }

                if (publicKeyInfoPtr != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(publicKeyInfoPtr);
                }
            }

            return(cert);
        }
Example #3
0
        /// <summary>
        /// Encode and sign a CERT_INFO structure
        /// </summary>
        /// <param name="hProv"></param>
        /// <param name="certInfo"></param>
        /// <param name="signature">True encodes with a AT_SIGNATURE key, otherwise AT_EXCHANGE</param>
        /// <param name="hashAlgorithm"></param>
        /// <returns></returns>
        private byte[] EncodeAndSignCertInfo(CryptoApiMethods.SafeCryptProviderHandle hProv, CryptoApiMethods.CERT_INFO certInfo, bool signature, CertificateHashAlgorithm hashAlgorithm)
        {
            CryptoApiMethods.CALG keyType = signature ? CryptoApiMethods.CALG.AT_SIGNATURE : CryptoApiMethods.CALG.AT_KEYEXCHANGE;
            byte[] ret         = null;
            uint   certLen     = 0;
            IntPtr certInfoPtr = IntPtr.Zero;

            CryptoApiMethods.CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm = new CryptoApiMethods.CRYPT_ALGORITHM_IDENTIFIER();
            //SignatureAlgorithm.pszObjId = CryptoApiMethods.szOID_OIWSEC_sha1RSASign;
            //SignatureAlgorithm.pszObjId = CryptoApiMethods.szOID_RSA_SHA1RSA;
            //SignatureAlgorithm.pszObjId = CryptoApiMethods.szOID_RSA_SHA512RSA;
            SignatureAlgorithm.pszObjId = HashAlgorithmToOID(hashAlgorithm);

            try
            {
                certInfoPtr = Marshal.AllocHGlobal(Marshal.SizeOf(certInfo));
                Marshal.StructureToPtr(certInfo, certInfoPtr, false);

                if (!CryptoApiMethods.CryptSignAndEncodeCertificate(hProv, keyType, CryptoApiMethods.CertEncoding.X509_ASN_ENCODING,
                                                                    new IntPtr((int)CryptoApiMethods.StructType.X509_CERT_TO_BE_SIGNED), certInfoPtr, SignatureAlgorithm, IntPtr.Zero, null, ref certLen))
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }

                ret = new byte[certLen];

                if (!CryptoApiMethods.CryptSignAndEncodeCertificate(hProv, keyType, CryptoApiMethods.CertEncoding.X509_ASN_ENCODING,
                                                                    new IntPtr((int)CryptoApiMethods.StructType.X509_CERT_TO_BE_SIGNED), certInfoPtr, SignatureAlgorithm, IntPtr.Zero, ret, ref certLen))
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }
            }
            finally
            {
                Marshal.DestroyStructure(certInfoPtr, certInfo.GetType());
                Marshal.FreeHGlobal(certInfoPtr);
            }

            return(ret);
        }
        /// <summary>
        /// Create a new certificate
        /// </summary>
        /// <param name="issuer">Issuer certificate, if null then self-sign</param>
        /// <param name="subjectName">Subject name</param>
        /// <param name="serialNumber">Serial number of certificate, if null then will generate a new one</param>
        /// <param name="signature">If true create an AT_SIGNATURE key, otherwise AT_EXCHANGE</param>
        /// <param name="keySize">Size of RSA key</param>
        /// <param name="notBefore">Start date of certificate</param>
        /// <param name="notAfter">End date of certificate</param>
        /// <param name="extensions">Array of extensions, if null then no extensions</param>
        /// <param name="hashAlgorithm">Specify the signature hash algorithm</param>
        /// <returns>The created X509 certificate</returns>
        public X509Certificate2 CreateCert(X509Certificate2 issuer, X500DistinguishedName subjectName, byte[] serialNumber, bool signature, int keySize, CertificateHashAlgorithm hashAlgorithm, DateTime notBefore, DateTime notAfter, X509ExtensionCollection extensions)
        {
            CryptoApiMethods.CERT_INFO certInfo = new CryptoApiMethods.CERT_INFO();
            RSACryptoServiceProvider key = CreateRSAKey(keySize, signature);
            IntPtr publicKeyInfoPtr = IntPtr.Zero;
            X509Certificate2 cert = null;
            List<X509Extension> newExts = null;

            if (extensions != null)
            {
                foreach (X509Extension ext in extensions)
                {
                    if (ext.RawData == null)
                    {
                        throw new ArgumentException(Properties.Resources.CreateCert_NeedEncodedData);
                    }
                }
            }

            try
            {
                if (serialNumber == null)
                {
                    serialNumber = Guid.NewGuid().ToByteArray();
                }

                certInfo.dwVersion = (uint)CryptoApiMethods.CertVersion.CERT_V3;
                certInfo.SerialNumber = new CryptoApiMethods.CRYPTOAPI_BLOB(serialNumber);
                certInfo.Subject = new CryptoApiMethods.CRYPTOAPI_BLOB(subjectName.RawData);

                if (issuer == null)
                {
                    // Self-signed
                    certInfo.Issuer = new CryptoApiMethods.CRYPTOAPI_BLOB(subjectName.RawData);
                }
                else
                {
                    certInfo.Issuer = new CryptoApiMethods.CRYPTOAPI_BLOB(issuer.SubjectName.RawData);
                }

                // Never seems to need these set to anything valid?
                certInfo.SubjectUniqueId = new CryptoApiMethods.CRYPT_BIT_BLOB();
                certInfo.IssuerUniqueId = new CryptoApiMethods.CRYPT_BIT_BLOB();

                certInfo.NotBefore = DateTimeToFileTime(notBefore);
                certInfo.NotAfter = DateTimeToFileTime(notAfter);

                certInfo.SignatureAlgorithm = new CryptoApiMethods.CRYPT_ALGORITHM_IDENTIFIER();
                // Doesn't seem to work properly with standard szOID_RSA_SHA1RSA
                //certInfo.SignatureAlgorithm.pszObjId = CryptoApiMethods.szOID_OIWSEC_sha1RSASign;
                //certInfo.SignatureAlgorithm.pszObjId = CryptoApiMethods.szOID_RSA_SHA1RSA;
                //certInfo.SignatureAlgorithm.pszObjId = CryptoApiMethods.szOID_RSA_SHA512RSA;
                certInfo.SignatureAlgorithm.pszObjId = HashAlgorithmToOID(hashAlgorithm);

                // Add extension fields
                publicKeyInfoPtr = ExportPublicKeyInfo(key);
                certInfo.SubjectPublicKeyInfo = (CryptoApiMethods.CERT_PUBLIC_KEY_INFO)Marshal.PtrToStructure(publicKeyInfoPtr, typeof(CryptoApiMethods.CERT_PUBLIC_KEY_INFO));

                newExts = new List<X509Extension>();

                if (extensions != null)
                {
                    // Filter out some extensions we don't want
                    newExts.AddRange(
                        extensions.Cast<X509Extension>().Where(
                        x =>
                           !x.Oid.Value.Equals(CryptoApiMethods.szOID_AUTHORITY_KEY_IDENTIFIER)
                        && !x.Oid.Value.Equals(CryptoApiMethods.szOID_SUBJECT_KEY_IDENTIFIER)
                        && !x.Oid.Value.Equals(CryptoApiMethods.szOID_AUTHORITY_KEY_IDENTIFIER2)));
                }

                if (issuer != null)
                {
                    newExts.Add(CreateAuthorityKeyInfo2(issuer.GetSerialNumber(), issuer.SubjectName, (RSACryptoServiceProvider)issuer.PrivateKey));
                }
                else
                {
                    newExts.Add(CreateAuthorityKeyInfo2(serialNumber, subjectName, key));
                }

                newExts.Add(new X509SubjectKeyIdentifierExtension(HashPublicKeyInfo(key), false));

                certInfo.rgExtension = MarshalExtensions(newExts.ToArray());
                certInfo.cExtension = (uint)newExts.Count;

                byte[] certData = EncodeAndSignCertInfo(issuer != null ? issuer.PrivateKey as RSACryptoServiceProvider : key, certInfo, hashAlgorithm);

                cert = new X509Certificate2(certData, (string)null, X509KeyStorageFlags.Exportable);
                cert.PrivateKey = key;
            }
            finally
            {
                if (certInfo.rgExtension != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(certInfo.rgExtension);
                }

                if (certInfo.Subject != null)
                {
                    certInfo.Subject.Release();
                }

                if (certInfo.Issuer != null)
                {
                    certInfo.Issuer.Release();
                }

                if (publicKeyInfoPtr != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(publicKeyInfoPtr);
                }
            }

            return cert;
        }