HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

.Net BouncyCastle - CSR and Private Key Generation

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
csrbouncycastleprivatenetgenerationandkey

Problem

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.

```
///
/// 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
///
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();

Solution

ArrayList and Hashtable were superceded by List and Dictionary, respectively, in .NET 2.0.

The first parameter of the X509Name constructor, ordering, specifies the order in which the OID/string pairs will be processed. However we're using new ArrayList(attrs.Keys) for this parameter, and the documentation for Hashtable states "The order of the keys ... is unspecified", so we can't rely upon the keys being returned in the same order that we inserted them.

If the order isn't important in your case, replace ArrayList/Hashtable with List/Dictionary:

var attributes = new Dictionary
{
    { X509Name.CN, domainName },
    { X509Name.O, companyName },
    { X509Name.L, city },
    { X509Name.ST, state },
    { X509Name.C, countryIso2Characters }
};

if (division != null)
{
    attributes.Add(X509Name.OU, division);
}

if (email != null)
{
    attributes.Add(X509Name.EmailAddress, email);
}

var subject = new X509Name(attributes.Keys.ToList(), attributes);


If the order is important to you, then we need another solution since "The order of the keys in the Dictionary.KeyCollection is unspecified".

The obvious solution is to use a List>, but this gets very verbose:

var attributes = new List>
{
    new KeyValuePair(X509Name.CN, domainName),
    ...
};


One trick I read about is to define a helper class like this

private class KeyValuePairList : List>
{
    public void Add(TKey key, TValue value)
    {
        this.Add(new KeyValuePair(key, value));
    }

    public IEnumerable Keys
    {
        get { return this.Select(item => item.Key); }
    }

    public IEnumerable Values
    {
        get { return this.Select(item => item.Value); }
    }
}


The Add method lets us use the same initializer syntax we used for the Dictionary.

And then you can use the X509Name(IList, IList) constructor.

var attributes = new KeyValuePairList
{
    { X509Name.CN, domainName },
    { X509Name.O, companyName },
    { X509Name.L, city },
    { X509Name.ST, state },
    { X509Name.C, countryIso2Characters }
};

if (division != null)
{
    attributes.Add(X509Name.OU, division);
}

if (email != null)
{
    attributes.Add(X509Name.EmailAddress, email);
}

var subject = new X509Name(attributes.Keys.ToList(), attributes.Values.ToList());

Code Snippets

var attributes = new Dictionary<DerObjectIdentifier, string>
{
    { X509Name.CN, domainName },
    { X509Name.O, companyName },
    { X509Name.L, city },
    { X509Name.ST, state },
    { X509Name.C, countryIso2Characters }
};

if (division != null)
{
    attributes.Add(X509Name.OU, division);
}

if (email != null)
{
    attributes.Add(X509Name.EmailAddress, email);
}

var subject = new X509Name(attributes.Keys.ToList(), attributes);
var attributes = new List<KeyValuePair<DerObjectIdentifier, string>>
{
    new KeyValuePair<DerObjectIdentifier, string>(X509Name.CN, domainName),
    ...
};
private class KeyValuePairList<TKey, TValue> : List<KeyValuePair<TKey, TValue>>
{
    public void Add(TKey key, TValue value)
    {
        this.Add(new KeyValuePair<TKey, TValue>(key, value));
    }

    public IEnumerable<TKey> Keys
    {
        get { return this.Select(item => item.Key); }
    }

    public IEnumerable<TValue> Values
    {
        get { return this.Select(item => item.Value); }
    }
}
var attributes = new KeyValuePairList<DerObjectIdentifier, string>
{
    { X509Name.CN, domainName },
    { X509Name.O, companyName },
    { X509Name.L, city },
    { X509Name.ST, state },
    { X509Name.C, countryIso2Characters }
};

if (division != null)
{
    attributes.Add(X509Name.OU, division);
}

if (email != null)
{
    attributes.Add(X509Name.EmailAddress, email);
}

var subject = new X509Name(attributes.Keys.ToList(), attributes.Values.ToList());

Context

StackExchange Code Review Q#84752, answer score: 5

Revisions (0)

No revisions yet.