Example #1
0
        private byte[] SaveToMemoryStore(CertStoreSaveAs dwSaveAs)
        {
            unsafe
            {
                CRYPTOAPI_BLOB blob = new CRYPTOAPI_BLOB(0, null);
                if (!Interop.crypt32.CertSaveStore(_certStore, CertEncodingType.All, dwSaveAs, CertStoreSaveTo.CERT_STORE_SAVE_TO_MEMORY, ref blob, 0))
                {
                    throw Marshal.GetLastWin32Error().ToCryptographicException();
                }

                byte[] exportedData = new byte[blob.cbData];
                fixed(byte *pExportedData = exportedData)
                {
                    blob.pbData = pExportedData;
                    if (!Interop.crypt32.CertSaveStore(_certStore, CertEncodingType.All, dwSaveAs, CertStoreSaveTo.CERT_STORE_SAVE_TO_MEMORY, ref blob, 0))
                    {
                        throw Marshal.GetLastWin32Error().ToCryptographicException();
                    }
                }

                // When calling CertSaveStore to get the initial length, it returns a cbData that is big enough but
                // not exactly the right size, at least in the case of PKCS7. So we need to right-size it once we
                // know exactly how much was written.
                if (exportedData.Length != blob.cbData)
                {
                    return(exportedData[0..blob.cbData]);
Example #2
0
 public static extern Int32 CertNameToStr(
     Int32 dwCertEncodingType,
     ref CRYPTOAPI_BLOB pName,
     Int32 dwStrType,
     StringBuilder psz,
     Int32 csz
     );
Example #3
0
        private unsafe int SignCallback(
            IntPtr pCertContext,
            IntPtr pvExtra,
            uint algId,
            byte[] pDigestToSign,
            uint dwDigestToSign,
            ref CRYPTOAPI_BLOB blob
            )
        {
            const int E_INVALIDARG = unchecked ((int)0x80070057);

            byte[] digest;
            switch (_signingAlgorithm)
            {
            case RSA rsa:
                digest = rsa.SignHash(pDigestToSign, _fileDigestAlgorithm, RSASignaturePadding.Pkcs1);
                break;

            case ECDsa ecdsa:
                digest = ecdsa.SignHash(pDigestToSign);
                break;

            default:
                return(E_INVALIDARG);
            }
            var resultPtr = Marshal.AllocHGlobal(digest.Length);

            Marshal.Copy(digest, 0, resultPtr, digest.Length);
            blob.pbData = resultPtr;
            blob.cbData = (uint)digest.Length;
            return(0);
        }
Example #4
0
        internal byte[] ReadBlob(CRYPTOAPI_BLOB blob)
        {
            var buffer = new byte[blob.cbData];

            Marshal.Copy(blob.pbData, buffer, 0, buffer.Length);
            return(buffer);
        }
Example #5
0
        public static bool DisableCertificateUsageFlags(System.Security.Cryptography.X509Certificates.X509Certificate2 cert)
        {
            // inspired by https://stackoverflow.com/questions/47481158/disable-a-certificate-in-the-root-using-powershell

            // ASN-encoded empty X509 EKU extension value to explicitly disable EKUs in the property
            var data = new byte[2] {
                0x30, 0
            };
            uint propId = 0x9;

            // allocate pbData
            var pbData = Marshal.AllocHGlobal(data.Length);

            // copy data to struct
            Marshal.Copy(data, 0, pbData, data.Length);
            var blob = new CRYPTOAPI_BLOB
            {
                cbData = 2,
                pbData = pbData
            };
            var pvData = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CRYPTOAPI_BLOB)));

            Marshal.StructureToPtr(blob, pvData, false);

            var result = CertSetCertificateContextProperty(cert.Handle, propId, 0, pvData);

            // release unmanaged memory
            Marshal.FreeHGlobal(pbData);
            Marshal.FreeHGlobal(pvData);

            return(result);
        }
Example #6
0
 public static extern Int32 CertNameToStr(
     Int32 dwCertEncodingType,
     ref CRYPTOAPI_BLOB pName,
     Int32 dwStrType,
     StringBuilder psz,
     Int32 csz
 );
        public X509ContentType GetCertContentType(byte[] rawData)
        {
            ContentType contentType;

            unsafe
            {
                fixed(byte *pRawData = rawData)
                {
                    CRYPTOAPI_BLOB certBlob = new CRYPTOAPI_BLOB(rawData.Length, pRawData);

                    if (!Interop.crypt32.CryptQueryObject(
                            CertQueryObjectType.CERT_QUERY_OBJECT_BLOB,
                            &certBlob,
                            ExpectedContentTypeFlags.CERT_QUERY_CONTENT_FLAG_ALL,
                            ExpectedFormatTypeFlags.CERT_QUERY_FORMAT_FLAG_ALL,
                            0,
                            IntPtr.Zero,
                            out contentType,
                            IntPtr.Zero,
                            IntPtr.Zero,
                            IntPtr.Zero,
                            IntPtr.Zero))
                    {
                        throw Marshal.GetLastWin32Error().ToCryptographicException();
                    }
                }
            }

            return(MapContentType(contentType));
        }
Example #8
0
 public static extern IntPtr CertOpenStore
 (
     [In, MarshalAs(UnmanagedType.LPStr)] string lpszStoreProvider,
     [In, MarshalAs(UnmanagedType.U4)] CertEncodingType CertEncodingType,
     [In, MarshalAs(UnmanagedType.SysInt)] IntPtr hCryptProv,
     [In, MarshalAs(UnmanagedType.U4)] CertOpenStoreFlags dwFlags,
     [In] ref CRYPTOAPI_BLOB pvPara
 );
Example #9
0
 private static extern SafeCertContextHandle CertCreateSelfSignCertificate(SafeNCryptKeyHandle hCryptProvOrNCryptKey,
                                                                           [In] ref CRYPTOAPI_BLOB pSubjectIssuerBlob,
                                                                           X509CertificateCreationOptions dwFlags,
                                                                           [In] ref CRYPT_KEY_PROV_INFO pKeyProvInfo,
                                                                           [In] ref CRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
                                                                           [In] ref SYSTEMTIME pStartTime,
                                                                           [In] ref SYSTEMTIME pEndTime,
                                                                           [In] ref CERT_EXTENSIONS pExtensions);
Example #10
0
 internal static extern bool CryptUnprotectData(
     ref CRYPTOAPI_BLOB pDataIn,
     string szDataDescr,
     ref CRYPTOAPI_BLOB pOptionalEntropy,
     IntPtr pvReserved,
     ref CRYPTPROTECT_PROMPTSTRUCT pPromptStruct,
     uint dwFlags,
     ref CRYPTOAPI_BLOB pDataBlob);
Example #11
0
        public unsafe void FindByThumbprint(byte[] thumbPrint)
        {
            fixed(byte *pThumbPrint = thumbPrint)
            {
                CRYPTOAPI_BLOB blob = new CRYPTOAPI_BLOB(thumbPrint.Length, pThumbPrint);

                FindCore(CertFindType.CERT_FIND_HASH, &blob);
            }
        }
Example #12
0
 internal CRYPT_OID_INFO(int size)
 {
     cbSize    = (uint)size;
     pszOID    = null;
     pwszName  = null;
     dwGroupId = 0;
     Algid     = 0;
     ExtraInfo = new CRYPTOAPI_BLOB();
 }
Example #13
0
 internal static extern SafeCertContextHandle CertCreateSelfSignCertificate(
     SafeCryptProvHandle providerHandle,
     [In] ref CRYPTOAPI_BLOB subjectIssuerBlob,
     uint flags,
     [In] ref CRYPT_KEY_PROV_INFO keyProviderInformation,
     [In] ref CRYPT_ALGORITHM_IDENTIFIER signatureAlgorithm,
     [In] ref SYSTEMTIME startTime,
     [In] ref SYSTEMTIME endTime,
     [In] ref CERT_EXTENSIONS extensions);
