Depends on using BouncyCastle nuget package for the certificate generation.
Last active
August 29, 2015 14:23
-
-
Save dealproc/f20882d0defb9acbdf4a to your computer and use it in GitHub Desktop.
Issuing a Self-Signed certificate
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Mono.Options; | |
using Org.BouncyCastle.Crypto; | |
using Org.BouncyCastle.Security; | |
using System; | |
using System.Security.Cryptography.X509Certificates; | |
namespace testssl { | |
class Program { | |
//http://blogs.msdn.com/b/dcook/archive/2008/11/25/creating-a-self-signed-certificate-in-c.aspx | |
//http://www.wiktorzychla.com/2012/12/how-to-create-x509certificate2.html | |
static CertificateCategory _toCreate = CertificateCategory.Unknown; | |
static string _certSubject = ""; | |
static string _certIssuer = ""; | |
static string _privateKeyFile = ""; | |
static string _fileNameBase = ""; | |
static string _pksFilePassword = ""; | |
static bool show_help = false; | |
static int Main(string[] args) { | |
var x = ParseParameters(args); | |
if (x != 0) { return x; } | |
AsymmetricCipherKeyPair myCAKey = null; | |
switch (_toCreate) { | |
case CertificateCategory.ClientCert: | |
Console.WriteLine("Opening .key file."); | |
myCAKey = Certificates.Import(_privateKeyFile); | |
Console.WriteLine("Generating Client Certificate"); | |
var clientCert = Certificates.ClientCertificate.Generate(_certSubject.EnsureCNPrefix(), _certIssuer.EnsureCNPrefix(), myCAKey.Private); | |
var finalFileName = _fileNameBase + "-client.pfx"; | |
Console.WriteLine("Saving to: " + finalFileName); | |
Certificates.SaveToFile(DotNetUtilities.FromX509Certificate(clientCert), myCAKey, finalFileName, _certSubject, _pksFilePassword); | |
break; | |
case CertificateCategory.TrustedCA: | |
Console.WriteLine("Generating Root CA and Key"); | |
X509Certificate2 rootCA = Certificates.CertificateAuthority.Generate(_certSubject.EnsureCNPrefix(), ref myCAKey); | |
Console.WriteLine("Saving CA Certificate"); | |
Certificates.SaveToFile(DotNetUtilities.FromX509Certificate(rootCA), myCAKey, _fileNameBase + ".pfx", _certSubject, _pksFilePassword); | |
Console.WriteLine("Saving *.key file"); | |
Certificates.ExportKey(myCAKey, _fileNameBase + ".key"); | |
break; | |
default: | |
Console.WriteLine("Unknown command."); | |
return -1; | |
} | |
Console.WriteLine("done!"); | |
#if DEBUG | |
Console.ReadLine(); | |
#endif | |
return 0; | |
} | |
private static int ParseParameters(string[] args) { | |
var p = new OptionSet{ | |
{ | |
"t|type=" , "The type of certificate to generate: (CA/Client)", v => { | |
switch (v.ToLower()) { | |
case "ca": | |
_toCreate = CertificateCategory.TrustedCA; | |
break; | |
case "client": | |
_toCreate = CertificateCategory.ClientCert; | |
break; | |
} | |
} | |
}, | |
{ "p|password=", "The password for the pfx file.", v => _pksFilePassword = v }, | |
{ "s|subject=", "The subject of the certificate", v => _certSubject = v }, | |
{ "i|issuer=", "The CA Issuer (for client certificates)", v => _certIssuer = v }, | |
{ "k|key=", "The signing key file (for client certificates)", v => _privateKeyFile = v }, | |
{ "f|file=", "The output file, minus the extension (we add that for you)", v => _fileNameBase = v }, | |
{ "h|help", "Show this message and exit", v => show_help = v != null } | |
}; | |
try { | |
p.Parse(args); | |
} catch (OptionException e) { | |
Console.WriteLine("testssl: "); | |
Console.WriteLine(e.Message); | |
Console.WriteLine("Try `testssl --help ` for more information."); | |
return -1; | |
} | |
return 0; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Org.BouncyCastle.Asn1; | |
using Org.BouncyCastle.Asn1.Pkcs; | |
using Org.BouncyCastle.Asn1.X509; | |
using Org.BouncyCastle.Crypto; | |
using Org.BouncyCastle.Crypto.Generators; | |
using Org.BouncyCastle.Crypto.Parameters; | |
using Org.BouncyCastle.Crypto.Prng; | |
using Org.BouncyCastle.Math; | |
using Org.BouncyCastle.OpenSsl; | |
using Org.BouncyCastle.Pkcs; | |
using Org.BouncyCastle.Security; | |
using Org.BouncyCastle.Utilities; | |
using Org.BouncyCastle.X509; | |
using System; | |
using System.IO; | |
using System.Security.Cryptography.X509Certificates; | |
namespace testssl { | |
public static class Certificates { | |
/// <summary> | |
/// Saves a bouncycastle certificate to a pfx file, with the private key. | |
/// </summary> | |
/// <param name="newCert"></param> | |
/// <param name="kp"></param> | |
/// <param name="fileStream"></param> | |
/// <param name="CertAlias"></param> | |
/// <param name="Password"></param> | |
public static void SaveToFile(Org.BouncyCastle.X509.X509Certificate newCert, AsymmetricCipherKeyPair kp, string FilePath, string CertAlias, string Password) { | |
using (var certFile = File.Create(FilePath)) { | |
SaveToFile(newCert, kp, certFile, CertAlias, Password); | |
} | |
} | |
/// <summary> | |
/// Saves a bouncycastle certificate to a stream, with the private key. | |
/// <remarks>Useful for unit testing scenarios</remarks> | |
/// </summary> | |
/// <param name="newCert"></param> | |
/// <param name="kp"></param> | |
/// <param name="fileStream"></param> | |
/// <param name="CertAlias"></param> | |
/// <param name="Password"></param> | |
public static void SaveToFile(Org.BouncyCastle.X509.X509Certificate newCert, AsymmetricCipherKeyPair kp, Stream fileStream, string CertAlias, string Password) { | |
var newStore = new Pkcs12Store(); | |
var certEntry = new X509CertificateEntry(newCert); | |
newStore.SetCertificateEntry(CertAlias, certEntry); | |
newStore.SetKeyEntry(CertAlias, new AsymmetricKeyEntry(kp.Private), new[] { certEntry }); | |
newStore.Save(fileStream, Password.ToCharArray(), new SecureRandom(new CryptoApiRandomGenerator())); | |
} | |
/// <summary> | |
/// Reads a pfx file into memory, converting it to a bouncycastle certificate. | |
/// </summary> | |
/// <param name="FilePath"></param> | |
/// <param name="password"></param> | |
/// <returns></returns> | |
public static Org.BouncyCastle.X509.X509Certificate OpenFromFile(string FilePath, string password) { | |
return DotNetUtilities.FromX509Certificate(new X509Certificate2(FilePath, password)); | |
} | |
/// <summary> | |
/// Reads a pfx stream, converting it to a bouncycastle certificate. | |
/// </summary> | |
/// <param name="stream"></param> | |
/// <param name="password"></param> | |
/// <returns></returns> | |
public static Org.BouncyCastle.X509.X509Certificate OpenFromFile(Stream stream, string password) { | |
return DotNetUtilities.FromX509Certificate(new X509Certificate2(ReadStream(stream), password)); | |
} | |
public static AsymmetricCipherKeyPair Generate(int strength = 2048) { | |
var randomGenerator = new CryptoApiRandomGenerator(); | |
var random = new SecureRandom(randomGenerator); | |
var keyGenerationParameters = new KeyGenerationParameters(random, strength); | |
var keyPairGenerator = new RsaKeyPairGenerator(); | |
keyPairGenerator.Init(keyGenerationParameters); | |
return keyPairGenerator.GenerateKeyPair(); | |
} | |
public static void ExportKey(AsymmetricCipherKeyPair myCAKey, string fileName) { | |
using (var fStream = File.OpenWrite(fileName)) { | |
ExportKey(myCAKey, fStream); | |
} | |
} | |
public static void ExportKey(AsymmetricCipherKeyPair myCAKey, Stream s) { | |
PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(myCAKey.Private); | |
TextWriter tw = new StreamWriter(s); | |
PemWriter pw = new PemWriter(tw); | |
pw.WriteObject(myCAKey.Private); | |
pw.Writer.Flush(); | |
} | |
public static AsymmetricCipherKeyPair Import(string fileName) { | |
using (var fStream = File.Open(fileName, FileMode.Open)) { | |
return Import(fStream); | |
} | |
} | |
public static AsymmetricCipherKeyPair Import(Stream s) { | |
using (TextReader tr = new StreamReader(s)) { | |
PemReader pr = new PemReader(tr); | |
return (AsymmetricCipherKeyPair)pr.ReadObject(); | |
} | |
} | |
//http://stackoverflow.com/questions/844997/encrypting-a-bouncycastle-rsa-key-pair-and-storing-in-a-sql2008-database | |
public static bool addCertToStore(System.Security.Cryptography.X509Certificates.X509Certificate2 cert, StoreName st, StoreLocation sl) { | |
bool bRet = false; | |
try { | |
X509Store store = new X509Store(st, sl); | |
store.Open(OpenFlags.ReadWrite); | |
store.Add(cert); | |
store.Close(); | |
} catch { | |
} | |
return bRet; | |
} | |
public static X509Certificate2 getCertFromStore(StoreName st, StoreLocation sl, string issuerName) { | |
try { | |
X509Store store = new X509Store(st, sl); | |
store.Open(OpenFlags.OpenExistingOnly); | |
var certCollection = store.Certificates.Find(X509FindType.FindByIssuerName, issuerName, false); | |
if (certCollection.Count > 0) { | |
return certCollection[0]; | |
} | |
} catch { | |
} | |
return null; | |
} | |
private static byte[] ReadStream(System.IO.Stream input) { | |
byte[] buffer = new byte[16 * 1024]; | |
using (MemoryStream ms = new MemoryStream()) { | |
int read; | |
while ((read = input.Read(buffer, 0, buffer.Length)) > 0) { | |
ms.Write(buffer, 0, read); | |
} | |
return ms.ToArray(); | |
} | |
} | |
public static class ClientCertificate { | |
public static X509Certificate2 Generate(string subjectName, string issuerName, AsymmetricKeyParameter issuerPrivKey) { | |
const int keyStrength = 2048; | |
// Generating Random Numbers | |
CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator(); | |
SecureRandom random = new SecureRandom(randomGenerator); | |
// The Certificate Generator | |
X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator(); | |
// Serial Number | |
BigInteger serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random); | |
certificateGenerator.SetSerialNumber(serialNumber); | |
// Signature Algorithm | |
const string signatureAlgorithm = "SHA256WithRSA"; | |
certificateGenerator.SetSignatureAlgorithm(signatureAlgorithm); | |
// Issuer and Subject Name | |
X509Name subjectDN = new X509Name(subjectName); | |
X509Name issuerDN = new X509Name(issuerName); | |
certificateGenerator.SetIssuerDN(issuerDN); | |
certificateGenerator.SetSubjectDN(subjectDN); | |
// Valid For | |
DateTime notBefore = DateTime.UtcNow.Date; | |
DateTime notAfter = notBefore.AddYears(2); | |
certificateGenerator.SetNotBefore(notBefore); | |
certificateGenerator.SetNotAfter(notAfter); | |
// Subject Public Key | |
AsymmetricCipherKeyPair subjectKeyPair; | |
var keyGenerationParameters = new KeyGenerationParameters(random, keyStrength); | |
var keyPairGenerator = new RsaKeyPairGenerator(); | |
keyPairGenerator.Init(keyGenerationParameters); | |
subjectKeyPair = keyPairGenerator.GenerateKeyPair(); | |
certificateGenerator.SetPublicKey(subjectKeyPair.Public); | |
// Generating the Certificate | |
AsymmetricCipherKeyPair issuerKeyPair = subjectKeyPair; | |
// selfsign certificate | |
Org.BouncyCastle.X509.X509Certificate certificate = certificateGenerator.Generate(issuerPrivKey, random); | |
// correcponding private key | |
PrivateKeyInfo info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private); | |
// merge into X509Certificate2 | |
X509Certificate2 x509 = new System.Security.Cryptography.X509Certificates.X509Certificate2(certificate.GetEncoded()); | |
Asn1Sequence seq = (Asn1Sequence)Asn1Object.FromByteArray(info.PrivateKey.GetDerEncoded()); | |
if (seq.Count != 9) { | |
//throw new PemException("malformed sequence in RSA private key"); | |
} | |
RsaPrivateKeyStructure rsa = new RsaPrivateKeyStructure(seq); | |
RsaPrivateCrtKeyParameters rsaparams = new RsaPrivateCrtKeyParameters( | |
rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent, rsa.Prime1, rsa.Prime2, rsa.Exponent1, rsa.Exponent2, rsa.Coefficient); | |
x509.PrivateKey = DotNetUtilities.ToRSA(rsaparams); | |
return x509; | |
} | |
} | |
public static class CertificateAuthority { | |
public static X509Certificate2 Generate(string subjectName, ref AsymmetricCipherKeyPair CaPrivateKey) { | |
const int keyStrength = 2048; | |
// Generating Random Numbers | |
CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator(); | |
SecureRandom random = new SecureRandom(randomGenerator); | |
// The Certificate Generator | |
X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator(); | |
// Serial Number | |
BigInteger serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random); | |
certificateGenerator.SetSerialNumber(serialNumber); | |
// Signature Algorithm | |
const string signatureAlgorithm = "SHA256WithRSA"; | |
certificateGenerator.SetSignatureAlgorithm(signatureAlgorithm); | |
// Issuer and Subject Name | |
X509Name subjectDN = new X509Name(subjectName); | |
X509Name issuerDN = subjectDN; | |
certificateGenerator.SetIssuerDN(issuerDN); | |
certificateGenerator.SetSubjectDN(subjectDN); | |
// Valid For | |
DateTime notBefore = DateTime.UtcNow.Date; | |
DateTime notAfter = notBefore.AddYears(10); | |
certificateGenerator.SetNotBefore(notBefore); | |
certificateGenerator.SetNotAfter(notAfter); | |
// Subject Public Key | |
AsymmetricCipherKeyPair subjectKeyPair; | |
KeyGenerationParameters keyGenerationParameters = new KeyGenerationParameters(random, keyStrength); | |
RsaKeyPairGenerator keyPairGenerator = new RsaKeyPairGenerator(); | |
keyPairGenerator.Init(keyGenerationParameters); | |
subjectKeyPair = keyPairGenerator.GenerateKeyPair(); | |
certificateGenerator.SetPublicKey(subjectKeyPair.Public); | |
// Generating the Certificate | |
AsymmetricCipherKeyPair issuerKeyPair = subjectKeyPair; | |
// selfsign certificate | |
Org.BouncyCastle.X509.X509Certificate certificate = certificateGenerator.Generate(issuerKeyPair.Private, random); | |
X509Certificate2 x509 = new System.Security.Cryptography.X509Certificates.X509Certificate2(certificate.GetEncoded()); | |
CaPrivateKey = issuerKeyPair; | |
return x509; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment