// $Id: MakeCertChain.cs $
using System;
using System.Text;
using System.IO;
using CryptoSysPKI;
// Make a chain of X.509 certificates [Carl] --> [Ian] --> [Enid] then create a PFX file.
// Carl is a trusted root CA. Ian and Enid's certs are created from scratch.
/******************************* LICENSE ***********************************
* Copyright (C) 2019 David Ireland, DI Management Services Pty Limited.
* All rights reserved. <www.di-mgt.com.au> <www.cryptosys.net>
* The code in this module is licensed under the terms of the MIT license.
* For a copy, see <http://opensource.org/licenses/MIT>
****************************************************************************
*/
namespace MakeCertChain
{
class MakeCertChain
{
static void Main(string[] args)
{
//MakeKeys(); // Only call this once. Uncomment to redo.
MakeCertForIan();
MakeCertForEnid();
MakeP7();
CheckChain();
MakePFX();
}
// Only call this once!
static void MakeKeys()
{
// Create two new sets of 1024-bit RSA keys
string prikeyfile, pubkeyfile;
int r;
prikeyfile = "IanRSA.p8e";
pubkeyfile = "IanRSA.pub";
r = Rsa.MakeKeys(pubkeyfile, prikeyfile, 1024, Rsa.PublicExponent.Exp_EQ_65537, 2000, "password", Rsa.PbeOptions.Pbe_Pbkdf2_aes128_CBC, true);
Console.WriteLine("Rsa.MakeKeys returns {0}", r);
prikeyfile = "EnidRSA.p8e";
pubkeyfile = "EnidRSA.pub";
r = Rsa.MakeKeys(pubkeyfile, prikeyfile, 1024, Rsa.PublicExponent.Exp_EQ_65537, 2000, "password", Rsa.PbeOptions.Pbe_Pbkdf2_aes128_CBC, true);
Console.WriteLine("Rsa.MakeKeys returns {0}", r);
}
// Make an intermediate cert
static void MakeCertForIan()
{
string pubkeyfile;
string issuercert, issuerkey;
string certname;
int r;
X509.KeyUsageOptions kuo = X509.KeyUsageOptions.DigitalSignature | X509.KeyUsageOptions.KeyCertSign | X509.KeyUsageOptions.CrlSign;
certname = "IanRSASignedByCarl.cer";
pubkeyfile = "IanRSA.pub";
issuercert = "CarlRSASelf.cer";
issuerkey = "CarlPrivRSASign.p8e";
r = X509.MakeCert(certname, issuercert, pubkeyfile, issuerkey, 0x3002, 20, "O=Administración de certificados;CN=Ian", "notBefore=2019-01-01", kuo, "password",
SigAlgorithm.Rsa_Sha256, X509.CertOptions.SetAsCA | X509.CertOptions.UTF8String);
Console.WriteLine("X509.MakeCert returns {0} (expected 0)", r);
if (r != 0) disp_error(r);
ShowFileInfo(certname);
}
// Make an end-user cert
static void MakeCertForEnid()
{
string pubkeyfile;
string issuercert, issuerkey;
string certname;
int r;
X509.KeyUsageOptions kuo = X509.KeyUsageOptions.DigitalSignature;
certname = "EnidRSASignedByIan.cer";
pubkeyfile = "EnidRSA.pub";
issuercert = "IanRSASignedByCarl.cer";
issuerkey = "IanRSA.p8e";
r = X509.MakeCert(certname, issuercert, pubkeyfile, issuerkey, 0, 19, "CN=Enid", "notBefore=2019-01-02;rfc822Name=enid@example.org;serialNumber=#x02deadbeef123456", kuo, "password",
SigAlgorithm.Rsa_Sha256, X509.CertOptions.UTF8String);
Console.WriteLine("X509.MakeCert returns {0} (expected 0)", r);
if (r != 0) disp_error(r);
ShowFileInfo(certname);
}
static void MakeP7()
{
string fname = "enid.p7b";
// List of all the cert files we want to include
string certlist = "EnidRSASignedByIan.cer;IanRSASignedByCarl.cer;CarlRSASelf.cer";
int r;
// Use the Cms.MakeSigData method with "CertsOnly" option. inputFile and privateKey are ignored.
r = Cms.MakeSigData(fname, "", certlist, "", Cms.Options.CertsOnly);
Console.WriteLine("Cms.MakeSigData returns {0} (expected 0)", r);
if (r != 0) disp_error(r);
ShowFileInfo(fname);
}
static void CheckChain()
{
string fname = "enid.p7b";
string trustedCert = "CarlRSASelf.cer";
int r;
r = X509.ValidatePath(fname, trustedCert, false);
Console.WriteLine("X509.ValidatePath(.p7b) returns {0} (expected 0)", r);
if (r != 0) disp_error(r);
string certlist = "EnidRSASignedByIan.cer;IanRSASignedByCarl.cer;CarlRSASelf.cer";
r = X509.ValidatePath(certlist, trustedCert, false);
Console.WriteLine("X509.ValidatePath(list) returns {0} (expected 0)", r);
if (r != 0) disp_error(r);
}
static void MakePFX()
{
string pfxname = "enid.pfx";
string certlist = "EnidRSASignedByIan.cer;IanRSASignedByCarl.cer;CarlRSASelf.cer";
string prikeyfile = "EnidRSA.p8e";
int r = Pfx.MakeFile(pfxname, certlist, prikeyfile, "password", "Enid", Pfx.Options.Default);
Console.WriteLine("Pfx.MakeFile returns {0} (expected 0)", r);
if (r != 0) disp_error(r);
// NOTE: pfx will be different each time (encryption IVs)
ShowFileInfo(pfxname);
}
static void ShowFileInfo(string fname)
{
if (File.Exists(fname)) {
long flen = new System.IO.FileInfo(fname).Length;
Console.WriteLine(" File '{0}': {1} bytes, SHA-1={2}", fname, flen, Hash.HexFromFile(fname, HashAlgorithm.Sha1));
} else {
Console.WriteLine(" File '{0}' DOES NOT EXIST!", fname);
}
}
//***********************
// DISPLAY ERROR DETAILS
//***********************
/// <summary>
/// Display details of last error given error code
/// </summary>
/// <param name="nErr">Error code returned</param>
static void disp_error(int nErr)
{
string s = General.LastError();
Console.WriteLine("ERROR Returned={0}/{1}: {2}; {3}", nErr, General.ErrorCode(), General.ErrorLookup(nErr), s);
}
/// <summary>
/// Display details of last error (no error code)
/// </summary>
static void disp_error()
{
string s = General.LastError();
int nErr = General.ErrorCode();
Console.WriteLine("ERROR {0}: {1}: {2}", nErr, General.ErrorLookup(nErr), s);
}
}
}