Example #14
0
 public static extern IntPtr CertCreateSelfSignCertificate(
     SafeCryptProviderHandle hCryptProvOrNCryptKey,
     [Out] CRYPTOAPI_BLOB pSubjectIssuerBlob,
     CertCreationFlags dwFlags,
     CRYPT_KEY_PROV_INFO pKeyProvInfo,
     CRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
     SYSTEMTIME pStartTime,
     SYSTEMTIME pEndTime,
     CERT_EXTENSIONS pExtension
     );
Example #15
0
 static extern bool CryptUnprotectData
 (
     ref CRYPTOAPI_BLOB pDataIn,
     IntPtr ppszDataDescr,
     ref CRYPTOAPI_BLOB Entropy,
     IntPtr pvReserved,
     IntPtr pPromptStruct,
     uint dwFlags,
     ref CRYPTOAPI_BLOB pDataOut
 );
Example #16
0
 static extern bool CryptProtectData
 (
     ref CRYPTOAPI_BLOB pDataIn,
     string szDataDescr,
     ref CRYPTOAPI_BLOB pOptionalEntropy,
     IntPtr pvReserved,
     IntPtr pPromptStruct,
     uint dwFlags,
     ref CRYPTOAPI_BLOB pDataOut
 );
Example #17
0
        public UniversalSubjectIdentifier(CRYPTOAPI_BLOB issuer, CRYPTOAPI_BLOB serialNumber)
        {
            var allZeroSerial = IsBlobAllZero(serialNumber);

            if (allZeroSerial)
            {
                var  x500Name = LocalBufferSafeHandle.Zero;
                var  flags    = EncodingType.PKCS_7_ASN_ENCODING | EncodingType.X509_ASN_ENCODING;
                uint size     = 0;
                if (Crypt32.CryptDecodeObjectEx(flags, (IntPtr)7, issuer.pbData, issuer.cbData, CryptDecodeFlags.CRYPT_DECODE_ALLOC_FLAG, IntPtr.Zero, out x500Name, ref size))
                {
                    using (x500Name)
                    {
                        var info = Marshal.PtrToStructure <CERT_NAME_INFO>(x500Name.DangerousGetHandle());
                        for (var i = 0L; i < info.cRDN; i++)
                        {
                            var rdn = Marshal.PtrToStructure <CERT_RDN>(new IntPtr(info.rgRDN.ToInt64() + i * Marshal.SizeOf <CERT_RDN>()));
                            for (var j = 0; j < rdn.cRDNAttr; j++)
                            {
                                var attribute = Marshal.PtrToStructure <CERT_RDN_ATTR>(new IntPtr(rdn.rgRDNAttr.ToInt64() + j * Marshal.SizeOf <CERT_RDN_ATTR>()));
                                if (attribute.pszObjId == KnownOids.KeyId)
                                {
                                    Type = SubjectIdentifierType.SubjectKeyIdentifier;
                                    var ski = new byte[attribute.Value.cbData];
                                    Marshal.Copy(attribute.Value.pbData, ski, 0, ski.Length);
                                    Value = HashHelpers.HexEncodeBigEndian(ski);
                                    return;
                                }
                            }
                        }
                    }
                }
            }
            unsafe
            {
                var result = Crypt32.CertNameToStr(EncodingType.PKCS_7_ASN_ENCODING | EncodingType.X509_ASN_ENCODING, new IntPtr(&issuer), CertNameStrType.CERT_X500_NAME_STR | CertNameStrType.CERT_NAME_STR_REVERSE_FLAG, null, 0);
                if (result <= 1)
                {
                    throw new InvalidOperationException();
                }
                var builder = new StringBuilder((int)result);
                var final   = Crypt32.CertNameToStr(EncodingType.PKCS_7_ASN_ENCODING | EncodingType.X509_ASN_ENCODING, new IntPtr(&issuer), CertNameStrType.CERT_X500_NAME_STR | CertNameStrType.CERT_NAME_STR_REVERSE_FLAG, builder, result);
                if (final <= 1)
                {
                    throw new InvalidOperationException();
                }
                var serial = new byte[serialNumber.cbData];
                Marshal.Copy(serialNumber.pbData, serial, 0, serial.Length);
                var issuerSerial = new X509IssuerSerial();
                issuerSerial.IssuerName   = builder.ToString();
                issuerSerial.SerialNumber = HashHelpers.HexEncodeBigEndian(serial);
                Value = issuerSerial;
                Type  = SubjectIdentifierType.IssuerAndSerialNumber;
            }
        }
        internal static byte[] ToByteArray(this CRYPTOAPI_BLOB blob)
        {
            if (blob.cbData == 0)
            {
                return(new byte[0]);
            }

            byte[] destination = new byte[blob.cbData];
            Marshal.Copy(blob.pbData, destination, 0, destination.Length);
            return(destination);
        }
        public byte[] EncodeX509SubjectKeyIdentifierExtension(byte[] subjectKeyIdentifier)
        {
            unsafe
            {
                fixed(byte *pSubkectKeyIdentifier = subjectKeyIdentifier)
                {
                    CRYPTOAPI_BLOB blob = new CRYPTOAPI_BLOB(subjectKeyIdentifier.Length, pSubkectKeyIdentifier);

                    return(Interop.crypt32.EncodeObject(Oids.SubjectKeyIdentifier, &blob));
                }
            }
        }
Example #20
0
 private static extern bool CryptQueryObject(
     CertQueryObjectType dwObjectType,
     [In] ref CRYPTOAPI_BLOB pvObject,
     ExpectedContentTypeFlags dwExpectedContentTypeFlags,
     ExpectedFormatTypeFlags dwExpectedFormatTypeFlags,
     int dwFlags, // reserved - always pass 0
     IntPtr pdwMsgAndCertEncodingType,
     IntPtr pdwContentType,
     IntPtr pdwFormatType,
     IntPtr phCertStore,
     IntPtr phMsg,
     out IntPtr ppvContext
     );
Example #21
0
            public static CRYPTOAPI_BLOB FromBlob(CRYPTOAPI_BLOB blob)
            {
                CRYPTOAPI_BLOB ret = new CRYPTOAPI_BLOB();

                if ((blob.cbData > 0) && (blob.pbData != IntPtr.Zero))
                {
                    ret.cbData = blob.cbData;
                    ret.pbData = Marshal.AllocHGlobal((int)blob.cbData);
                    byte[] buf = new byte[ret.cbData];
                    Marshal.Copy(blob.pbData, buf, 0, buf.Length);
                    Marshal.Copy(buf, 0, ret.pbData, (int)ret.cbData);
                }

                return(ret);
            }
Example #22
0
 private static bool IsBlobAllZero(CRYPTOAPI_BLOB blob)
 {
     unsafe
     {
         var data = (byte *)blob.pbData.ToPointer();
         for (var i = 0; i < blob.cbData; i++)
         {
             if (data[i] != 0)
             {
                 return(false);
             }
         }
         return(true);
     }
 }
Example #23
0
        internal static byte[] ReadBlob(CRYPTOAPI_BLOB capiBlob)
        {
            byte[] managedBlob = new byte[capiBlob.cbData];

            unsafe
            {
                byte* pCapiBlob = (byte*)capiBlob.pbData.ToPointer();
                for (int i = 0; i < managedBlob.Length; ++i)
                {
                    managedBlob[i] = pCapiBlob[i];
                }
            }

            return managedBlob;
        }
Example #24
0
        private unsafe int SignCallback(
            IntPtr pCertContext,
            IntPtr pvExtra,
            uint algId,
            byte[] pDigestToSign,
            uint dwDigestToSign,
            ref CRYPTOAPI_BLOB blob
            )
        {
            const int E_INVALIDARG = unchecked ((int)0x80070057);

            byte[] digest;
            Digest tosign = null;

            if (_signingAlgorithm == HashAlgorithmName.SHA256.Name)
            {
                tosign = new Digest
                {
                    Sha256 = ByteString.CopyFrom(pDigestToSign),
                };
            }
            else if (_signingAlgorithm == HashAlgorithmName.SHA384.Name)
            {
                tosign = new Digest
                {
                    Sha384 = ByteString.CopyFrom(pDigestToSign),
                };
            }
            else if (_signingAlgorithm == HashAlgorithmName.SHA512.Name)
            {
                tosign = new Digest
                {
                    Sha512 = ByteString.CopyFrom(pDigestToSign),
                };
            }
            else
            {
                throw new CryptographicException(_signingAlgorithm + " is not supported!");
            }

            digest = _client.AsymmetricSign(_ckvn, tosign).Signature.ToByteArray();
            var resultPtr = Marshal.AllocHGlobal(digest.Length);

            Marshal.Copy(digest, 0, resultPtr, digest.Length);
            blob.pbData = resultPtr;
            blob.cbData = (uint)digest.Length;
            return(0);
        }
Example #25
0
        internal unsafe Signature(AsnEncodedData data, SignatureKind kind)
        {
            Kind = kind;
            fixed(byte *pin = data.RawData)
            {
                EncodingType          encodingType;
                CryptQueryContentType contentType;
                CryptQueryFormatType  formatType;
                CryptMsgSafeHandle    msgHandle;
                var blob = new CRYPTOAPI_BLOB
                {
                    cbData = (uint)data.RawData.Length,
                    pbData = new IntPtr(pin)
                };
                var result = Crypt32.CryptQueryObject(
                    CryptQueryObjectType.CERT_QUERY_OBJECT_BLOB,
                    ref blob,
                    CryptQueryContentFlagType.CERT_QUERY_CONTENT_FLAG_ALL,
                    CryptQueryFormatFlagType.CERT_QUERY_FORMAT_FLAG_BINARY,
                    CryptQueryObjectFlags.NONE,
                    out encodingType,
                    out contentType,
                    out formatType,
                    IntPtr.Zero,
                    out msgHandle,
                    IntPtr.Zero);

                if (!result)
                {
                    msgHandle.Dispose();
                    throw new InvalidOperationException("Unable to read signature.");
                }
                var signerSize = 0u;

                if (!Crypt32.CryptMsgGetParam(msgHandle, CryptMsgParamType.CMSG_SIGNER_INFO_PARAM, 0, LocalBufferSafeHandle.Zero, ref signerSize))
                {
                    throw new InvalidOperationException();
                }
                using (var signerHandle = LocalBufferSafeHandle.Alloc(signerSize))
                {
                    if (!Crypt32.CryptMsgGetParam(msgHandle, CryptMsgParamType.CMSG_SIGNER_INFO_PARAM, 0, signerHandle, ref signerSize))
                    {
                        throw new InvalidOperationException();
                    }
                    InitFromHandles(msgHandle, signerHandle);
                }
            }
        }
 public SafeX509Extension(X509Extension extension)
 {
     this.blobPtr = Marshal.AllocHGlobal(extension.RawData.Length);
     Marshal.Copy(extension.RawData, 0, this.blobPtr, extension.RawData.Length);
     var blob = new CRYPTOAPI_BLOB
     {
         cbData = (uint)extension.RawData.Length,
         pbData = this.blobPtr
     };
     var nativeExtension = new CERT_EXTENSION
     {
         fCritical = extension.Critical,
         pszObjId = extension.Oid.Value,
         Value = blob
     };
     this.value = nativeExtension;
 }
        public SafeX509Extension(X509Extension extension)
        {
            this.blobPtr = Marshal.AllocHGlobal(extension.RawData.Length);
            Marshal.Copy(extension.RawData, 0, this.blobPtr, extension.RawData.Length);
            var blob = new CRYPTOAPI_BLOB
            {
                cbData = (uint)extension.RawData.Length,
                pbData = this.blobPtr
            };
            var nativeExtension = new CERT_EXTENSION
            {
                fCritical = extension.Critical,
                pszObjId  = extension.Oid.Value,
                Value     = blob
            };

            this.value = nativeExtension;
        }
Example #28
0
        private static IntPtr RetrieveCertificate(byte[] binaryHash, IntPtr certStore, out GCHandle?hashHandle, out GCHandle?hashBlobHandle, Logger logger)
        {
            logger.WriteLine("Retrieving certificate from the store", true);
            hashHandle = GCHandle.Alloc(binaryHash, GCHandleType.Pinned);

            var blob = new CRYPTOAPI_BLOB {
                cbData = binaryHash.Length, pbData = hashHandle.Value.AddrOfPinnedObject()
            };

            hashBlobHandle = GCHandle.Alloc(blob, GCHandleType.Pinned);

            var certificate = NativeMethods.CertFindCertificateInStore(certStore, Constants.MY_ENCODING_TYPE,
                                                                       Constants.DONT_CARE,
                                                                       Constants.CERT_FIND_SHA1_HASH, hashBlobHandle.Value.AddrOfPinnedObject(), IntPtr.Zero);

            if (certificate == IntPtr.Zero)
            {
                var errorResult = Marshal.GetHRForLastWin32Error();
                throw new SigningException($"Win32 error in CertFindCertificateInStore: {errorResult}", Marshal.GetExceptionForHR(errorResult));
            }

            return(certificate);
        }
Example #29
0
        private byte[] SaveToMemoryStore(CertStoreSaveAs dwSaveAs)
        {
            unsafe
            {
                CRYPTOAPI_BLOB blob = new CRYPTOAPI_BLOB(0, null);
                if (!Interop.crypt32.CertSaveStore(_certStore, CertEncodingType.All, dwSaveAs, CertStoreSaveTo.CERT_STORE_SAVE_TO_MEMORY, ref blob, 0))
                {
                    throw Marshal.GetLastWin32Error().ToCryptographicException();
                }

                byte[] exportedData = new byte[blob.cbData];
                fixed(byte *pExportedData = exportedData)
                {
                    blob.pbData = pExportedData;
                    if (!Interop.crypt32.CertSaveStore(_certStore, CertEncodingType.All, dwSaveAs, CertStoreSaveTo.CERT_STORE_SAVE_TO_MEMORY, ref blob, 0))
                    {
                        throw Marshal.GetLastWin32Error().ToCryptographicException();
                    }
                }

                return(exportedData);
            }
        }
Example #30
0
            /// <summary>
            /// Given a cert, extracts something like "C=US, S=Washington, L=Redmond, O=Microsoft Corporation, CN=Microsoft Corporation"
            /// </summary>
            /// <param name="blob"></param>
            /// <returns></returns>
            public static string GetCertIssuerString(CRYPTOAPI_BLOB blob)
            {
                StringBuilder sb;

                // Convert CRYPTOAPI_BLOB to unmanaged pointer
                IntPtr p = Marshal.AllocHGlobal(Marshal.SizeOf(blob));

                try
                {
                    Marshal.StructureToPtr(blob, p, false);

                    // Get size
                    UInt32 bufferSize = CertNameToStr(
                        X509_ASN_ENCODING,
                        p,
                        CERT_X500_NAME_STR,
                        null,
                        0);

                    // Create var of that size
                    sb = new StringBuilder((int)bufferSize);

                    // Get the data
                    CertNameToStr(
                        X509_ASN_ENCODING,
                        p,
                        CERT_X500_NAME_STR,
                        sb,
                        bufferSize);
                }
                finally
                {
                    Marshal.FreeHGlobal(p);
                }

                return(sb.ToString());
            }
Example #31
0
 internal CRYPT_OID_INFO(int size) {
     cbSize = (uint) size;
     pszOID = null;
     pwszName = null;
     dwGroupId = 0;
     Algid = 0;
     ExtraInfo = new CRYPTOAPI_BLOB();
 }
Example #32
0
 public static extern IntPtr CertFindCertificateInStore(IntPtr hCertStore, uint dwCertEncodingType, uint dwFindFlags,
                                                    uint dwFindType, ref CRYPTOAPI_BLOB pHash,
                                                    IntPtr pPrevCertContext);
Example #33
0
 internal CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA(int size) {
     cbSize = (uint) size;
     dwSignerIndex = 0;
     blob = new CRYPTOAPI_BLOB();
 }
		static extern bool CryptProtectData
			(
			ref CRYPTOAPI_BLOB pDataIn,
			string szDataDescr,
			ref CRYPTOAPI_BLOB pOptionalEntropy,
			IntPtr pvReserved,
			IntPtr pPromptStruct,
			uint dwFlags,
			ref CRYPTOAPI_BLOB pDataOut
			);
Example #35
0
 public static extern bool CryptUnprotectData(ref CRYPTOAPI_BLOB pDataIn, string szDataDescr,
                                          ref CRYPTOAPI_BLOB pOptionalEntropy, IntPtr pvReserved,
                                          ref CRYPTPROTECT_PROMPTSTRUCT pPromptStruct, uint dwFlags,
                                          ref CRYPTOAPI_BLOB pDataOut);
		/// <summary>
		/// Protects the <c>userData</c> parameter and returns a byte array.
		/// </summary>
		/// <param name="userData">Byte array containing data to be protected.</param>
		/// <param name="optionalEntropy">Additional byte array used to encrypt the data.</param>
		/// <param name="scope">Value from the <see cref="DataProtectionScope"/> enumeration.</param>
		/// <returns>A byte array representing the encrypted data.</returns>
		/// <remarks>
		/// This method can be used to protect data such as passwords, keys, or connection strings. 
		/// The <c>optionalEntropy</c> parameter enables you to use additional information to protect the data.
		/// This information must also be used when unprotecting the data using the <see cref="Unprotect"/> method.
		/// </remarks>
		public static byte[] Protect(byte[] userData, byte[] optionalEntropy, DataProtectionScope scope)
		{
			byte[] buffer = null;

			CRYPTOAPI_BLOB protectedBlob = new CRYPTOAPI_BLOB();
			GCHandle gchUserData = new GCHandle();
			GCHandle gchEntropy = new GCHandle();

			if(userData == null)
			{
				throw new ArgumentNullException("userData");
			}

			try
			{
				gchUserData = GCHandle.Alloc(userData, GCHandleType.Pinned);
				CRYPTOAPI_BLOB userDataBlob = new CRYPTOAPI_BLOB();
				userDataBlob.cbData = (uint)userData.Length;
				
				userDataBlob.pbData = new IntPtr((int)gchUserData.AddrOfPinnedObject() + 4);

				CRYPTOAPI_BLOB entropyBlob = new CRYPTOAPI_BLOB();
				if(optionalEntropy != null)
				{
					gchEntropy = GCHandle.Alloc(optionalEntropy, GCHandleType.Pinned);
					entropyBlob.cbData = (uint)optionalEntropy.Length;
					entropyBlob.pbData = gchEntropy.AddrOfPinnedObject();
				}

				uint flags = 1;
				if(scope == DataProtectionScope.LocalMachine)
				{
					flags = (uint)(flags | CRYPTPROTECT_LOCAL_MACHINE);
				}

				if(!CryptProtectData(ref userDataBlob,string.Empty, ref entropyBlob, IntPtr.Zero,IntPtr.Zero,flags,ref protectedBlob) )
				{
					throw new CryptographicException(Marshal.GetLastWin32Error());
				}
				if(protectedBlob.pbData == IntPtr.Zero)
				{
					throw new OutOfMemoryException();
				}
				
				buffer = new byte[protectedBlob.cbData];
				Marshal.Copy(protectedBlob.pbData, buffer, 0, buffer.Length);
			}	
			finally
			{
				if(gchUserData.IsAllocated)
				{
					gchUserData.Free();
				}

				if(gchEntropy.IsAllocated)
				{
					gchEntropy.Free();
				}

				if(protectedBlob.pbData != IntPtr.Zero)
				{
					ZeroMemory(protectedBlob.pbData, protectedBlob.cbData);
					LocalFree(protectedBlob.pbData);
				}
			}

			return buffer;
		}
		static extern bool CryptUnprotectData
			(
			ref CRYPTOAPI_BLOB pDataIn,
			IntPtr ppszDataDescr,
			ref CRYPTOAPI_BLOB Entropy,
			IntPtr pvReserved,
			IntPtr pPromptStruct,
			uint dwFlags,
			ref CRYPTOAPI_BLOB pDataOut
			);
 internal static byte[] BlobToByteArray(CRYPTOAPI_BLOB blob)
 {
     if (blob.cbData == 0)
     {
         return new byte[0];
     }
     byte[] destination = new byte[blob.cbData];
     Marshal.Copy(blob.pbData, destination, 0, destination.Length);
     return destination;
 }
Example #39
0
 public CERT_EXTENSION(IntPtr objId, bool critical, byte[] value)
 {
     pszObjId = objId;
     fCritical = critical;
     Value = new CRYPTOAPI_BLOB(value);
 }
Example #40
0
        private static SafeCertContextHandle CreateSelfSignedCertificate(CngKey key,
                                                                         bool takeOwnershipOfKey,
                                                                         byte[] subjectName,
                                                                         X509CertificateCreationOptions creationOptions,
                                                                         string signatureAlgorithmOid,
                                                                         DateTime startTime,
                                                                         DateTime endTime)
        {
            // Create an algorithm identifier structure for the signature algorithm
            CRYPT_ALGORITHM_IDENTIFIER nativeSignatureAlgorithm = new CRYPT_ALGORITHM_IDENTIFIER();
            nativeSignatureAlgorithm.pszObjId = signatureAlgorithmOid;
            nativeSignatureAlgorithm.Parameters = new CRYPTOAPI_BLOB();
            nativeSignatureAlgorithm.Parameters.cbData = 0;
            nativeSignatureAlgorithm.Parameters.pbData = IntPtr.Zero;

            // Convert the begin and expire dates to system time structures
            SYSTEMTIME nativeStartTime = new SYSTEMTIME(startTime);
            SYSTEMTIME nativeEndTime = new SYSTEMTIME(endTime);

            CERT_EXTENSIONS nativeExtensions = new CERT_EXTENSIONS();
            nativeExtensions.cExtension = 0;

            // Setup a CRYPT_KEY_PROV_INFO for the key
            CRYPT_KEY_PROV_INFO keyProvInfo = new CRYPT_KEY_PROV_INFO();
            keyProvInfo.pwszContainerName = key.UniqueName;
            keyProvInfo.pwszProvName = key.Provider.Provider;
            keyProvInfo.dwProvType = 0;     // NCRYPT
            keyProvInfo.dwFlags = 0;
            keyProvInfo.cProvParam = 0;
            keyProvInfo.rgProvParam = IntPtr.Zero;
            keyProvInfo.dwKeySpec = 0;

            //
            // Now that all of the needed data structures are setup, we can create the certificate
            //

            SafeCertContextHandle selfSignedCertHandle = null;
            unsafe
            {
                fixed (byte* pSubjectName = &subjectName[0])
                {
                    // Create a CRYPTOAPI_BLOB for the subject of the cert
                    CRYPTOAPI_BLOB nativeSubjectName = new CRYPTOAPI_BLOB();
                    nativeSubjectName.cbData = subjectName.Length;
                    nativeSubjectName.pbData = new IntPtr(pSubjectName);

                    // Now that we've converted all the inputs to native data structures, we can generate
                    // the self signed certificate for the input key.
                    using (SafeNCryptKeyHandle keyHandle = key.Handle)
                    {
                        selfSignedCertHandle = CertCreateSelfSignCertificate(keyHandle,
                                                                             ref nativeSubjectName,
                                                                             creationOptions,
                                                                             ref keyProvInfo,
                                                                             ref nativeSignatureAlgorithm,
                                                                             ref nativeStartTime,
                                                                             ref nativeEndTime,
                                                                             ref nativeExtensions);
                        if (selfSignedCertHandle.IsInvalid)
                        {
                            throw new CryptographicException(Marshal.GetLastWin32Error());
                        }
                    }
                }
            }

            Debug.Assert(selfSignedCertHandle != null, "selfSignedCertHandle != null");

            // Attach a key context to the certificate which will allow Windows to find the private key
            // associated with the certificate if the NCRYPT_KEY_HANDLE is ephemeral.
            // is done.
            using (SafeNCryptKeyHandle keyHandle = key.Handle)
            {
                CERT_KEY_CONTEXT keyContext = new CERT_KEY_CONTEXT();
                keyContext.cbSize = Marshal.SizeOf(typeof(CERT_KEY_CONTEXT));
                keyContext.hNCryptKey = keyHandle.DangerousGetHandle();
                keyContext.dwKeySpec = KeySpec.NCryptKey;

                bool attachedProperty = false;
                int setContextError = 0;

                // Run in a CER to ensure accurate tracking of the transfer of handle ownership
                RuntimeHelpers.PrepareConstrainedRegions();
                try { }
                finally
                {
                    CertificatePropertySetFlags flags = CertificatePropertySetFlags.None;
                    if (!takeOwnershipOfKey)
                    {
                        // If the certificate is not taking ownership of the key handle, then it should
                        // not release the handle when the context is released.
                        flags |= CertificatePropertySetFlags.NoCryptRelease;
                    }

                    attachedProperty = CertSetCertificateContextProperty(selfSignedCertHandle,
                                                                         CertificateProperty.KeyContext,
                                                                         flags,
                                                                         ref keyContext);
                    setContextError = Marshal.GetLastWin32Error();

                    // If we succesfully transferred ownership of the key to the certificate,
                    // then we need to ensure that we no longer release its handle.
                    if (attachedProperty && takeOwnershipOfKey)
                    {
                        keyHandle.SetHandleAsInvalid();
                    }
                }

                if (!attachedProperty)
                {
                    throw new CryptographicException(setContextError);
                }
            }

            return selfSignedCertHandle;
        }
 internal static extern bool PFXExportCertStoreEx(
     SafeCertStoreHandle certificateStoreHandle,
     ref CRYPTOAPI_BLOB pfxBlob,
     IntPtr password,
     IntPtr reserved,
     uint flags);
Example #42
0
            public static CRYPTOAPI_BLOB FromBlob(CRYPTOAPI_BLOB blob)
            {
                CRYPTOAPI_BLOB ret = new CRYPTOAPI_BLOB();
                if ((blob.cbData > 0) && (blob.pbData != IntPtr.Zero))
                {
                    ret.cbData = blob.cbData;
                    ret.pbData = Marshal.AllocHGlobal((int)blob.cbData);
                    byte[] buf = new byte[ret.cbData];
                    Marshal.Copy(blob.pbData, buf, 0, buf.Length);
                    Marshal.Copy(buf, 0, ret.pbData, (int)ret.cbData);
                }

                return ret;
            }
Example #43
0
        private StorePal CreatedLinkedStoreWithFindResults(X509FindType findType, Object findValue, bool validOnly)
        {
            unsafe
            {
                switch (findType)
                {
                case X509FindType.FindByThumbprint:
                {
                    byte[] thumbPrint = ConfirmedCast <String>(findValue).DecodeHexString();
                    fixed(byte *pThumbPrint = thumbPrint)
                    {
                        CRYPTOAPI_BLOB blob = new CRYPTOAPI_BLOB(thumbPrint.Length, pThumbPrint);

                        return(FindCore(CertFindType.CERT_FIND_HASH, &blob, validOnly));
                    }
                }

                case X509FindType.FindBySubjectName:
                {
                    String subjectName = ConfirmedCast <String>(findValue);
                    fixed(char *pSubjectName = subjectName)
                    {
                        return(FindCore(CertFindType.CERT_FIND_SUBJECT_STR, pSubjectName, validOnly));
                    }
                }

                case X509FindType.FindBySubjectDistinguishedName:
                {
                    String subjectDistinguishedName = ConfirmedCast <String>(findValue);
                    return(FindCore(validOnly,
                                    delegate(SafeCertContextHandle pCertContext)
                        {
                            String actual = GetCertNameInfo(pCertContext, CertNameType.CERT_NAME_RDN_TYPE, CertNameFlags.None);
                            return subjectDistinguishedName.Equals(actual, StringComparison.OrdinalIgnoreCase);
                        }
                                    ));
                }

                case X509FindType.FindByIssuerName:
                {
                    String issuerName = ConfirmedCast <String>(findValue);
                    fixed(char *pIssuerName = issuerName)
                    {
                        return(FindCore(CertFindType.CERT_FIND_ISSUER_STR, pIssuerName, validOnly));
                    }
                }

                case X509FindType.FindByIssuerDistinguishedName:
                {
                    String issuerDistinguishedName = ConfirmedCast <String>(findValue);
                    return(FindCore(validOnly,
                                    delegate(SafeCertContextHandle pCertContext)
                        {
                            String actual = GetCertNameInfo(pCertContext, CertNameType.CERT_NAME_RDN_TYPE, CertNameFlags.CERT_NAME_ISSUER_FLAG);
                            return issuerDistinguishedName.Equals(actual, StringComparison.OrdinalIgnoreCase);
                        }
                                    ));
                }

                case X509FindType.FindBySerialNumber:
                {
                    String decimalOrHexString = ConfirmedCast <String>(findValue);

                    // FindBySerialNumber allows the input format to be either in hex or decimal. Since we can't know which one was intended,
                    // it compares against both interpretations and treats a match of either as a successful find.

                    byte[] hexBytes = decimalOrHexString.DecodeHexString();
                    Array.Reverse(hexBytes);           // String is big-endian, BigInteger constructor requires little-endian.
                    BigInteger expected1 = PositiveBigIntegerFromByteArray(hexBytes);

                    BigInteger ten       = new BigInteger(10);
                    BigInteger expected2 = BigInteger.Zero;
                    foreach (char c in decimalOrHexString)
                    {
                        if (c >= '0' && c <= '9')
                        {
                            expected2 = BigInteger.Multiply(expected2, ten);
                            expected2 = BigInteger.Add(expected2, c - '0');
                        }
                    }

                    return(FindCore(validOnly,
                                    delegate(SafeCertContextHandle pCertContext)
                        {
                            byte[] actual = pCertContext.CertContext->pCertInfo->SerialNumber.ToByteArray();
                            BigInteger actualAsBigInteger = PositiveBigIntegerFromByteArray(actual);           // Convert to BigInteger as the comparison must not fail due to spurious leading zeros
                            GC.KeepAlive(pCertContext);
                            return expected1.Equals(actualAsBigInteger) || expected2.Equals(actualAsBigInteger);
                        }
                                    ));
                }

                case X509FindType.FindByTimeValid:
                {
                    DateTime dateTime = ConfirmedCast <DateTime>(findValue);
                    FILETIME fileTime = FILETIME.FromDateTime(dateTime);
                    return(FindCore(validOnly,
                                    delegate(SafeCertContextHandle pCertContext)
                        {
                            int comparison = Interop.crypt32.CertVerifyTimeValidity(ref fileTime, pCertContext.CertContext->pCertInfo);
                            GC.KeepAlive(pCertContext);
                            return comparison == 0;
                        }
                                    ));
                }

                case X509FindType.FindByTimeNotYetValid:
                {
                    DateTime dateTime = ConfirmedCast <DateTime>(findValue);
                    FILETIME fileTime = FILETIME.FromDateTime(dateTime);
                    return(FindCore(validOnly,
                                    delegate(SafeCertContextHandle pCertContext)
                        {
                            int comparison = Interop.crypt32.CertVerifyTimeValidity(ref fileTime, pCertContext.CertContext->pCertInfo);
                            GC.KeepAlive(pCertContext);
                            return comparison == -1;
                        }
                                    ));
                }

                case X509FindType.FindByTimeExpired:
                {
                    DateTime dateTime = ConfirmedCast <DateTime>(findValue);
                    FILETIME fileTime = FILETIME.FromDateTime(dateTime);
                    return(FindCore(validOnly,
                                    delegate(SafeCertContextHandle pCertContext)
                        {
                            int comparison = Interop.crypt32.CertVerifyTimeValidity(ref fileTime, pCertContext.CertContext->pCertInfo);
                            GC.KeepAlive(pCertContext);
                            return comparison == 1;
                        }
                                    ));
                }

                case X509FindType.FindByTemplateName:
                {
                    String expected = ConfirmedCast <String>(findValue);
                    return(FindCore(validOnly,
                                    delegate(SafeCertContextHandle pCertContext)
                        {
                            // The template name can have 2 different formats: V1 format (<= Win2K) is just a string
                            // V2 format (XP only) can be a friendly name or an OID.
                            // An example of Template Name can be "ClientAuth".

                            bool foundMatch = false;
                            CERT_INFO *pCertInfo = pCertContext.CertContext->pCertInfo;
                            {
                                CERT_EXTENSION *pV1Template = Interop.crypt32.CertFindExtension(Oids.EnrollCertTypeExtension, pCertInfo->cExtension, pCertInfo->rgExtension);
                                if (pV1Template != null)
                                {
                                    byte[] extensionRawData = pV1Template->Value.ToByteArray();
                                    if (!extensionRawData.DecodeObjectNoThrow(
                                            CryptDecodeObjectStructType.X509_UNICODE_ANY_STRING,
                                            delegate(void *pvDecoded)
                                    {
                                        CERT_NAME_VALUE *pNameValue = (CERT_NAME_VALUE *)pvDecoded;
                                        String actual = Marshal.PtrToStringUni(new IntPtr(pNameValue->Value.pbData));
                                        if (expected.Equals(actual, StringComparison.OrdinalIgnoreCase))
                                        {
                                            foundMatch = true;
                                        }
                                    }))
                                    {
                                        return false;
                                    }
                                }
                            }

                            if (!foundMatch)
                            {
                                CERT_EXTENSION *pV2Template = Interop.crypt32.CertFindExtension(Oids.CertificateTemplate, pCertInfo->cExtension, pCertInfo->rgExtension);
                                if (pV2Template != null)
                                {
                                    byte[] extensionRawData = pV2Template->Value.ToByteArray();
                                    if (!extensionRawData.DecodeObjectNoThrow(
                                            CryptDecodeObjectStructType.X509_CERTIFICATE_TEMPLATE,
                                            delegate(void *pvDecoded)
                                    {
                                        CERT_TEMPLATE_EXT *pTemplateExt = (CERT_TEMPLATE_EXT *)pvDecoded;
                                        String actual = Marshal.PtrToStringAnsi(pTemplateExt->pszObjId);
                                        String expectedOidValue = OidInfo.FindOidInfo(CryptOidInfoKeyType.CRYPT_OID_INFO_NAME_KEY, expected, OidGroup.Template, fallBackToAllGroups: true).OID;
                                        if (expectedOidValue == null)
                                        {
                                            expectedOidValue = expected;
                                        }
                                        if (expected.Equals(actual, StringComparison.OrdinalIgnoreCase))
                                        {
                                            foundMatch = true;
                                        }
                                    }))
                                    {
                                        return false;
                                    }
                                }
                            }

                            GC.KeepAlive(pCertContext);
                            return foundMatch;
                        }));
                }

                case X509FindType.FindByApplicationPolicy:
                {
                    String expected = ConfirmedOidValue(findValue, OidGroup.Policy);
                    return(FindCore(validOnly,
                                    delegate(SafeCertContextHandle pCertContext)
                        {
                            int numOids;
                            int cbData = 0;
                            if (!Interop.crypt32.CertGetValidUsages(1, ref pCertContext, out numOids, null, ref cbData))
                            {
                                return false;
                            }

                            // -1 means the certificate is good for all usages.
                            if (numOids == -1)
                            {
                                return true;
                            }

                            fixed(byte *pOidsPointer = new byte[cbData])
                            {
                                if (!Interop.crypt32.CertGetValidUsages(1, ref pCertContext, out numOids, pOidsPointer, ref cbData))
                                {
                                    return false;
                                }

                                IntPtr *pOids = (IntPtr *)pOidsPointer;
                                for (int i = 0; i < numOids; i++)
                                {
                                    String actual = Marshal.PtrToStringAnsi(pOids[i]);
                                    if (expected.Equals(actual, StringComparison.OrdinalIgnoreCase))
                                    {
                                        return true;
                                    }
                                }
                                return false;
                            }
                        }
                                    ));
                }

                case X509FindType.FindByCertificatePolicy:
                {
                    String expected = ConfirmedOidValue(findValue, OidGroup.Policy);
                    return(FindCore(validOnly,
                                    delegate(SafeCertContextHandle pCertContext)
                        {
                            CERT_INFO *pCertInfo = pCertContext.CertContext->pCertInfo;
                            CERT_EXTENSION *pCertExtension = Interop.crypt32.CertFindExtension(Oids.CertPolicies, pCertInfo->cExtension, pCertInfo->rgExtension);
                            if (pCertExtension == null)
                            {
                                return false;
                            }

                            bool foundMatch = false;
                            byte[] extensionRawData = pCertExtension->Value.ToByteArray();
                            if (!extensionRawData.DecodeObjectNoThrow(
                                    CryptDecodeObjectStructType.X509_CERT_POLICIES,
                                    delegate(void *pvDecoded)
                            {
                                CERT_POLICIES_INFO *pCertPoliciesInfo = (CERT_POLICIES_INFO *)pvDecoded;
                                for (int i = 0; i < pCertPoliciesInfo->cPolicyInfo; i++)
                                {
                                    CERT_POLICY_INFO *pCertPolicyInfo = &(pCertPoliciesInfo->rgPolicyInfo[i]);
                                    String actual = Marshal.PtrToStringAnsi(pCertPolicyInfo->pszPolicyIdentifier);
                                    if (expected.Equals(actual, StringComparison.OrdinalIgnoreCase))
                                    {
                                        foundMatch = true;
                                        break;
                                    }
                                }
                            }
                                    ))
                            {
                                return false;
                            }

                            GC.KeepAlive(pCertContext);
                            return foundMatch;
                        }
                                    ));
                }

                case X509FindType.FindByExtension:
                {
                    String oidValue = ConfirmedOidValue(findValue, OidGroup.ExtensionOrAttribute);
                    return(FindCore(validOnly,
                                    delegate(SafeCertContextHandle pCertContext)
                        {
                            CERT_INFO *pCertInfo = pCertContext.CertContext->pCertInfo;
                            CERT_EXTENSION *pCertExtension = Interop.crypt32.CertFindExtension(oidValue, pCertInfo->cExtension, pCertInfo->rgExtension);
                            GC.KeepAlive(pCertContext);
                            return pCertExtension != null;
                        }
                                    ));
                }

                case X509FindType.FindByKeyUsage:
                {
                    X509KeyUsageFlags expected = ConfirmedX509KeyUsage(findValue);
                    return(FindCore(validOnly,
                                    delegate(SafeCertContextHandle pCertContext)
                        {
                            CERT_INFO *pCertInfo = pCertContext.CertContext->pCertInfo;
                            X509KeyUsageFlags actual;
                            if (!Interop.crypt32.CertGetIntendedKeyUsage(CertEncodingType.All, pCertInfo, out actual, sizeof(X509KeyUsageFlags)))
                            {
                                return true;          // no key usage means it is valid for all key usages.
                            }
                            GC.KeepAlive(pCertContext);
                            return (actual & expected) == expected;
                        }
                                    ));
                }

                case X509FindType.FindBySubjectKeyIdentifier:
                {
                    byte[] expected = ConfirmedCast <String>(findValue).DecodeHexString();
                    return(FindCore(validOnly,
                                    delegate(SafeCertContextHandle pCertContext)
                        {
                            int cbData = 0;
                            if (!Interop.crypt32.CertGetCertificateContextProperty(pCertContext, CertContextPropId.CERT_KEY_IDENTIFIER_PROP_ID, null, ref cbData))
                            {
                                return false;
                            }

                            byte[] actual = new byte[cbData];
                            if (!Interop.crypt32.CertGetCertificateContextProperty(pCertContext, CertContextPropId.CERT_KEY_IDENTIFIER_PROP_ID, actual, ref cbData))
                            {
                                return false;
                            }

                            return expected.ContentsEqual(actual);
                        }
                                    ));
                }

                default:
                    throw new CryptographicException(SR.Cryptography_X509_InvalidFindType);
                }
            }
        }
