Exemple #1
0
            //
            // This returns an allocated native memory block. Its lifetime (and that of any allocated subblocks it may point to) is that of "hb".
            //
            private static unsafe CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *EncodeKeyTransRecipientInfo(CmsRecipient recipient, HeapBlockRetainer hb)
            {
                // "recipient" is a deep-cloned CmsRecipient object whose lifetime this class controls. Because of this, we can pull out the CERT_CONTEXT* and CERT_INFO* pointers
                // and embed pointers to them in the memory block we return. Yes, this code is scary.
                //
                // (The use of SafeCertContextHandle here is about using a consistent pattern to get the CERT_CONTEXT (rather than the ugly (CERT_CONTEXT*)(recipient.Certificate.Handle) pattern.)
                // It's not about keeping the context alive.)
                using (SafeCertContextHandle hCertContext = recipient.Certificate.CreateCertContextHandle())
                {
                    CERT_CONTEXT *pCertContext = hCertContext.DangerousGetCertContext();
                    CERT_INFO *   pCertInfo    = pCertContext->pCertInfo;

                    CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *pEncodeInfo = (CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *)(hb.Alloc(sizeof(CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO)));

                    pEncodeInfo->cbSize = sizeof(CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO);

                    CRYPT_ALGORITHM_IDENTIFIER algId = pCertInfo->SubjectPublicKeyInfo.Algorithm;
                    pEncodeInfo->KeyEncryptionAlgorithm = algId;

                    pEncodeInfo->pvKeyEncryptionAuxInfo = IntPtr.Zero;
                    pEncodeInfo->hCryptProv             = IntPtr.Zero;

                    pEncodeInfo->RecipientPublicKey = pCertInfo->SubjectPublicKeyInfo.PublicKey;

                    pEncodeInfo->RecipientId = EncodeRecipientId(recipient, hCertContext, pCertContext, pCertInfo, hb);

                    return(pEncodeInfo);
                }
            }
Exemple #2
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);
Exemple #3
0
 public static extern IntPtr CertCreateSelfSignCertificate(IntPtr hProv,
                                                           ref CERT_NAME_BLOB pSubjectIssuerBlob,
                                                           uint dwFlagsm,
                                                           ref CRYPT_KEY_PROV_INFO pKeyProvInfo,
                                                           ref CRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
                                                           ref SYSTEM_TIME pStartTime,
                                                           ref SYSTEM_TIME pEndTime,
                                                           IntPtr other);
Exemple #4
0
 internal static extern IntPtr CertCreateSelfSignCertificate(
     IntPtr providerHandle,
     [In] CryptoApiBlob subjectIssuerBlob,
     int flags,
     ref CRYPT_KEY_PROV_INFO pKeyProvInfo,
     ref CRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
     [In] SystemTime startTime,
     [In] SystemTime endTime,
     IntPtr extensions);
Exemple #5
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);
Exemple #6
0
 public static extern bool CryptSignAndEncodeCertificate(IntPtr hCryptProvOrNCryptKey,
                                                         uint dwKeySpec,
                                                         uint dwCertEncodingType,
                                                         ulong lpszStructType,
                                                         IntPtr pvStructInfo,
                                                         ref CRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
                                                         IntPtr pvHashAuxInfo,
                                                         byte[] pbEncoded,
                                                         ref uint pcbEncoded);
