The purpose of this code is to generate the CSR and the Private Key.
The scenario is that we have some clients for whom we run websites and for the SSL component we want to have a page on our site where they can input the fields like domain name, company name etc and then the system will generate the CSR (and return it to them on the screen so they can get it signed by a third party, e.g. geotrust) and the private key will automatically be put into the correct spot on the web server ready for use.
The 'main' part of this is below.
/// <summary>
/// Generates certificate request in PKCS#10 format defined by RFC 2986.
/// This will also output the private key at the same time.
/// *******************************************
/// Notes / Handy references:
/// http://www.keylength.com/en/compare/
/// http://csrc.nist.gov/publications/nistpubs/800-57/sp800-57_part1_rev3_general.pdf
/// </summary>
private void GeneratePkcs10
(string domainName, string companyName, string division, string city, string state,
string countryIso2Characters, string email, RootLenght rootLength, out string csr, out string privateKey)
{
csr = null;
privateKey = null;
try
{
var rsaKeyPairGenerator = new RsaKeyPairGenerator();
// Note: the numbers {3, 5, 17, 257 or 65537} as Fermat primes.
// NIST doesn't allow a public exponent smaller than 65537, since smaller exponents are a problem if they aren't properly padded.
// Note: the default in openssl is '65537', i.e. 0x10001.
var genParam = new RsaKeyGenerationParameters
(BigInteger.ValueOf(0x10001), new SecureRandom(), (int) rootLength, 128);
rsaKeyPairGenerator.Init(genParam);
AsymmetricCipherKeyPair pair = rsaKeyPairGenerator.GenerateKeyPair();
IDictionary attrs = new Hashtable();
attrs.Add(X509Name.CN, domainName);
attrs.Add(X509Name.O, companyName);
attrs.Add(X509Name.L, city);
attrs.Add(X509Name.ST, state);
attrs.Add(X509Name.C, countryIso2Characters);
if (division != null)
{
attrs.Add(X509Name.OU, division);
}
if (email != null)
{
attrs.Add(X509Name.EmailAddress, email);
}
var subject = new X509Name(new ArrayList(attrs.Keys), attrs);
var pkcs10CertificationRequest = new Pkcs10CertificationRequest
(PkcsObjectIdentifiers.Sha256WithRsaEncryption.Id, subject, pair.Public, null, pair.Private);
csr = Convert.ToBase64String(pkcs10CertificationRequest.GetEncoded());
var pkInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(pair.Private);
privateKey = Convert.ToBase64String(pkInfo.GetDerEncoded());
}
catch (Exception ex)
{
// Note: handles errors on the page. Redirect to error page.
ErrorHandler(ex);
}
}
private enum RootLenght
{
RootLength2048 = 2048,
RootLength3072 = 3072,
RootLength4096 = 4096,
}
Because the documentation for BouncyCastle for .net is limited, I am unsure if the above is 'correct'. It does compile, however:
Is it safe to always use
BigInteger.ValueOf(0x10001)
? This seems to be the default for OpenSSL so I presume this is correct. Or should this be the actual number 65537?NIST does not have a 'certainty' recommendation for 4096 keys. Is it safe to use 128 always for the three lengths in the enum? I saw this answer but it is a bit dated. Should I be switching the value depending on the length of the key?
Am I missing anything?