Skip to content

Instantly share code, notes, and snippets.

@jimmyca15
Created December 13, 2017 02:10
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save jimmyca15/8f737f5f0bcf347450bd6d6bf34f4f7e to your computer and use it in GitHub Desktop.
Save jimmyca15/8f737f5f0bcf347450bd6d6bf34f4f7e to your computer and use it in GitHub Desktop.
Code for creating a self signed certificate in .NET Core using CertEnroll APIs
namespace CreateCert
{
using System;
using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
class Certificate
{
public static async Task<X509Certificate2> Create(string subject, string friendlyName, IEnumerable<string> alternativeNames)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentNullException(nameof(subject));
}
string issuer = subject;
var subjectDn = new CX500DistinguishedNameClass();
subjectDn.Encode($"CN={subject}", X500NameFlags.XCN_CERT_NAME_STR_NONE);
var issuerDn = new CX500DistinguishedNameClass();
issuerDn.Encode($"CN={issuer}", X500NameFlags.XCN_CERT_NAME_STR_NONE);
var key = new CX509PrivateKeyClass();
key.ProviderName = "Microsoft RSA SChannel Cryptographic Provider";
key.Length = 2048;
//
// False: Current User, True: Local Machine
key.MachineContext = true;
key.Create();
var cert = new CX509CertificateRequestCertificateClass();
cert.InitializeFromPrivateKey(X509CertificateEnrollmentContext.ContextMachine, key, string.Empty);
cert.Subject = subjectDn;
cert.Issuer = issuerDn;
cert.NotBefore = DateTime.UtcNow.AddMinutes(-10);
cert.NotAfter = cert.NotBefore.AddYears(2);
var hashAlgorithm = new CObjectIdClass();
hashAlgorithm.InitializeFromAlgorithmName(ObjectIdGroupId.XCN_CRYPT_FIRST_ALG_OID_GROUP_ID, ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY, AlgorithmFlags.AlgorithmFlagsNone, "SHA256");
cert.HashAlgorithm = hashAlgorithm;
var clientAuthOid = new CObjectIdClass();
clientAuthOid.InitializeFromValue("1.3.6.1.5.5.7.3.2");
var serverAuthOid = new CObjectIdClass();
serverAuthOid.InitializeFromValue("1.3.6.1.5.5.7.3.1");
var ekuOids = new CObjectIdsClass();
ekuOids.Add(clientAuthOid);
ekuOids.Add(serverAuthOid);
var ekuExt = new CX509ExtensionEnhancedKeyUsageClass();
ekuExt.InitializeEncode(ekuOids);
cert.X509Extensions.Add(ekuExt);
var keyUsage = new CX509ExtensionKeyUsageClass();
var flags = X509KeyUsageFlags.XCN_CERT_KEY_ENCIPHERMENT_KEY_USAGE | X509KeyUsageFlags.XCN_CERT_DIGITAL_SIGNATURE_KEY_USAGE;
keyUsage.InitializeEncode(flags);
cert.X509Extensions.Add(keyUsage);
if (alternativeNames != null)
{
var names = new CAlternativeNamesClass();
var altnames = new CX509ExtensionAlternativeNamesClass();
foreach (string n in alternativeNames)
{
var name = new CAlternativeNameClass();
// Dns Alternative Name
name.InitializeFromString(AlternativeNameType.XCN_CERT_ALT_NAME_DNS_NAME, n);
names.Add(name);
}
altnames.InitializeEncode(names);
cert.X509Extensions.Add(altnames);
}
cert.Encode();
string locator = Guid.NewGuid().ToString();
var enrollment = new CX509EnrollmentClass();
enrollment.CertificateFriendlyName = locator;
// TODO get certificates see if any have name of friendlyName
// if so append (1) or (2) or so forth to friendlyname, even if friendlyname is the empty string
// create with criendlyname
enrollment.InitializeFromRequest(cert);
string certdata = enrollment.CreateRequest(EncodingType.XCN_CRYPT_STRING_BASE64HEADER);
enrollment.InstallResponse(InstallResponseRestrictionFlags.AllowUntrustedCertificate, certdata, EncodingType.XCN_CRYPT_STRING_BASE64HEADER, string.Empty);
await Task.Delay(1000);
X509Certificate2 retCert = null;
using (var store = new X509Store(StoreName.My, StoreLocation.LocalMachine))
{
store.Open(OpenFlags.ReadWrite);
foreach (var certificate in store.Certificates)
{
if (certificate.FriendlyName == locator)
{
retCert = certificate;
//
// Must update friendlyname while store is still open
if (retCert != null && friendlyName != null)
{
retCert.FriendlyName = friendlyName;
}
break;
}
}
}
return retCert;
}
}
public enum X500NameFlags
{
XCN_CERT_NAME_STR_AMBIGUOUS_SEPARATOR_FLAGS = 0x4c000000,
XCN_CERT_NAME_STR_COMMA_FLAG = 0x4000000,
XCN_CERT_NAME_STR_CRLF_FLAG = 0x8000000,
XCN_CERT_NAME_STR_DISABLE_IE4_UTF8_FLAG = 0x10000,
XCN_CERT_NAME_STR_DISABLE_UTF8_DIR_STR_FLAG = 0x100000,
XCN_CERT_NAME_STR_DS_ESCAPED = 0x800000,
XCN_CERT_NAME_STR_ENABLE_PUNYCODE_FLAG = 0x200000,
XCN_CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG = 0x20000,
XCN_CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG = 0x40000,
XCN_CERT_NAME_STR_FORCE_UTF8_DIR_STR_FLAG = 0x80000,
XCN_CERT_NAME_STR_FORWARD_FLAG = 0x1000000,
XCN_CERT_NAME_STR_NO_PLUS_FLAG = 0x20000000,
XCN_CERT_NAME_STR_NO_QUOTING_FLAG = 0x10000000,
XCN_CERT_NAME_STR_NONE = 0,
XCN_CERT_NAME_STR_REVERSE_FLAG = 0x2000000,
XCN_CERT_NAME_STR_SEMICOLON_FLAG = 0x40000000,
XCN_CERT_OID_NAME_STR = 2,
XCN_CERT_SIMPLE_NAME_STR = 1,
XCN_CERT_X500_NAME_STR = 3,
XCN_CERT_XML_NAME_STR = 4
}
public enum EncodingType
{
XCN_CRYPT_STRING_ANY = 7,
XCN_CRYPT_STRING_BASE64 = 1,
XCN_CRYPT_STRING_BASE64_ANY = 6,
XCN_CRYPT_STRING_BASE64HEADER = 0,
XCN_CRYPT_STRING_BASE64REQUESTHEADER = 3,
XCN_CRYPT_STRING_BASE64URI = 13,
XCN_CRYPT_STRING_BASE64X509CRLHEADER = 9,
XCN_CRYPT_STRING_BINARY = 2,
XCN_CRYPT_STRING_CHAIN = 0x100,
XCN_CRYPT_STRING_ENCODEMASK = 0xff,
XCN_CRYPT_STRING_HASHDATA = 0x10000000,
XCN_CRYPT_STRING_HEX = 4,
XCN_CRYPT_STRING_HEX_ANY = 8,
XCN_CRYPT_STRING_HEXADDR = 10,
XCN_CRYPT_STRING_HEXASCII = 5,
XCN_CRYPT_STRING_HEXASCIIADDR = 11,
XCN_CRYPT_STRING_HEXRAW = 12,
XCN_CRYPT_STRING_NOCR = -2147483648,
XCN_CRYPT_STRING_NOCRLF = 0x40000000,
XCN_CRYPT_STRING_PERCENTESCAPE = 0x8000000,
XCN_CRYPT_STRING_STRICT = 0x20000000,
XCN_CRYPT_STRING_TEXT = 0x200
}
public enum ObjectIdGroupId
{
XCN_CRYPT_ANY_GROUP_ID = 0,
XCN_CRYPT_ENCRYPT_ALG_OID_GROUP_ID = 2,
XCN_CRYPT_ENHKEY_USAGE_OID_GROUP_ID = 7,
XCN_CRYPT_EXT_OR_ATTR_OID_GROUP_ID = 6,
XCN_CRYPT_FIRST_ALG_OID_GROUP_ID = 1,
XCN_CRYPT_GROUP_ID_MASK = 0xffff,
XCN_CRYPT_HASH_ALG_OID_GROUP_ID = 1,
XCN_CRYPT_KEY_LENGTH_MASK = 0xfff0000,
XCN_CRYPT_LAST_ALG_OID_GROUP_ID = 4,
XCN_CRYPT_LAST_OID_GROUP_ID = 10,
XCN_CRYPT_OID_DISABLE_SEARCH_DS_FLAG = -2147483648,
XCN_CRYPT_OID_INFO_OID_GROUP_BIT_LEN_MASK = 0xfff0000,
XCN_CRYPT_OID_INFO_OID_GROUP_BIT_LEN_SHIFT = 0x10,
XCN_CRYPT_OID_PREFER_CNG_ALGID_FLAG = 0x40000000,
XCN_CRYPT_POLICY_OID_GROUP_ID = 8,
XCN_CRYPT_PUBKEY_ALG_OID_GROUP_ID = 3,
XCN_CRYPT_RDN_ATTR_OID_GROUP_ID = 5,
XCN_CRYPT_SIGN_ALG_OID_GROUP_ID = 4,
XCN_CRYPT_TEMPLATE_OID_GROUP_ID = 9
}
public enum ObjectIdPublicKeyFlags
{
XCN_CRYPT_OID_INFO_PUBKEY_ANY = 0,
XCN_CRYPT_OID_INFO_PUBKEY_ENCRYPT_KEY_FLAG = 0x40000000,
XCN_CRYPT_OID_INFO_PUBKEY_SIGN_KEY_FLAG = -2147483648
}
public enum X509CertificateEnrollmentContext
{
ContextNone = 0,
ContextUser = 1,
ContextMachine = 2,
ContextAdministratorForceMachine = 3
}
public enum AlgorithmFlags
{
AlgorithmFlagsNone,
AlgorithmFlagsWrap
}
public enum X509KeyUsageFlags
{
XCN_CERT_CRL_SIGN_KEY_USAGE = 2,
XCN_CERT_DATA_ENCIPHERMENT_KEY_USAGE = 0x10,
XCN_CERT_DECIPHER_ONLY_KEY_USAGE = 0x8000,
XCN_CERT_DIGITAL_SIGNATURE_KEY_USAGE = 0x80,
XCN_CERT_ENCIPHER_ONLY_KEY_USAGE = 1,
XCN_CERT_KEY_AGREEMENT_KEY_USAGE = 8,
XCN_CERT_KEY_CERT_SIGN_KEY_USAGE = 4,
XCN_CERT_KEY_ENCIPHERMENT_KEY_USAGE = 0x20,
XCN_CERT_NO_KEY_USAGE = 0,
XCN_CERT_NON_REPUDIATION_KEY_USAGE = 0x40,
XCN_CERT_OFFLINE_CRL_SIGN_KEY_USAGE = 2
}
public enum AlternativeNameType
{
XCN_CERT_ALT_NAME_DIRECTORY_NAME = 5,
XCN_CERT_ALT_NAME_DNS_NAME = 3,
XCN_CERT_ALT_NAME_GUID = 10,
XCN_CERT_ALT_NAME_IP_ADDRESS = 8,
XCN_CERT_ALT_NAME_OTHER_NAME = 1,
XCN_CERT_ALT_NAME_REGISTERED_ID = 9,
XCN_CERT_ALT_NAME_RFC822_NAME = 2,
XCN_CERT_ALT_NAME_UNKNOWN = 0,
XCN_CERT_ALT_NAME_URL = 7,
XCN_CERT_ALT_NAME_USER_PRINCIPLE_NAME = 11
}
public enum InstallResponseRestrictionFlags
{
AllowNone = 0,
AllowNoOutstandingRequest = 1,
AllowUntrustedCertificate = 2,
AllowUntrustedRoot = 4
}
public abstract class CertEnrollWrapper
{
protected object _instance;
private Type _type = null;
public CertEnrollWrapper()
{
if (Type != null)
{
_instance = Activator.CreateInstance(Type);
}
}
protected abstract string TypeName { get; }
public CertEnrollWrapper(object instance)
{
_instance = instance;
}
public object Instance {
get => _instance;
}
protected Type Type {
get {
if (_type == null)
{
_type = Type.GetTypeFromProgID(TypeName);
}
return _type;
}
}
}
public class CX509EnrollmentClass : CertEnrollWrapper
{
public CX509EnrollmentClass() : base() { }
protected override string TypeName {
get => "X509Enrollment.CX509Enrollment";
}
public string CreateRequest(EncodingType Encoding)
{
return (string)Type.InvokeMember(nameof(CreateRequest), System.Reflection.BindingFlags.InvokeMethod, null, _instance, new object[] { Encoding });
}
public void InitializeFromRequest(CX509CertificateRequestCertificateClass pRequest)
{
Type.InvokeMember(nameof(InitializeFromRequest), System.Reflection.BindingFlags.InvokeMethod, null, _instance, new object[] { pRequest.Instance });
}
public void InstallResponse(InstallResponseRestrictionFlags Restrictions, string strResponse, EncodingType Encoding, string strPassword)
{
Type.InvokeMember(nameof(InstallResponse), System.Reflection.BindingFlags.InvokeMethod, null, _instance, new object[] { Restrictions, strResponse, Encoding, strPassword });
}
public string CertificateFriendlyName {
get => (string)Type.InvokeMember(nameof(CertificateFriendlyName), System.Reflection.BindingFlags.GetProperty, null, _instance, null);
set => Type.InvokeMember(nameof(CertificateFriendlyName), System.Reflection.BindingFlags.SetProperty, null, _instance, new object[] { value });
}
}
public class CAlternativeNameClass : CertEnrollWrapper
{
public CAlternativeNameClass() : base() { }
protected override string TypeName {
get => "X509Enrollment.CAlternativeName";
}
public void InitializeFromString(AlternativeNameType type, string strValue)
{
Type.InvokeMember(nameof(InitializeFromString), System.Reflection.BindingFlags.InvokeMethod, null, _instance, new object[] { type, strValue });
}
}
public class CAlternativeNamesClass : CertEnrollWrapper
{
public CAlternativeNamesClass() : base() { }
protected override string TypeName {
get => "X509Enrollment.CAlternativeNames";
}
public void Add(CAlternativeNameClass pVal)
{
Type.InvokeMember(nameof(Add), System.Reflection.BindingFlags.InvokeMethod, null, _instance, new object[] { pVal.Instance });
}
}
public class CX509ExtensionAlternativeNamesClass : CertEnrollWrapper
{
public CX509ExtensionAlternativeNamesClass() : base() { }
protected override string TypeName {
get => "X509Enrollment.CX509ExtensionAlternativeNames";
}
public void InitializeEncode(CAlternativeNamesClass pValue)
{
Type.InvokeMember(nameof(InitializeEncode), System.Reflection.BindingFlags.InvokeMethod, null, _instance, new object[] { pValue.Instance });
}
}
public class CObjectIdClass : CertEnrollWrapper
{
public CObjectIdClass() : base() { }
public CObjectIdClass(object instance) : base(instance) { }
protected override string TypeName {
get => "X509Enrollment.CObjectId";
}
public void InitializeFromAlgorithmName(ObjectIdGroupId GroupId, ObjectIdPublicKeyFlags KeyFlags, AlgorithmFlags AlgFlags, string strAlgorithmName)
{
Type.InvokeMember(nameof(InitializeFromAlgorithmName), System.Reflection.BindingFlags.InvokeMethod, null, _instance, new object[] { GroupId, KeyFlags, AlgFlags, strAlgorithmName });
}
public void InitializeFromValue(string strValue)
{
Type.InvokeMember(nameof(InitializeFromValue), System.Reflection.BindingFlags.InvokeMethod, null, _instance, new object[] { strValue });
}
}
public class CObjectIdsClass : CertEnrollWrapper
{
public CObjectIdsClass() : base() { }
protected override string TypeName {
get => "X509Enrollment.CObjectIds";
}
public void Add(CObjectIdClass value)
{
Type.InvokeMember(nameof(Add), System.Reflection.BindingFlags.InvokeMethod, null, _instance, new object[] { value.Instance });
}
}
public class CX509ExtensionClass : CertEnrollWrapper
{
public CX509ExtensionClass() : base() { }
public CX509ExtensionClass(object instance) : base(instance) { }
protected override string TypeName {
get => "X509Enrollment.CX509Extension";
}
public void Initialize(CObjectIdsClass pObjectId, string strEncodedData)
{
Type.InvokeMember(nameof(Initialize), System.Reflection.BindingFlags.InvokeMethod, null, _instance, new object[] { pObjectId.Instance, strEncodedData });
}
}
public class CX509ExtensionEnhancedKeyUsageClass : CertEnrollWrapper
{
public CX509ExtensionEnhancedKeyUsageClass() : base() { }
protected override string TypeName {
get => "X509Enrollment.CX509ExtensionEnhancedKeyUsage";
}
public void InitializeEncode(CObjectIdsClass value)
{
Type.InvokeMember(nameof(InitializeEncode), System.Reflection.BindingFlags.InvokeMethod, null, _instance, new object[] { value.Instance });
}
}
public class CX509ExtensionKeyUsageClass : CertEnrollWrapper
{
public CX509ExtensionKeyUsageClass() : base() { }
protected override string TypeName {
get => "X509Enrollment.CX509ExtensionKeyUsage";
}
public void InitializeEncode(X509KeyUsageFlags UsageFlags)
{
Type.InvokeMember(nameof(InitializeEncode), System.Reflection.BindingFlags.InvokeMethod, null, _instance, new object[] { UsageFlags });
}
}
public class CX509ExtensionsClass : CertEnrollWrapper
{
public CX509ExtensionsClass() : base() { }
public CX509ExtensionsClass(object instance) : base(instance) { }
protected override string TypeName {
get => "X509Enrollment.CX509Extensions";
}
public void Add(CX509ExtensionClass value)
{
Type.InvokeMember(nameof(Add), System.Reflection.BindingFlags.InvokeMethod, null, _instance, new object[] { value.Instance });
}
public void Add(CX509ExtensionEnhancedKeyUsageClass value)
{
Type.InvokeMember(nameof(Add), System.Reflection.BindingFlags.InvokeMethod, null, _instance, new object[] { value.Instance });
}
public void Add(CX509ExtensionKeyUsageClass value)
{
Type.InvokeMember(nameof(Add), System.Reflection.BindingFlags.InvokeMethod, null, _instance, new object[] { value.Instance });
}
public void Add(CX509ExtensionAlternativeNamesClass value)
{
Type.InvokeMember(nameof(Add), System.Reflection.BindingFlags.InvokeMethod, null, _instance, new object[] { value.Instance });
}
}
public class CX500DistinguishedNameClass : CertEnrollWrapper
{
public CX500DistinguishedNameClass() : base() { }
public CX500DistinguishedNameClass(object instance) : base(instance) { }
protected override string TypeName {
get => "X509Enrollment.CX500DistinguishedName";
}
public string Name {
get {
return (string)Type.InvokeMember(nameof(Name), System.Reflection.BindingFlags.GetProperty, null, _instance, null);
}
}
public void Encode(string name, X500NameFlags flags)
{
Type.InvokeMember(nameof(Encode), System.Reflection.BindingFlags.InvokeMethod, null, _instance, new object[] { name, flags });
}
}
public class CX509PrivateKeyClass : CertEnrollWrapper
{
public CX509PrivateKeyClass() : base() { }
protected override string TypeName {
get => "X509Enrollment.CX509PrivateKey";
}
public int Length {
get => (int)Type.InvokeMember(nameof(Length), System.Reflection.BindingFlags.GetProperty, null, _instance, null);
set => Type.InvokeMember(nameof(Length), System.Reflection.BindingFlags.SetProperty, null, _instance, new object[] { value });
}
public bool MachineContext {
get => (bool)Type.InvokeMember(nameof(MachineContext), System.Reflection.BindingFlags.GetProperty, null, _instance, null);
set => Type.InvokeMember(nameof(MachineContext), System.Reflection.BindingFlags.SetProperty, null, _instance, new object[] { value });
}
public string ProviderName {
get => (string)Type.InvokeMember(nameof(ProviderName), System.Reflection.BindingFlags.GetProperty, null, _instance, null);
set => Type.InvokeMember(nameof(ProviderName), System.Reflection.BindingFlags.SetProperty, null, _instance, new object[] { value });
}
public void Create()
{
Type.InvokeMember(nameof(Create), System.Reflection.BindingFlags.InvokeMethod, null, _instance, null);
}
}
public class CX509CertificateRequestCertificateClass : CertEnrollWrapper
{
public CX509CertificateRequestCertificateClass() : base() { }
protected override string TypeName {
get => "X509Enrollment.CX509CertificateRequestCertificate";
}
public CObjectIdClass HashAlgorithm {
get => new CObjectIdClass(Type.InvokeMember(nameof(HashAlgorithm), System.Reflection.BindingFlags.GetProperty, null, _instance, null));
set => Type.InvokeMember(nameof(HashAlgorithm), System.Reflection.BindingFlags.SetProperty, null, _instance, new object[] { value.Instance });
}
public CX500DistinguishedNameClass Issuer {
get => new CX500DistinguishedNameClass(Type.InvokeMember(nameof(Issuer), System.Reflection.BindingFlags.GetProperty, null, _instance, null));
set => Type.InvokeMember(nameof(Issuer), System.Reflection.BindingFlags.SetProperty, null, _instance, new object[] { value.Instance });
}
public DateTime NotAfter {
get => (DateTime)Type.InvokeMember(nameof(NotAfter), System.Reflection.BindingFlags.GetProperty, null, _instance, null);
set => Type.InvokeMember(nameof(NotAfter), System.Reflection.BindingFlags.SetProperty, null, _instance, new object[] { value });
}
public DateTime NotBefore {
get => (DateTime)Type.InvokeMember(nameof(NotBefore), System.Reflection.BindingFlags.GetProperty, null, _instance, null);
set => Type.InvokeMember(nameof(NotBefore), System.Reflection.BindingFlags.SetProperty, null, _instance, new object[] { value });
}
public CX500DistinguishedNameClass Subject {
get => new CX500DistinguishedNameClass(Type.InvokeMember(nameof(Subject), System.Reflection.BindingFlags.GetProperty, null, _instance, null));
set => Type.InvokeMember(nameof(Subject), System.Reflection.BindingFlags.SetProperty, null, _instance, new object[] { value.Instance });
}
public CX509ExtensionsClass X509Extensions {
get => new CX509ExtensionsClass(Type.InvokeMember(nameof(X509Extensions), System.Reflection.BindingFlags.GetProperty, null, _instance, null));
set => Type.InvokeMember(nameof(X509Extensions), System.Reflection.BindingFlags.SetProperty, null, _instance, new object[] { value.Instance });
}
public void Encode()
{
Type.InvokeMember(nameof(Encode), System.Reflection.BindingFlags.InvokeMethod, null, _instance, null);
}
public void InitializeFromPrivateKey(X509CertificateEnrollmentContext Context, CX509PrivateKeyClass pPrivateKey, string strTemplateName)
{
Type.InvokeMember(nameof(InitializeFromPrivateKey), System.Reflection.BindingFlags.InvokeMethod, null, _instance, new object[] { Context, pPrivateKey.Instance, strTemplateName });
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment