| | 1 | | // Copyright (c) Microsoft Corporation. All rights reserved. |
| | 2 | | // Licensed under the MIT License. See License.txt in the project root for license information. |
| | 3 | |
|
| | 4 | | namespace IntegrationTestCommon |
| | 5 | | { |
| | 6 | | using System; |
| | 7 | | using System.IO; |
| | 8 | | using System.Security.Cryptography; |
| | 9 | | using System.Linq; |
| | 10 | | using Org.BouncyCastle.Crypto.Prng; |
| | 11 | | using Org.BouncyCastle.Math; |
| | 12 | | using Org.BouncyCastle.Security; |
| | 13 | | using Org.BouncyCastle.X509; |
| | 14 | | using Org.BouncyCastle.Asn1.X509; |
| | 15 | | using Org.BouncyCastle.Crypto; |
| | 16 | | using Org.BouncyCastle.Crypto.Generators; |
| | 17 | | using System.Security.Cryptography.X509Certificates; |
| | 18 | | using Org.BouncyCastle.Pkcs; |
| | 19 | | using Org.BouncyCastle.Crypto.Operators; |
| | 20 | |
|
| | 21 | | /// <summary> |
| | 22 | | /// Static class for generating pfx and cer files. |
| | 23 | | /// </summary> |
| | 24 | | public static class CertificateBuilder |
| | 25 | | { |
| 2 | 26 | | public static string Sha1Algorithm = "sha1WithRSA"; |
| 2 | 27 | | public static string Sha256Algorithm = "sha256WithRSA"; |
| | 28 | |
|
| | 29 | | /// <summary> |
| | 30 | | /// Create a self signed certificate in the specified file. |
| | 31 | | /// </summary> |
| | 32 | | /// <param name="subjectName">The subject of the certificate to create.</param> |
| | 33 | | /// <param name="fileName">The file name to write the certificate to.</param> |
| | 34 | | /// <param name="signatureAlgorithm">The signature algorithm to use</param> |
| | 35 | | /// <param name="password">True if there is a password, false otherwise. Note that if there is a password, PFX |
| | 36 | | public static void CreateSelfSignedInFile(string subjectName, string fileName, string signatureAlgorithm, string |
| | 37 | | { |
| 8 | 38 | | byte[] serialNumber = GenerateSerialNumber(); |
| 8 | 39 | | string subject = string.Format("CN={0}", subjectName); |
| | 40 | |
|
| 8 | 41 | | var subjectDN = new X509Name(subject); |
| 8 | 42 | | var issuerDN = subjectDN; |
| | 43 | |
|
| | 44 | | const int keyStrength = 2048; |
| 8 | 45 | | var randomGenerator = new CryptoApiRandomGenerator(); |
| 8 | 46 | | var random = new SecureRandom(randomGenerator); |
| 8 | 47 | | var keyGenerationParameters = new KeyGenerationParameters(random, keyStrength); |
| 8 | 48 | | var keyPairGenerator = new RsaKeyPairGenerator(); |
| 8 | 49 | | keyPairGenerator.Init(keyGenerationParameters); |
| 8 | 50 | | var subjectKeyPair = keyPairGenerator.GenerateKeyPair(); |
| 8 | 51 | | var issuerKeyPair = subjectKeyPair; |
| | 52 | |
|
| 8 | 53 | | ISignatureFactory signatureFactory = new Asn1SignatureFactory(signatureAlgorithm, issuerKeyPair.Private, ran |
| | 54 | |
|
| | 55 | |
|
| 8 | 56 | | var certificateGenerator = new X509V3CertificateGenerator(); |
| 8 | 57 | | certificateGenerator.AddExtension(X509Extensions.ExtendedKeyUsage.Id, true, new ExtendedKeyUsage(KeyPurposeI |
| 8 | 58 | | certificateGenerator.SetSerialNumber(new BigInteger(serialNumber.Concat(new Byte[] { 0 }).ToArray())); |
| 8 | 59 | | certificateGenerator.SetIssuerDN(issuerDN); |
| 8 | 60 | | certificateGenerator.SetSubjectDN(subjectDN); |
| 8 | 61 | | certificateGenerator.SetNotBefore(DateTime.Now); |
| 8 | 62 | | certificateGenerator.SetNotAfter(DateTime.Now); |
| 8 | 63 | | certificateGenerator.SetPublicKey(subjectKeyPair.Public); |
| 8 | 64 | | var certificate = certificateGenerator.Generate(signatureFactory); |
| | 65 | |
|
| | 66 | |
|
| 8 | 67 | | var store = new Pkcs12Store(); |
| 8 | 68 | | string friendlyName = certificate.SubjectDN.ToString(); |
| 8 | 69 | | var certificateEntry = new X509CertificateEntry(certificate); |
| 8 | 70 | | store.SetCertificateEntry(friendlyName, certificateEntry); |
| 8 | 71 | | store.SetKeyEntry(friendlyName, new AsymmetricKeyEntry(subjectKeyPair.Private), new[] { certificateEntry }); |
| 8 | 72 | | var stream = new MemoryStream(); |
| 8 | 73 | | store.Save(stream, password.ToCharArray(), random); |
| | 74 | |
|
| 8 | 75 | | var convertedCertificate = new X509Certificate2(stream.ToArray(), password, X509KeyStorageFlags.PersistKeySe |
| | 76 | |
|
| | 77 | | //If password is not empty, generate a PKCS#12 formatted file |
| 8 | 78 | | if (!string.IsNullOrEmpty(password)) |
| | 79 | | { |
| 4 | 80 | | File.WriteAllBytes(fileName, stream.ToArray()); |
| | 81 | | } |
| | 82 | | //If password is empty generate a DER formatted file |
| | 83 | | else |
| | 84 | | { |
| 4 | 85 | | File.WriteAllBytes(fileName, convertedCertificate.RawData); |
| | 86 | | } |
| | 87 | |
|
| 4 | 88 | | } |
| | 89 | |
|
| | 90 | | private static byte[] GenerateSerialNumber() |
| | 91 | | { |
| 8 | 92 | | byte[] sn = Guid.NewGuid().ToByteArray(); |
| | 93 | |
|
| | 94 | | //The high bit must be unset |
| 8 | 95 | | sn[0] &= 0x7F; |
| | 96 | |
|
| 8 | 97 | | return sn; |
| | 98 | | } |
| | 99 | | } |
| | 100 | | } |