Example #44
0
        public static void TestHandleCtor()
        {
            IntPtr pCertContext = IntPtr.Zero;
            byte[] rawData = TestData.MsCertificate;
            unsafe
            {
                fixed (byte* pRawData = rawData)
                {
                    CRYPTOAPI_BLOB certBlob = new CRYPTOAPI_BLOB() { cbData = rawData.Length, pbData = pRawData };
                    bool success = CryptQueryObject(
                        CertQueryObjectType.CERT_QUERY_OBJECT_BLOB,
                        ref certBlob,
                        ExpectedContentTypeFlags.CERT_QUERY_CONTENT_FLAG_CERT,
                        ExpectedFormatTypeFlags.CERT_QUERY_FORMAT_FLAG_BINARY,
                        0,
                        IntPtr.Zero,
                        IntPtr.Zero,
                        IntPtr.Zero,
                        IntPtr.Zero,
                        IntPtr.Zero,
                        out pCertContext
                            );

                    if (!success)
                    {
                        int hr = Marshal.GetHRForLastWin32Error();
                        throw new CryptographicException(hr);
                    }
                }
            }

            // Now, create an X509Certificate around our handle.
            using (X509Certificate2 c = new X509Certificate2(pCertContext))
            {
                // And release our ref-count on the handle. X509Certificate better be maintaining its own.
                CertFreeCertificateContext(pCertContext);

                // Now, test various properties to make sure the X509Certificate actually wraps our CERT_CONTEXT.
                IntPtr h = c.Handle;
                Assert.Equal(pCertContext, h);
                pCertContext = IntPtr.Zero;

#if netstandard17
                Assert.Equal(rawData, c.GetRawCertData());
                Assert.Equal(rawData, c.GetRawCertDataString().HexToByteArray());
#endif

                string issuer = c.Issuer;
                Assert.Equal(
                    "CN=Microsoft Code Signing PCA, O=Microsoft Corporation, L=Redmond, S=Washington, C=US",
                    issuer);

                byte[] expectedPublicKey = (
                    "3082010a0282010100e8af5ca2200df8287cbc057b7fadeeeb76ac28533f3adb" +
                    "407db38e33e6573fa551153454a5cfb48ba93fa837e12d50ed35164eef4d7adb" +
                    "137688b02cf0595ca9ebe1d72975e41b85279bf3f82d9e41362b0b40fbbe3bba" +
                    "b95c759316524bca33c537b0f3eb7ea8f541155c08651d2137f02cba220b10b1" +
                    "109d772285847c4fb91b90b0f5a3fe8bf40c9a4ea0f5c90a21e2aae3013647fd" +
                    "2f826a8103f5a935dc94579dfb4bd40e82db388f12fee3d67a748864e162c425" +
                    "2e2aae9d181f0e1eb6c2af24b40e50bcde1c935c49a679b5b6dbcef9707b2801" +
                    "84b82a29cfbfa90505e1e00f714dfdad5c238329ebc7c54ac8e82784d37ec643" +
                    "0b950005b14f6571c50203010001").HexToByteArray();

                byte[] publicKey = c.GetPublicKey();
                Assert.Equal(expectedPublicKey, publicKey);

                byte[] expectedThumbPrint = "108e2ba23632620c427c570b6d9db51ac31387fe".HexToByteArray();
                byte[] thumbPrint = c.GetCertHash();
                Assert.Equal(expectedThumbPrint, thumbPrint);
            }
        }