Exemple #7
0
        public unsafe X509Certificate2 GenerateCertificateAuthority(PrivateKey privateKey, X500DistinguishedName dn, HashAlgorithm signatureAlgorithm, DateTime?notBefore = null, DateTime?notAfter = null)
        {
            {
                fixed(byte *dnPtr = dn.RawData)
                {
                    var blob = new NATIVE_CRYPTOAPI_BLOB
                    {
                        cbData = (uint)dn.RawData.Length,
                        pbData = dnPtr
                    };
                    var signatureAlgorithmIdentifier = new CRYPT_ALGORITHM_IDENTIFIER
                    {
                        pszObjId = HashAlgorithmToSignatureAlgorithm(privateKey, signatureAlgorithm)
                    };

                    using (var extensions = new MarshalX509ExtensionCollection())
                    {
                        using (extensions.Freeze())
                        {
                            extensions.Add(new X509BasicConstraintsExtension(true, true, 1, true));
                            extensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.CrlSign | X509KeyUsageFlags.KeyCertSign, true));
                            extensions.Add(new X509EnhancedKeyUsageExtension(new OidCollection {
                                new Oid(OIDs.EKU_SERVER)
                            }, false));
                            using (var publicKey = privateKey.ToPublicKey())
                            {
                                using (var sha1 = new SHA1CryptoServiceProvider())
                                {
                                    var pubKeyHash = sha1.ComputeHash(publicKey.Key);
                                    extensions.Add(new X509SubjectKeyIdentifierExtension(pubKeyHash, false));
                                    extensions.Add(new X509AuthorityKeyIdentifierExtension(pubKeyHash, null));
                                }
                            }
                        }
                        var certExtensions = extensions.Extensions;
                        var keyProvInfo    = new CRYPT_KEY_PROV_INFO
                        {
                            cProvParam        = 0,
                            dwKeySpec         = privateKey.KeySpec,
                            dwProvType        = privateKey.Handle.IsNCryptKey ? ProviderType.CNG : ProviderType.PROV_RSA_AES,
                            pwszProvName      = privateKey.ProviderName,
                            dwFlags           = 0,
                            pwszContainerName = privateKey.Name
                        };
                        var beginning   = new SYSTEMTIME(notBefore ?? DateTime.UtcNow.AddHours(-1));
                        var expiration  = new SYSTEMTIME(notAfter ?? DateTime.UtcNow.AddHours(-1).AddYears(30));
                        var certContext = Crypt32.CertCreateSelfSignCertificate(privateKey.Handle, ref blob, SelfSignFlags.NONE, ref keyProvInfo, ref signatureAlgorithmIdentifier, beginning, expiration, ref certExtensions);
                        if (certContext == IntPtr.Zero)
                        {
                            throw new Win32Exception(Marshal.GetLastWin32Error());
                        }
                        return(new X509Certificate2(certContext));
                    }
                }
            }
        }
Exemple #8
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
     );
Exemple #9
0
 public static extern bool CryptSignAndEncodeCertificate(
     SafeCryptProviderHandle hCryptProv,
     CALG dwKeySpec,
     CertEncoding dwCertEncodingType,
     IntPtr lpszStructType,
     IntPtr pvStructInfo,
     CRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
     IntPtr pvHashAuxInfo,
     byte[] pbEncoded,
     ref uint pcbEncoded
     );
