/* Myrtille: A native HTML4/5 Remote Desktop Protocol client. Copyright(c) 2014-2021 Cedric Coste Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ using System; using System.Diagnostics; using System.Security.Cryptography.X509Certificates; using CertEnroll_Interop; namespace Myrtille.Helpers { public static class CertificateHelper { public static X509Certificate2 CreateSelfSignedCertificate(string issuer, string name) { // CAUTION! this method fails under "vanilla" Windows 2008 and requires an adaptation for a Windows 10 build // see http://stackoverflow.com/questions/33001983/issues-compiling-in-windows-10/35365099#35365099 try { // create a DN for issuer and subject var dn = new CX500DistinguishedName(); dn.Encode("CN=" + issuer, X500NameFlags.XCN_CERT_NAME_STR_NONE); // create a private key for the certificate var privateKey = (IX509PrivateKey)Activator.CreateInstance(Type.GetTypeFromProgID("X509Enrollment.CX509PrivateKey")); privateKey.ProviderName = "Microsoft Base Cryptographic Provider v1.0"; privateKey.MachineContext = true; privateKey.Length = 2048; privateKey.KeySpec = X509KeySpec.XCN_AT_SIGNATURE; privateKey.ExportPolicy = X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG; privateKey.Create(); // use the stronger SHA512 hashing algorithm var hashobj = new CObjectId(); hashobj.InitializeFromAlgorithmName(ObjectIdGroupId.XCN_CRYPT_HASH_ALG_OID_GROUP_ID, ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY, AlgorithmFlags.AlgorithmFlagsNone, "SHA512"); // add extended key usage (look at MSDN for a list of possible OIDs) var oid = new CObjectId(); oid.InitializeFromValue("1.3.6.1.5.5.7.3.1"); // SSL server var oidlist = new CObjectIds(); oidlist.Add(oid); var eku = new CX509ExtensionEnhancedKeyUsage(); eku.InitializeEncode(oidlist); // create the self signing request var cert = (IX509CertificateRequestCertificate)Activator.CreateInstance(Type.GetTypeFromProgID("X509Enrollment.CX509CertificateRequestCertificate")); // Windows 2008 R2 and above cert.InitializeFromPrivateKey(X509CertificateEnrollmentContext.ContextMachine, (CX509PrivateKey)privateKey, ""); // Windows 10 //cert.InitializeFromPrivateKey(X509CertificateEnrollmentContext.ContextMachine, privateKey, ""); cert.Issuer = dn; cert.Subject = dn; cert.NotBefore = DateTime.Now; cert.NotAfter = DateTime.Now.AddYears(1); // 1 year expiration cert.X509Extensions.Add((CX509Extension)eku); cert.HashAlgorithm = hashobj; cert.Encode(); // do the final enrollment process var enroll = (IX509Enrollment)Activator.CreateInstance(Type.GetTypeFromProgID("X509Enrollment.CX509Enrollment")); enroll.InitializeFromRequest(cert); enroll.CertificateFriendlyName = name; string csr = enroll.CreateRequest(); // output a base64 encoded PKCS#12 enroll.InstallResponse(InstallResponseRestrictionFlags.AllowUntrustedCertificate, csr, EncodingType.XCN_CRYPT_STRING_BASE64, ""); var base64encoded = enroll.CreatePFX("", PFXExportOptions.PFXExportChainWithRoot); // return the certificate return new X509Certificate2(Convert.FromBase64String(base64encoded), "", X509KeyStorageFlags.Exportable); } catch (Exception exc) { Trace.TraceError("Failed to create a self-signed certificate ({0})", exc); throw; } } } }