Example #45
0
        /*****************************************************************************
        *       wmain
        *
        *****************************************************************************/
        static int Main(string[] args)
        {
            HRESULT        hr               = HRESULT.S_OK;
            SafeHCERTSTORE hStoreHandle     = default;
            string         wszStoreName     = "MY"; // by default, MY
            string         wszContainerName = "SAMPLE";
            uint           dwBits           = 0;

            string wszKeyAlgName = "RSA";             //

            string[] rgwszCNGAlgs = new string[] { "SHA1", "RSA" };

            SafeNCRYPT_KEY_HANDLE hCNGKey      = default;
            SafePCCERT_CONTEXT    pCertContext = default;
            CRYPTOAPI_BLOB        SubjectName  = default;
            int i;

            //
            // options
            //

            for (i = 0; i < args.Length; i++)
            {
                if (string.Compare(args[i], "/?") == 0 || string.Compare(args[i], "-?") == 0)
                {
                    Usage("CreateCert.exe");
                    goto CleanUp;
                }

                if (args[i][0] != '-')
                {
                    break;
                }

                if (string.Compare(args[i], "-s") == 0)
                {
                    if (i + 1 >= args.Length)
                    {
                        hr = HRESULT.E_INVALIDARG;

                        goto CleanUp;
                    }

                    wszStoreName = args[++i];
                }
                else
                if (string.Compare(args[i], "-c") == 0)
                {
                    if (i + 1 >= args.Length)
                    {
                        hr = HRESULT.E_INVALIDARG;

                        goto CleanUp;
                    }

                    wszContainerName = args[++i];
                }
                else
                if (string.Compare(args[i], "-k") == 0)
                {
                    if (i + 1 >= args.Length)
                    {
                        hr = HRESULT.E_INVALIDARG;

                        goto CleanUp;
                    }

                    wszKeyAlgName = args[++i];
                }
                else
                if (string.Compare(args[i], "-h") == 0)
                {
                    if (i + 1 >= args.Length)
                    {
                        hr = HRESULT.E_INVALIDARG;

                        goto CleanUp;
                    }

                    rgwszCNGAlgs[0] = args[++i];
                }
                else
                if (string.Compare(args[i], "-l") == 0)
                {
                    if (i + 1 >= args.Length)
                    {
                        hr = HRESULT.E_INVALIDARG;

                        goto CleanUp;
                    }

                    dwBits = uint.Parse(args[++i]);
                }
            }

            if (i >= args.Length)
            {
                hr = HRESULT.E_INVALIDARG;

                goto CleanUp;
            }

            var wszSubject = args[i];

            //
            // Find the Signature algorithm
            //

            var pOidInfo = CryptFindOIDInfo(CryptOIDInfoFlags.CRYPT_OID_INFO_NAME_KEY, wszKeyAlgName, OIDGroupId.CRYPT_PUBKEY_ALG_OID_GROUP_ID);

            if (default == pOidInfo)
            {
                Console.Write("FAILED: Unable to find Public Key algorithm: '{0}'.\n", wszKeyAlgName);
                hr = HRESULT.CRYPT_E_UNKNOWN_ALGO;
                goto CleanUp;
            }

            var oidInfo = (CRYPT_OID_INFO)pOidInfo;

            if (!string.IsNullOrEmpty(oidInfo.pwszCNGExtraAlgid))
            {
                rgwszCNGAlgs[1] = oidInfo.pwszCNGExtraAlgid;
            }
            else
            {
                rgwszCNGAlgs[1] = oidInfo.pwszCNGAlgid;
            }

            using (var pAlgs = SafeLocalHandle.CreateFromStringList(rgwszCNGAlgs, StringListPackMethod.Packed, CharSet.Unicode))
                pOidInfo = CryptFindOIDInfo(CryptOIDInfoFlags.CRYPT_OID_INFO_CNG_SIGN_KEY, pAlgs, OIDGroupId.CRYPT_SIGN_ALG_OID_GROUP_ID);
            if (default == pOidInfo)
            {
                Console.Write("FAILED: Unable to find signature algorithm: '{0}:{1}'\n", rgwszCNGAlgs[0], rgwszCNGAlgs[1]);
                hr = HRESULT.CRYPT_E_UNKNOWN_ALGO;
                goto CleanUp;
            }

            var SignatureAlgorithm = new CRYPT_ALGORITHM_IDENTIFIER {
                pszObjId = ((CRYPT_OID_INFO)pOidInfo).pszOID
            };

            //-------------------------------------------------------------------
            // Open a system store, in this case, the My store.

            hStoreHandle = CertOpenStore(CertStoreProvider.CERT_STORE_PROV_SYSTEM, 0, default, CertStoreFlags.CERT_SYSTEM_STORE_CURRENT_USER, wszStoreName);
        /// <summary>
        /// Create a self-signed x509 certificate.
        /// </summary>
        /// <param name="subjectName">The distinguished name.</param>
        /// <param name="notBefore">The start time.</param>
        /// <param name="notAfter">the end time.</param>
        /// <param name="extensions">the extensions.</param>
        /// <returns>A byte array containing the certificate and private key encoded as PFX.</returns>
        public static byte[] CreateSelfSignCertificatePfx(
            string subjectName,
            DateTime notBefore,
            DateTime notAfter,
            params X509Extension[] extensions)
        {
            if (subjectName == null)
            {
                subjectName = string.Empty;
            }

            byte[] pfxData;

            SYSTEMTIME startSystemTime = ToSystemTime(notBefore);
            SYSTEMTIME endSystemTime = ToSystemTime(notAfter);
            string containerName = $"Created by Workstation. {Guid.NewGuid().ToString()}";

            GCHandle gcHandle = default(GCHandle);
            var providerContext = SafeCryptProvHandle.InvalidHandle;
            var cryptKey = SafeCryptKeyHandle.InvalidHandle;
            var certContext = SafeCertContextHandle.InvalidHandle;
            var certStore = SafeCertStoreHandle.InvalidHandle;
            var storeCertContext = SafeCertContextHandle.InvalidHandle;

            try
            {
                Check(NativeMethods.CryptAcquireContextW(
                    out providerContext,
                    containerName,
                    null,
                    PROV_RSA_FULL,
                    CRYPT_NEWKEYSET));

                Check(NativeMethods.CryptGenKey(
                    providerContext,
                    AT_KEYEXCHANGE,
                    CRYPT_EXPORTABLE | (2048 << 16), // 2048bit
                    out cryptKey));

                IntPtr pbEncoded = IntPtr.Zero;
                int cbEncoded = 0;

                Check(NativeMethods.CertStrToNameW(
                    X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                    subjectName,
                    CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
                    IntPtr.Zero,
                    IntPtr.Zero,
                    ref cbEncoded,
                    IntPtr.Zero));

                pbEncoded = Marshal.AllocHGlobal(cbEncoded);

                Check(NativeMethods.CertStrToNameW(
                    X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                    subjectName,
                    CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
                    IntPtr.Zero,
                    pbEncoded,
                    ref cbEncoded,
                    IntPtr.Zero));

                var nameBlob = new CRYPTOAPI_BLOB
                {
                    cbData = (uint)cbEncoded,
                    pbData = pbEncoded
                };

                var kpi = new CRYPT_KEY_PROV_INFO
                {
                    pwszContainerName = containerName,
                    dwProvType = PROV_RSA_FULL,
                    dwKeySpec = AT_KEYEXCHANGE
                };

                var signatureAlgorithm = new CRYPT_ALGORITHM_IDENTIFIER
                {
                    pszObjId = OID_RSA_SHA256RSA,
                    Parameters = default(CRYPTOAPI_BLOB)
                };

                IntPtr pInfo = IntPtr.Zero;
                int cbInfo = 0;
                byte[] keyHash = null;
                int cbKeyHash = 0;

                try
                {
                    Check(NativeMethods.CryptExportPublicKeyInfoEx(
                        providerContext,
                        AT_KEYEXCHANGE,
                        X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                        OID_RSA_RSA,
                        0,
                        IntPtr.Zero,
                        IntPtr.Zero,
                        ref cbInfo));

                    pInfo = Marshal.AllocHGlobal(cbInfo);

                    Check(NativeMethods.CryptExportPublicKeyInfoEx(
                        providerContext,
                        AT_KEYEXCHANGE,
                        X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                        OID_RSA_RSA,
                        0,
                        IntPtr.Zero,
                        pInfo,
                        ref cbInfo));

                    Check(NativeMethods.CryptHashPublicKeyInfo(
                        providerContext,
                        CALG_SHA1,
                        0,
                        X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                        pInfo,
                        null,
                        ref cbKeyHash));

                    keyHash = new byte[cbKeyHash];

                    Check(NativeMethods.CryptHashPublicKeyInfo(
                        providerContext,
                        CALG_SHA1,
                        0,
                        X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                        pInfo,
                        keyHash,
                        ref cbKeyHash));
                }
                finally
                {
                    if (pInfo != IntPtr.Zero)
                    {
                        Marshal.FreeHGlobal(pInfo);
                    }
                }

                var safeExtensions = new List<SafeX509Extension>();
                var blob = IntPtr.Zero;
                try
                {
                    foreach (var item in extensions)
                    {
                        safeExtensions.Add(new SafeX509Extension(item));
                    }

                    // adding SubjectKeyIdentifier TODO: AuthKeyIdentifier?
                    safeExtensions.Add(new SafeX509Extension(new X509SubjectKeyIdentifierExtension(keyHash, false)));

                    var structSize = Marshal.SizeOf<CERT_EXTENSION>();
                    blob = Marshal.AllocHGlobal(structSize * safeExtensions.Count);
                    for (int index = 0, offset = 0; index < safeExtensions.Count; index++, offset += structSize)
                    {
                        var marshalX509Extension = safeExtensions[index];
                        Marshal.StructureToPtr(marshalX509Extension.Value, blob + offset, false);
                    }

                    var certExtensions = new CERT_EXTENSIONS { cExtension = (uint)safeExtensions.Count, rgExtension = blob };

                    certContext = NativeMethods.CertCreateSelfSignCertificate(
                        providerContext,
                        ref nameBlob,
                        0,
                        ref kpi,
                        ref signatureAlgorithm,
                        ref startSystemTime,
                        ref endSystemTime,
                        ref certExtensions);
                    Check(!certContext.IsInvalid);
                }
                finally
                {
                    foreach (var safeExtension in safeExtensions)
                    {
                        safeExtension.Dispose();
                    }

                    safeExtensions.Clear();
                    Marshal.FreeHGlobal(blob);
                    Marshal.FreeHGlobal(pbEncoded);
                }

                certStore = NativeMethods.CertOpenStore(
                    sz_CERT_STORE_PROV_MEMORY,
                    0,
                    IntPtr.Zero,
                    CERT_STORE_CREATE_NEW_FLAG,
                    IntPtr.Zero);
                Check(!certStore.IsInvalid);

                Check(NativeMethods.CertAddCertificateContextToStore(
                    certStore,
                    certContext,
                    CERT_STORE_ADD_NEW,
                    out storeCertContext));

                NativeMethods.CertSetCertificateContextProperty(
                    storeCertContext,
                    CERT_KEY_PROV_INFO_PROP_ID,
                    0,
                    ref kpi);

                CRYPTOAPI_BLOB pfxBlob = default(CRYPTOAPI_BLOB);
                Check(NativeMethods.PFXExportCertStoreEx(
                    certStore,
                    ref pfxBlob,
                    IntPtr.Zero,
                    IntPtr.Zero,
                    EXPORT_PRIVATE_KEYS | REPORT_NO_PRIVATE_KEY | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY));

                pfxData = new byte[pfxBlob.cbData];
                gcHandle = GCHandle.Alloc(pfxData, GCHandleType.Pinned);
                pfxBlob.pbData = gcHandle.AddrOfPinnedObject();

                Check(NativeMethods.PFXExportCertStoreEx(
                    certStore,
                    ref pfxBlob,
                    IntPtr.Zero,
                    IntPtr.Zero,
                    EXPORT_PRIVATE_KEYS | REPORT_NO_PRIVATE_KEY | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY));

                gcHandle.Free();
            }
            finally
            {
                if (gcHandle.IsAllocated)
                {
                    gcHandle.Free();
                }

                if (!certContext.IsInvalid)
                {
                    certContext.Dispose();
                }

                if (!storeCertContext.IsInvalid)
                {
                    storeCertContext.Dispose();
                }

                if (!certStore.IsInvalid)
                {
                    certStore.Dispose();
                }

                if (!cryptKey.IsInvalid)
                {
                    cryptKey.Dispose();
                }

                if (!providerContext.IsInvalid)
                {
                    providerContext.Dispose();
                    providerContext = SafeCryptProvHandle.InvalidHandle;

                    // Delete generated keyset. Does not return a providerContext
                    NativeMethods.CryptAcquireContextW(
                        out providerContext,
                        containerName,
                        null,
                        PROV_RSA_FULL,
                        CRYPT_DELETEKEYSET);
                }
            }

            return pfxData;
        }