Exemple #10
0
        public unsafe X509Certificate2 GenerateCertificate(X509Certificate2 issuingCertificate, PrivateKey privateKey, X500DistinguishedName dn, string[] dnsNames, IPAddress[] ipAddresses = null, HashAlgorithm?signatureAlgorithm = null, DateTime?notBefore = null, DateTime?notAfter = null)
        {
            if (!issuingCertificate.HasPrivateKey)
            {
                throw new ArgumentException("Issuing certificate must have a private key.", nameof(issuingCertificate));
            }
            IntPtr basicEncodedDataPtr = IntPtr.Zero, certExtensionPtr = IntPtr.Zero;
            var    serialNumber = new byte[16];
            var    rng = RandomNumberGenerator.Create();

            rng.GetNonZeroBytes(serialNumber);
            serialNumber[15] &= 0x7F;
            fixed(byte *dnPtr = dn.RawData, issuerDnPtr = issuingCertificate.SubjectName.RawData, serialNumberPtr = serialNumber)
            {
                try
                {
                    var blob = new NATIVE_CRYPTOAPI_BLOB
                    {
                        cbData = (uint)dn.RawData.Length,
                        pbData = dnPtr
                    };
                    var signingSignatureAlgorithmIdentifier = new CRYPT_ALGORITHM_IDENTIFIER
                    {
                        pszObjId = issuingCertificate.SignatureAlgorithm.Value
                    };
                    using (var signingKey = ExtractKey(issuingCertificate))
                    {
                        var signingAlgorithmIdentifier = new CRYPT_ALGORITHM_IDENTIFIER
                        {
                            pszObjId = signatureAlgorithm != null?HashAlgorithmToSignatureAlgorithm(signingKey, signatureAlgorithm.Value) : issuingCertificate.SignatureAlgorithm.Value
                        };
                        using (PublicKeyInfo publicKey = privateKey.ToPublicKey(), signingPublicKey = signingKey.ToPublicKey())
                        {
                            using (var extensions = new MarshalX509ExtensionCollection())
                            {
                                using (extensions.Freeze())
                                {
                                    var usage = X509KeyUsageFlags.DigitalSignature;
                                    if (privateKey.AlgorithmGroup == AlgorithmGroup.RSA)
                                    {
                                        //Key encipherment is not valid for DSA/ECDSA
                                        usage |= X509KeyUsageFlags.KeyEncipherment;
                                    }
                                    extensions.Add(new X509BasicConstraintsExtension(false, false, 0, true));
                                    extensions.Add(new X509KeyUsageExtension(usage, true));
                                    extensions.Add(new X509EnhancedKeyUsageExtension(new OidCollection {
                                        new Oid(OIDs.EKU_SERVER)
                                    }, false));
                                    extensions.Add(new X509SubjectAlternativeNameExtension(DnsAltNamesFromArray(dnsNames, ipAddresses ?? new IPAddress[0]), false));
                                    using (var sha1 = new SHA1CryptoServiceProvider())
                                    {
                                        var issuingKeyId = sha1.ComputeHash(signingPublicKey.Key);
                                        extensions.Add(new X509SubjectKeyIdentifierExtension(sha1.ComputeHash(publicKey.Key), false));
                                        extensions.Add(new X509AuthorityKeyIdentifierExtension(issuingKeyId, null));
                                    }
                                }
                                var certInfo = new CERT_INFO();
                                certInfo.Subject      = blob;
                                certInfo.SerialNumber = new NATIVE_CRYPTOAPI_BLOB {
                                    cbData = (uint)serialNumber.Length, pbData = serialNumberPtr
                                };
                                certInfo.SubjectPublicKeyInfo = publicKey.PublicKey;
                                certInfo.dwVersion            = CertificateVersion.CERT_V3;
                                certInfo.Issuer = new NATIVE_CRYPTOAPI_BLOB {
                                    cbData = (uint)issuingCertificate.SubjectName.RawData.Length, pbData = issuerDnPtr
                                };
                                certInfo.SignatureAlgorithm = signingAlgorithmIdentifier;
                                certInfo.NotAfter           = FileTimeHelper.ToFileTimeStructureUtc(notAfter ?? DateTime.Now.AddHours(-1).AddYears(5));
                                certInfo.NotBefore          = FileTimeHelper.ToFileTimeStructureUtc(notBefore ?? DateTime.Now.AddHours(-1));
                                certInfo.cExtension         = extensions.Extensions.cExtension;
                                certInfo.rgExtension        = extensions.Extensions.rgExtension;
                                var size           = 0u;
                                var CERT_INFO_TYPE = (IntPtr)2;
                                if (!Crypt32.CryptSignAndEncodeCertificate(signingKey.Handle, signingKey.KeySpec, EncodingType.X509_ASN_ENCODING, CERT_INFO_TYPE, ref certInfo, ref signingSignatureAlgorithmIdentifier, IntPtr.Zero, IntPtr.Zero, ref size))
                                {
                                    throw new Win32Exception(Marshal.GetLastWin32Error());
                                }
                                var buffer = Marshal.AllocHGlobal((int)size);
                                if (!Crypt32.CryptSignAndEncodeCertificate(signingKey.Handle, signingKey.KeySpec, EncodingType.X509_ASN_ENCODING, CERT_INFO_TYPE, ref certInfo, ref signingSignatureAlgorithmIdentifier, IntPtr.Zero, buffer, ref size))
                                {
                                    throw new Win32Exception(Marshal.GetLastWin32Error());
                                }
                                const int CERT_KEY_PROV_INFO_PROP_ID = 2;
                                var       certificate = new X509Certificate2(SerializeCertificate(buffer, size));
                                var       keyProvInfo = new CRYPT_KEY_PROV_INFO
                                {
                                    cProvParam        = 0,
                                    dwKeySpec         = privateKey.KeySpec,
                                    dwProvType        = privateKey.Handle.IsNCryptKey ? ProviderType.CNG : ProviderType.PROV_RSA_AES,
                                    pwszProvName      = privateKey.ProviderName,
                                    dwFlags           = 0,
                                    pwszContainerName = privateKey.Name
                                };
                                if (!Crypt32.CertSetCertificateContextProperty(certificate.Handle, CERT_KEY_PROV_INFO_PROP_ID, 0u, ref keyProvInfo))
                                {
                                    throw new Win32Exception(Marshal.GetLastWin32Error());
                                }
                                return(new X509Certificate2(certificate));
                            }
                        }
                    }
                }
                finally
                {
                    Marshal.FreeHGlobal(basicEncodedDataPtr);
                    Marshal.FreeHGlobal(certExtensionPtr);
                }
            }
        }
Exemple #11
0
 public static extern bool CryptSignAndEncodeCertificate(
        SafeCryptProviderHandle hCryptProv,
        CALG dwKeySpec,
        CertEncoding dwCertEncodingType,
        IntPtr lpszStructType,
        IntPtr pvStructInfo,
        CRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
        IntPtr pvHashAuxInfo,
        byte[] pbEncoded,
        ref uint pcbEncoded
  );
        /// <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;
        }
Exemple #13
0
        public static AlgorithmIdentifier ToAlgorithmIdentifier(this CRYPT_ALGORITHM_IDENTIFIER cryptAlgorithmIdentifer)
        {
            string oidValue = cryptAlgorithmIdentifer.pszObjId.ToStringAnsi();
            AlgId  algId    = oidValue.ToAlgId();

            int keyLength;

            switch (algId)
            {
            case AlgId.CALG_RC2:
            {
                if (cryptAlgorithmIdentifer.Parameters.cbData == 0)
                {
                    keyLength = 0;
                }
                else
                {
                    CRYPT_RC2_CBC_PARAMETERS rc2Parameters;
                    unsafe
                    {
                        int cbSize = sizeof(CRYPT_RC2_CBC_PARAMETERS);
                        if (!Interop.Crypt32.CryptDecodeObject(CryptDecodeObjectStructType.PKCS_RC2_CBC_PARAMETERS, cryptAlgorithmIdentifer.Parameters.pbData, (int)(cryptAlgorithmIdentifer.Parameters.cbData), &rc2Parameters, ref cbSize))
                        {
                            throw Interop.CPError.GetLastWin32Error().ToCryptographicException();
                        }
                    }

                    switch (rc2Parameters.dwVersion)
                    {
                    case CryptRc2Version.CRYPT_RC2_40BIT_VERSION:
                        keyLength = KeyLengths.Rc2_40Bit;
                        break;

                    case CryptRc2Version.CRYPT_RC2_56BIT_VERSION:
                        keyLength = KeyLengths.Rc2_56Bit;
                        break;

                    case CryptRc2Version.CRYPT_RC2_64BIT_VERSION:
                        keyLength = KeyLengths.Rc2_64Bit;
                        break;

                    case CryptRc2Version.CRYPT_RC2_128BIT_VERSION:
                        keyLength = KeyLengths.Rc2_128Bit;
                        break;

                    default:
                        keyLength = 0;
                        break;
                    }
                }
                break;
            }

            case AlgId.CALG_RC4:
            {
                int saltLength = 0;
                if (cryptAlgorithmIdentifer.Parameters.cbData != 0)
                {
                    using (SafeHandle sh = Interop.Crypt32.CryptDecodeObjectToMemory(CryptDecodeObjectStructType.X509_OCTET_STRING, cryptAlgorithmIdentifer.Parameters.pbData, (int)cryptAlgorithmIdentifer.Parameters.cbData))
                    {
                        unsafe
                        {
                            DATA_BLOB *pDataBlob = (DATA_BLOB *)(sh.DangerousGetHandle());
                            saltLength = (int)(pDataBlob->cbData);
                        }
                    }
                }

                // For RC4, keyLength = 128 - (salt length * 8).
                keyLength = KeyLengths.Rc4Max_128Bit - saltLength * 8;
                break;
            }

            case AlgId.CALG_DES:
                // DES key length is fixed at 64 (or 56 without the parity bits).
                keyLength = KeyLengths.Des_64Bit;
                break;

            case AlgId.CALG_3DES:
                // 3DES key length is fixed at 192 (or 168 without the parity bits).
                keyLength = KeyLengths.TripleDes_192Bit;
                break;

            default:
                // We've exhausted all the algorithm types that the desktop used to set the KeyLength for. Key lengths are not a viable way of
                // identifying algorithms in the long run so we will not extend this list any further.
                keyLength = 0;
                break;
            }

            AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(Oid.FromOidValue(oidValue, OidGroup.All), keyLength);

            switch (oidValue)
            {
            case Oids.RsaOaep:
                algorithmIdentifier.Parameters = cryptAlgorithmIdentifer.Parameters.ToByteArray();
                break;
            }
            return(algorithmIdentifier);
        }
        /// <summary>
        /// Creates the certificate and adds it to the store.
        /// </summary>
        private static string CreateSelfSignedCertificate(
            IntPtr hProvider,
            IntPtr hStore,
            bool useMachineStore,
            string applicationName,
            string applicationUri,
            string subjectName,
            IList<string> hostNames,
            ushort keySize,
            ushort lifetimeInMonths,
            ushort algorithm = 0)
        {
            IntPtr hKey = IntPtr.Zero;
            IntPtr pKpi = IntPtr.Zero;
            IntPtr pThumbprint = IntPtr.Zero;
            IntPtr pContext = IntPtr.Zero;
            IntPtr pAlgorithmId = IntPtr.Zero;
            IntPtr pNewContext = IntPtr.Zero;
            CRYPT_DATA_BLOB publicKeyId = new CRYPT_DATA_BLOB();
            CERT_NAME_BLOB subjectNameBlob = new CERT_NAME_BLOB();
            SYSTEMTIME stValidTo = new SYSTEMTIME();
            CERT_EXTENSIONS extensions = new CERT_EXTENSIONS();
            CRYPT_DATA_BLOB friendlyName = new CRYPT_DATA_BLOB();

            GCHandle hValidTo = new GCHandle();
            GCHandle hExtensionList = new GCHandle();
            GCHandle hSubjectNameBlob = new GCHandle();
            GCHandle hFriendlyName = new GCHandle();

            try
            {
                // create a new key pair.
                int bResult = NativeMethods.CryptGenKey(
                    hProvider,
                    AT_KEYEXCHANGE,
                    CRYPT_EXPORTABLE | (keySize << 16),
                    ref hKey);

                if (bResult == 0)
                {
                    Throw("Could not generate a new key pair. Error={0:X8}", Marshal.GetLastWin32Error());
                }

                // gey the public key identifier.
                GetPublicKeyIdentifier(hProvider, ref publicKeyId);

                // construct the certificate subject name.
                CreateX500Name(subjectName, ref subjectNameBlob);
                GCHandle hSubjectName = GCHandle.Alloc(subjectNameBlob, GCHandleType.Pinned);

                // allocate memory for all possible extensions.
                extensions.cExtension = 0;
                extensions.rgExtension = Marshal.AllocHGlobal(6 * Marshal.SizeOf(typeof(CERT_EXTENSION)));

                // create the subject key info extension.
                IntPtr pPos = extensions.rgExtension;
                CERT_EXTENSION extension = new CERT_EXTENSION();
                CreateSubjectKeyIdentifierExtension(ref extension, ref publicKeyId);
                Marshal.StructureToPtr(extension, pPos, false);
                pPos = new IntPtr(pPos.ToInt64() + Marshal.SizeOf(typeof(CERT_EXTENSION)));
                extensions.cExtension++;

                // create the authority key info extension.
                extension = new CERT_EXTENSION();
                CreateAuthorityKeyIdentifierExtension(ref extension, ref publicKeyId);
                Marshal.StructureToPtr(extension, pPos, false);
                pPos = new IntPtr(pPos.ToInt64() + Marshal.SizeOf(typeof(CERT_EXTENSION)));
                extensions.cExtension++;

                // create the basic constraints extension.
                extension = new CERT_EXTENSION();
                CreateBasicConstraintsExtension(ref extension, false);
                Marshal.StructureToPtr(extension, pPos, false);
                pPos = new IntPtr(pPos.ToInt64() + Marshal.SizeOf(typeof(CERT_EXTENSION)));
                extensions.cExtension++;

                // create the key usage extension.
                extension = new CERT_EXTENSION();
                CreateKeyUsageExtension(ref extension, false);
                Marshal.StructureToPtr(extension, pPos, false);
                pPos = new IntPtr(pPos.ToInt64() + Marshal.SizeOf(typeof(CERT_EXTENSION)));
                extensions.cExtension++;

                // create the extended key usage extension.
                extension = new CERT_EXTENSION();
                CreateExtendedKeyUsageExtension(ref extension);
                Marshal.StructureToPtr(extension, pPos, false);
                pPos = new IntPtr(pPos.ToInt64() + Marshal.SizeOf(typeof(CERT_EXTENSION)));
                extensions.cExtension++;

                // create the subject alternate name extension.
                extension = new CERT_EXTENSION();
                CreateSubjectAltNameExtension(applicationUri, hostNames, ref extension);
                Marshal.StructureToPtr(extension, pPos, false);
                pPos = new IntPtr(pPos.ToInt64() + Marshal.SizeOf(typeof(CERT_EXTENSION)));
                extensions.cExtension++;

                // set the expiration date.
                DateTime validTo = DateTime.UtcNow.AddMonths(lifetimeInMonths);
                System.Runtime.InteropServices.ComTypes.FILETIME ftValidTo = new System.Runtime.InteropServices.ComTypes.FILETIME();
                ulong ticks = (ulong)(validTo.Ticks - new DateTime(1601, 1, 1).Ticks);
                ftValidTo.dwHighDateTime = (int)((0xFFFFFFFF00000000 & (ulong)ticks) >> 32);
                ftValidTo.dwLowDateTime = (int)((ulong)ticks & 0x00000000FFFFFFFF);

                NativeMethods.FileTimeToSystemTime(ref ftValidTo, ref stValidTo);

                // specify what key is being used to sign the certificate.
                CRYPT_KEY_PROV_INFO kpi = new CRYPT_KEY_PROV_INFO();

                kpi.pwszContainerName = KEY_CONTAINER_NAME; // must be the same as the hProvider
                kpi.pwszProvName = DEFAULT_CRYPTO_PROVIDER;
                kpi.dwProvType = PROV_RSA_FULL;
                kpi.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID;
                kpi.dwKeySpec = AT_KEYEXCHANGE;

                if (useMachineStore)
                {
                    kpi.dwFlags |= CRYPT_MACHINE_KEYSET;
                }
                else
                {
                    kpi.dwFlags |= CRYPT_USER_KEYSET;
                }

                pKpi = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CRYPT_KEY_PROV_INFO)));
                Marshal.StructureToPtr(kpi, pKpi, false);

                hValidTo = GCHandle.Alloc(stValidTo, GCHandleType.Pinned);
                hExtensionList = GCHandle.Alloc(extensions, GCHandleType.Pinned);
                hSubjectNameBlob = GCHandle.Alloc(subjectNameBlob, GCHandleType.Pinned);

                if (algorithm == 1)
                {
                    CRYPT_ALGORITHM_IDENTIFIER algorithmID = new CRYPT_ALGORITHM_IDENTIFIER();
                    algorithmID.pszObjId = "1.2.840.113549.1.1.11"; //SHA256

                    pAlgorithmId = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CRYPT_ALGORITHM_IDENTIFIER)));
                    Marshal.StructureToPtr(algorithmID, pAlgorithmId, false);

                    //create the certificate
                    pContext = NativeMethods.CertCreateSelfSignCertificate(
                         hProvider,
                         hSubjectNameBlob.AddrOfPinnedObject(),
                         0,
                         pKpi,
                         pAlgorithmId,
                         IntPtr.Zero,
                         hValidTo.AddrOfPinnedObject(),
                         hExtensionList.AddrOfPinnedObject());
                }
                else
                {
                    // (default) create the certificate.
                    pContext = NativeMethods.CertCreateSelfSignCertificate(
                    hProvider,
                    hSubjectNameBlob.AddrOfPinnedObject(),
                    0,
                    pKpi,
                    IntPtr.Zero,
                    IntPtr.Zero,
                    hValidTo.AddrOfPinnedObject(),
                    hExtensionList.AddrOfPinnedObject());
                }

                if (pContext == IntPtr.Zero)
                {
                    Throw("Could not create self-signed certificate. Error={0:X8}", Marshal.GetLastWin32Error());
                }

                // get the thumbprint.
                int dwThumbprintSize = 20;
                pThumbprint = Marshal.AllocHGlobal(dwThumbprintSize);

                bResult = NativeMethods.CertGetCertificateContextProperty(
                    pContext,
                    CERT_SHA1_HASH_PROP_ID,
                    pThumbprint,
                    ref dwThumbprintSize);

                if (bResult == 0)
                {
                    Throw("Could not get the thumbprint of the new certificate. Error={0:X8}", Marshal.GetLastWin32Error());
                }

                byte[] bytes = new byte[dwThumbprintSize];
                Marshal.Copy(pThumbprint, bytes, 0, dwThumbprintSize);
                string thumbprint = Utils.ToHexString(bytes);

                // set the friendly name.
                friendlyName.pbData = Marshal.StringToHGlobalUni(applicationName);
                friendlyName.cbData = (applicationName.Length+1)*Marshal.SizeOf(typeof(ushort));
                hFriendlyName = GCHandle.Alloc(friendlyName, GCHandleType.Pinned);

                bResult = NativeMethods.CertSetCertificateContextProperty(
                    pContext,
                    CERT_FRIENDLY_NAME_PROP_ID,
                    0,
                    hFriendlyName.AddrOfPinnedObject());

                if (bResult == 0)
                {
                    Throw("Could not set the friendly name for the certificate. Error={0:X8}", Marshal.GetLastWin32Error());
                }

                // add into store.
                bResult = NativeMethods.CertAddCertificateContextToStore(
                    hStore,
                    pContext,
                    CERT_STORE_ADD_REPLACE_EXISTING,
                    ref pNewContext);

                if (bResult == 0)
                {
                    Throw("Could not add the certificate to the store. Error={0:X8}", Marshal.GetLastWin32Error());
                }

                return thumbprint;
            }
            finally
            {
                if (pContext != IntPtr.Zero)
                {
                    NativeMethods.CertFreeCertificateContext(pContext);
                }

                if (pNewContext != IntPtr.Zero)
                {
                    NativeMethods.CertFreeCertificateContext(pNewContext);
                }

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

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

                if (pAlgorithmId != IntPtr.Zero)
                {
                    Marshal.DestroyStructure(pAlgorithmId, typeof(CRYPT_ALGORITHM_IDENTIFIER));
                    Marshal.FreeHGlobal(pAlgorithmId);
                }

                if (hValidTo.IsAllocated) hValidTo.Free();
                if (hExtensionList.IsAllocated) hExtensionList.Free();
                if (hSubjectNameBlob.IsAllocated) hSubjectNameBlob.Free();
                if (hFriendlyName.IsAllocated) hFriendlyName.Free();

                if (pKpi != IntPtr.Zero)
                {
                    Marshal.DestroyStructure(pKpi, typeof(CRYPT_KEY_PROV_INFO));
                    Marshal.FreeHGlobal(pKpi);
                }

                DeleteExtensions(ref extensions.rgExtension, extensions.cExtension);
                DeleteX500Name(ref subjectNameBlob);

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

                if (hKey != IntPtr.Zero)
                {
                    NativeMethods.CryptDestroyKey(hKey);
                }
            }
        }
Exemple #15
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);
        }
Exemple #16
0
 internal CMSG_ENVELOPED_ENCODE_INFO(int size) {
     cbSize = (uint) size;
     hCryptProv = IntPtr.Zero;
     ContentEncryptionAlgorithm = new CRYPT_ALGORITHM_IDENTIFIER();
     pvEncryptionAuxInfo = IntPtr.Zero;
     cRecipients = 0;
     rgpRecipients = IntPtr.Zero;
     rgCmsRecipients = IntPtr.Zero;
     cCertEncoded = 0;
     rgCertEncoded = IntPtr.Zero;
     cCrlEncoded = 0;
     rgCrlEncoded = IntPtr.Zero;
     cAttrCertEncoded = 0;
     rgAttrCertEncoded = IntPtr.Zero;
     cUnprotectedAttr = 0;
     rgUnprotectedAttr = IntPtr.Zero;
 }
Exemple #17
0
 internal CMSG_SIGNER_ENCODE_INFO(int size) {
     cbSize = (uint) size;
     pCertInfo = IntPtr.Zero;
     hCryptProv = IntPtr.Zero;
     dwKeySpec = 0;
     HashAlgorithm = new CRYPT_ALGORITHM_IDENTIFIER();
     pvHashAuxInfo = IntPtr.Zero;
     cAuthAttr = 0;
     rgAuthAttr = IntPtr.Zero;
     cUnauthAttr = 0;
     rgUnauthAttr = IntPtr.Zero;
     SignerId = new CERT_ID();
     HashEncryptionAlgorithm = new CRYPT_ALGORITHM_IDENTIFIER();
     pvHashEncryptionAuxInfo = IntPtr.Zero;
 }
Exemple #18
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;
        }
            //
            // This returns an allocated native memory block. Its lifetime (and that of any allocated subblocks it may point to) is that of "hb".
            //
            private static unsafe CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *EncodeKeyTransRecipientInfo(CmsRecipient recipient, HeapBlockRetainer hb)
            {
                // "recipient" is a deep-cloned CmsRecipient object whose lifetime this class controls. Because of this, we can pull out the CERT_CONTEXT* and CERT_INFO* pointers
                // and embed pointers to them in the memory block we return. Yes, this code is scary.
                //
                // (The use of SafeCertContextHandle here is about using a consistent pattern to get the CERT_CONTEXT (rather than the ugly (CERT_CONTEXT*)(recipient.Certificate.Handle) pattern.)
                // It's not about keeping the context alive.)
                using (SafeCertContextHandle hCertContext = recipient.Certificate.CreateCertContextHandle())
                {
                    CERT_CONTEXT *pCertContext = hCertContext.DangerousGetCertContext();
                    CERT_INFO *   pCertInfo    = pCertContext->pCertInfo;

                    CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *pEncodeInfo = (CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO *)(hb.Alloc(sizeof(CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO)));

                    pEncodeInfo->cbSize = sizeof(CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO);

                    if (recipient.RSAEncryptionPadding is null)
                    {
                        CRYPT_ALGORITHM_IDENTIFIER algId = pCertInfo->SubjectPublicKeyInfo.Algorithm;
                        pEncodeInfo->KeyEncryptionAlgorithm = algId;
                    }
                    else if (recipient.RSAEncryptionPadding == RSAEncryptionPadding.Pkcs1)
                    {
                        pEncodeInfo->KeyEncryptionAlgorithm.pszObjId          = hb.AllocAsciiString(Oids.Rsa);
                        pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = (uint)s_rsaPkcsParameters.Length;
                        pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(s_rsaPkcsParameters);
                    }
                    else if (recipient.RSAEncryptionPadding == RSAEncryptionPadding.OaepSHA1)
                    {
                        pEncodeInfo->KeyEncryptionAlgorithm.pszObjId          = hb.AllocAsciiString(Oids.RsaOaep);
                        pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = (uint)s_rsaOaepSha1Parameters.Length;
                        pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(s_rsaOaepSha1Parameters);
                    }
                    else if (recipient.RSAEncryptionPadding == RSAEncryptionPadding.OaepSHA256)
                    {
                        pEncodeInfo->KeyEncryptionAlgorithm.pszObjId          = hb.AllocAsciiString(Oids.RsaOaep);
                        pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = (uint)s_rsaOaepSha256Parameters.Length;
                        pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(s_rsaOaepSha256Parameters);
                    }
                    else if (recipient.RSAEncryptionPadding == RSAEncryptionPadding.OaepSHA384)
                    {
                        pEncodeInfo->KeyEncryptionAlgorithm.pszObjId          = hb.AllocAsciiString(Oids.RsaOaep);
                        pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = (uint)s_rsaOaepSha384Parameters.Length;
                        pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(s_rsaOaepSha384Parameters);
                    }
                    else if (recipient.RSAEncryptionPadding == RSAEncryptionPadding.OaepSHA512)
                    {
                        pEncodeInfo->KeyEncryptionAlgorithm.pszObjId          = hb.AllocAsciiString(Oids.RsaOaep);
                        pEncodeInfo->KeyEncryptionAlgorithm.Parameters.cbData = (uint)s_rsaOaepSha512Parameters.Length;
                        pEncodeInfo->KeyEncryptionAlgorithm.Parameters.pbData = hb.AllocBytes(s_rsaOaepSha512Parameters);
                    }
                    else
                    {
                        throw ErrorCode.CRYPT_E_UNKNOWN_ALGO.ToCryptographicException();
                    }

                    pEncodeInfo->pvKeyEncryptionAuxInfo = IntPtr.Zero;
                    pEncodeInfo->hCryptProv             = IntPtr.Zero;

                    pEncodeInfo->RecipientPublicKey = pCertInfo->SubjectPublicKeyInfo.PublicKey;

                    pEncodeInfo->RecipientId = EncodeRecipientId(recipient, hCertContext, pCertContext, pCertInfo, hb);

                    return(pEncodeInfo);
                }
            }
Exemple #20
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
     );
Exemple #21
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);
        }