/// <summary> /// Static method used to create a certificate and return as a .net object /// </summary> public X509Certificate2 Create(string name, DateTime start, DateTime end, string userPassword, bool addtoStore = false) { UserPassword = userPassword ?? String.Empty; // generate a key pair using RSA var generator = new RsaKeyPairGenerator(); // keys have to be a minimum of 2048 bits for Azure generator.Init(new KeyGenerationParameters(new SecureRandom(new CryptoApiRandomGenerator()), 2048)); KeyPair = generator.GenerateKeyPair(); // get a copy of the private key AsymmetricKeyParameter privateKey = KeyPair.Private; // create the CN using the name passed in and create a unique serial number for the cert var certName = new X509Name("CN=" + name); BigInteger serialNo = BigInteger.ProbablePrime(120, new Random()); // start the generator and set CN/DN and serial number and valid period var x509Generator = new X509V3CertificateGenerator(); x509Generator.SetSerialNumber(serialNo); x509Generator.SetSubjectDN(certName); x509Generator.SetIssuerDN(certName); x509Generator.SetNotBefore(start); x509Generator.SetNotAfter(end); // add the server authentication key usage var keyUsage = new KeyUsage(KeyUsage.KeyEncipherment); x509Generator.AddExtension(X509Extensions.KeyUsage, false, keyUsage.ToAsn1Object()); var extendedKeyUsage = new ExtendedKeyUsage(new[] { KeyPurposeID.IdKPServerAuth }); x509Generator.AddExtension(X509Extensions.ExtendedKeyUsage, true, extendedKeyUsage.ToAsn1Object()); // algorithm can only be SHA1 ?? x509Generator.SetSignatureAlgorithm("sha1WithRSA"); // Set the key pair x509Generator.SetPublicKey(KeyPair.Public); X509Certificate certificate = x509Generator.Generate(KeyPair.Private); // export the certificate bytes byte[] certStream = DotNetUtilities.ToX509Certificate(certificate).Export(X509ContentType.Pkcs12, UserPassword); // build the key parameter and the certificate entry var keyEntry = new AsymmetricKeyEntry(privateKey); var entry = new X509CertificateEntry(certificate); // build the PKCS#12 store to encapsulate the certificate var builder = new Pkcs12StoreBuilder(); builder.SetUseDerEncoding(true); builder.SetCertAlgorithm(PkcsObjectIdentifiers.Sha1WithRsaEncryption); builder.SetKeyAlgorithm(PkcsObjectIdentifiers.Sha1WithRsaEncryption); builder.Build(); // create a memorystream to hold the output var stream = new MemoryStream(10000); // create the individual store and set two entries for cert and key var store = new Pkcs12Store(); store.SetCertificateEntry("Created by Fluent Management", entry); store.SetKeyEntry("Created by Fluent Management", keyEntry, new[] { entry }); store.Save(stream, UserPassword.ToCharArray(), new SecureRandom()); // Create the equivalent C# representation DerEncodedCertificate = new X509Certificate2(stream.GetBuffer(), userPassword, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet); // if specified then this add this certificate to the store if (addtoStore) { AddToMyStore(DerEncodedCertificate); } return(DerEncodedCertificate); }
/// <summary> /// Creates a cert with the connectionstring (token) and stores it in the given cert store. /// </summary> public async static Task WriteAsync(string name, string connectionString, string storeType, string storePath) { if (string.IsNullOrEmpty(connectionString)) { throw new ArgumentException("Token not found in X509Store and no new token provided!"); } SecureRandom random = new SecureRandom(); KeyGenerationParameters keyGenerationParameters = new KeyGenerationParameters(random, 2048); RsaKeyPairGenerator keyPairGenerator = new RsaKeyPairGenerator(); keyPairGenerator.Init(keyGenerationParameters); AsymmetricCipherKeyPair keys = keyPairGenerator.GenerateKeyPair(); ArrayList nameOids = new ArrayList(); nameOids.Add(X509Name.CN); ArrayList nameValues = new ArrayList(); nameValues.Add(name); X509Name subjectDN = new X509Name(nameOids, nameValues); X509Name issuerDN = subjectDN; X509V3CertificateGenerator cg = new X509V3CertificateGenerator(); cg.SetSerialNumber(BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random)); cg.SetIssuerDN(issuerDN); cg.SetSubjectDN(subjectDN); cg.SetNotBefore(DateTime.Now); cg.SetNotAfter(DateTime.Now.AddMonths(12)); cg.SetPublicKey(keys.Public); cg.AddExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.DataEncipherment)); // encrypt the token with the public key so only the owner of the assoc. private key can decrypt it and // "hide" it in the instruction code cert extension RSA rsa = RSA.Create(); RSAParameters rsaParams = new RSAParameters(); RsaKeyParameters keyParams = (RsaKeyParameters)keys.Public; rsaParams.Modulus = new byte[keyParams.Modulus.ToByteArrayUnsigned().Length]; keyParams.Modulus.ToByteArrayUnsigned().CopyTo(rsaParams.Modulus, 0); rsaParams.Exponent = new byte[keyParams.Exponent.ToByteArrayUnsigned().Length]; keyParams.Exponent.ToByteArrayUnsigned().CopyTo(rsaParams.Exponent, 0); rsa.ImportParameters(rsaParams); if (rsa != null) { byte[] bytes = rsa.Encrypt(Encoding.ASCII.GetBytes(connectionString), RSAEncryptionPadding.OaepSHA1); if (bytes != null) { cg.AddExtension(X509Extensions.InstructionCode, false, bytes); } else { throw new CryptographicException("Can not encrypt IoTHub security token using generated public key!"); } } // sign the cert with the private key ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA256WITHRSA", keys.Private, random); Org.BouncyCastle.X509.X509Certificate x509 = cg.Generate(signatureFactory); // create a PKCS12 store for the cert and its private key X509Certificate2 certificate = null; using (MemoryStream pfxData = new MemoryStream()) { Pkcs12StoreBuilder builder = new Pkcs12StoreBuilder(); builder.SetUseDerEncoding(true); Pkcs12Store pkcsStore = builder.Build(); X509CertificateEntry[] chain = new X509CertificateEntry[1]; string passcode = Guid.NewGuid().ToString(); chain[0] = new X509CertificateEntry(x509); pkcsStore.SetKeyEntry(name, new AsymmetricKeyEntry(keys.Private), chain); pkcsStore.Save(pfxData, passcode.ToCharArray(), random); // create X509Certificate2 object from PKCS12 file certificate = CertificateFactory.CreateCertificateFromPKCS12(pfxData.ToArray(), passcode); // handle each store type differently switch (storeType) { case CertificateStoreType.Directory: { // Add to DirectoryStore using (DirectoryCertificateStore store = new DirectoryCertificateStore()) { store.Open(storePath); X509CertificateCollection certificates = await store.Enumerate().ConfigureAwait(false); // remove any existing cert with our name from the store foreach (X509Certificate2 cert in certificates) { if (cert.SubjectName.Decode(X500DistinguishedNameFlags.None | X500DistinguishedNameFlags.DoNotUseQuotes).Equals("CN=" + name, StringComparison.OrdinalIgnoreCase)) { await store.Delete(cert.Thumbprint).ConfigureAwait(false); } } // add new one await store.Add(certificate).ConfigureAwait(false); } break; } case CertificateStoreType.X509Store: { // Add to X509Store using (X509Store store = new X509Store(storePath, StoreLocation.CurrentUser)) { store.Open(OpenFlags.ReadWrite); // remove any existing cert with our name from the store foreach (X509Certificate2 cert in store.Certificates) { if (cert.SubjectName.Decode(X500DistinguishedNameFlags.None | X500DistinguishedNameFlags.DoNotUseQuotes).Equals("CN=" + name, StringComparison.OrdinalIgnoreCase)) { store.Remove(cert); } } // add new cert to store try { store.Add(certificate); } catch (Exception e) { throw new Exception($"Not able to add cert to the requested store type '{storeType}' (exception message: '{e.Message}'."); } } break; } default: { throw new Exception($"The requested store type '{storeType}' is not supported. Please change."); } } return; } }
/// <summary> /// Creates new certificate /// </summary> /// <returns></returns> public static void CreateSelfSignedCertificate(string subjectDirName, DateTime startDate, DateTime endDate, int signatureBits, int keyStrength, string password, string fileName) { string signatureAlgorithm; switch (signatureBits) { case 160: signatureAlgorithm = "SHA1withRSA"; break; case 224: signatureAlgorithm = "SHA224withRSA"; break; case 256: signatureAlgorithm = "SHA256withRSA"; break; case 384: signatureAlgorithm = "SHA384withRSA"; break; case 512: signatureAlgorithm = "SHA512withRSA"; break; default: throw new ArgumentException("Invalid signature bit size.", "signatureBits"); } // Generating Random Numbers CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator(); SecureRandom random = new SecureRandom(randomGenerator); // Generate public/private keys. AsymmetricCipherKeyPair encryptionKeys; KeyGenerationParameters keyGenerationParameters = new KeyGenerationParameters(random, keyStrength); RsaKeyPairGenerator keyPairGenerator = new RsaKeyPairGenerator(); keyPairGenerator.Init(keyGenerationParameters); encryptionKeys = keyPairGenerator.GenerateKeyPair(); // The Certificate Generator X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator(); certificateGenerator.SetSerialNumber(BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random)); certificateGenerator.SetSignatureAlgorithm(signatureAlgorithm); certificateGenerator.SetIssuerDN(new X509Name(subjectDirName)); certificateGenerator.SetSubjectDN(new X509Name(subjectDirName)); certificateGenerator.SetNotBefore(startDate); certificateGenerator.SetNotAfter(endDate); certificateGenerator.SetPublicKey(encryptionKeys.Public); // self-sign certificate Org.BouncyCastle.X509.X509Certificate certificate = certificateGenerator.Generate(encryptionKeys.Private, random); Pkcs12Store store = new Pkcs12Store(); string friendlyName = certificate.SubjectDN.ToString(); X509CertificateEntry certificateEntry = new X509CertificateEntry(certificate); store.SetCertificateEntry(friendlyName, certificateEntry); store.SetKeyEntry(friendlyName, new AsymmetricKeyEntry(encryptionKeys.Private), new[] { certificateEntry }); MemoryStream stream = new MemoryStream(); store.Save(stream, password.ToCharArray(), random); //Verify that the certificate is valid. _ = new X509Certificate2(stream.ToArray(), password, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); //Write the file. File.WriteAllBytes(fileName, stream.ToArray()); File.WriteAllBytes(Path.ChangeExtension(fileName, ".cer"), certificate.GetEncoded()); }
private void cmdOK_Click(object sender, EventArgs e) { X509V1CertificateGenerator certGen = new X509V1CertificateGenerator(); IDictionary attrs = new Hashtable(); attrs[X509Name.CN] = txtCN.Text; attrs[X509Name.O] = txtCompany.Text; attrs[X509Name.C] = txtCC.Text; attrs[X509Name.ST] = txtProvince.Text; attrs[X509Name.OU] = txtOU.Text; attrs[X509Name.L] = txtCity.Text; IList ord = new ArrayList(); ord.Add(X509Name.CN); ord.Add(X509Name.O); ord.Add(X509Name.C); ord.Add(X509Name.ST); ord.Add(X509Name.OU); ord.Add(X509Name.L); X509Name CN = new X509Name(ord, attrs); Org.BouncyCastle.X509.X509Certificate newCert; certGen.SetSerialNumber(BigInteger.ProbablePrime(120, new Random())); certGen.SetIssuerDN(CN); certGen.SetNotAfter(new DateTime(DT.Value.Year, DT.Value.Month, DT.Value.Day, 0, 0, 0, 0)); certGen.SetNotBefore(DateTime.Now.Subtract(new TimeSpan(7, 0, 0, 0))); certGen.SetSubjectDN(CN); CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator(); SecureRandom random; AsymmetricCipherKeyPair keypair; if (txtSPKI.Text == "") { RsaKeyPairGenerator keypairgen = new RsaKeyPairGenerator(); keypairgen.Init(new KeyGenerationParameters(new SecureRandom(new CryptoApiRandomGenerator()), 2048)); keypair = keypairgen.GenerateKeyPair(); certGen.SetPublicKey(keypair.Public); random = new SecureRandom(randomGenerator); ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA256WITHRSA", keypair.Private, random); newCert = certGen.Generate(signatureFactory); } else { RsaPublicKeyStructure rsaPubStructure = RsaPublicKeyStructure.GetInstance(Asn1Object.FromByteArray(File.ReadAllBytes(txtSPKI.Text))); AsymmetricKeyParameter extpublickey = (AsymmetricKeyParameter)(new RsaKeyParameters(false, rsaPubStructure.Modulus, rsaPubStructure.PublicExponent)); certGen.SetPublicKey(extpublickey); RsaKeyPairGenerator keypairgen = new RsaKeyPairGenerator(); keypairgen.Init(new KeyGenerationParameters(new SecureRandom(new CryptoApiRandomGenerator()), 2048)); keypair = keypairgen.GenerateKeyPair(); random = new SecureRandom(randomGenerator); ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA256WITHRSA", keypair.Private, random); newCert = certGen.Generate(signatureFactory); } byte[] PlainCer = newCert.GetEncoded(); SaveFileDialog save = new SaveFileDialog(); if (lstOutput.SelectedIndex == 0) { save.Filter = "Certificate|*.cer"; save.DefaultExt = ".cer"; save.Title = "Save CER file"; } if (lstOutput.SelectedIndex == 1) { save.Filter = "Certificate|*.der"; save.DefaultExt = ".der"; save.Title = "Save DER file"; } if (lstOutput.SelectedIndex == 2) { save.Filter = "Certificate|*.p12"; save.DefaultExt = ".p12"; save.Title = "Save P12 file"; } if (save.ShowDialog(this) != System.Windows.Forms.DialogResult.OK) { return; } if (lstOutput.SelectedIndex == 0) { File.WriteAllBytes(save.FileName, PlainCer); } if (lstOutput.SelectedIndex == 1) { TextWriter txt = new StreamWriter(save.FileName, false, Encoding.ASCII); PemWriter text = new PemWriter(txt); text.WriteObject(newCert); txt.Close(); } if (lstOutput.SelectedIndex == 2) { Pkcs12Store pkcs = new Pkcs12Store(); pkcs.SetCertificateEntry(txtCN.Text, new X509CertificateEntry(newCert)); AsymmetricKeyEntry keyentry = new AsymmetricKeyEntry(keypair.Private); pkcs.SetKeyEntry(txtCN.Text, keyentry, new[] { new X509CertificateEntry(newCert) }); MemoryStream mem = new MemoryStream(); pkcs.Save(mem, txtPassword.Text.ToCharArray(), random); PlainCer = newCert.GetEncoded(); File.WriteAllBytes(save.FileName, mem.GetBuffer()); } this.Close(); }
/// <summary> /// Static method used to create a certificate and return as a .net object /// </summary> public static X509Certificate2 Create(string name, DateTime start, DateTime end, string userPassword, bool addtoStore = false, string exportDirectory = null) { // generate a key pair using RSA var generator = new RsaKeyPairGenerator(); // keys have to be a minimum of 2048 bits for Azure generator.Init(new KeyGenerationParameters(new SecureRandom(new CryptoApiRandomGenerator()), 2048)); AsymmetricCipherKeyPair cerKp = generator.GenerateKeyPair(); // get a copy of the private key AsymmetricKeyParameter privateKey = cerKp.Private; // create the CN using the name passed in and create a unique serial number for the cert var certName = new X509Name("CN=" + name); BigInteger serialNo = BigInteger.ProbablePrime(120, new Random()); // start the generator and set CN/DN and serial number and valid period var x509Generator = new X509V3CertificateGenerator(); x509Generator.SetSerialNumber(serialNo); x509Generator.SetSubjectDN(certName); x509Generator.SetIssuerDN(certName); x509Generator.SetNotBefore(start); x509Generator.SetNotAfter(end); // add the server authentication key usage var keyUsage = new KeyUsage(KeyUsage.KeyEncipherment); x509Generator.AddExtension(X509Extensions.KeyUsage, false, keyUsage.ToAsn1Object()); var extendedKeyUsage = new ExtendedKeyUsage(new[] { KeyPurposeID.IdKPServerAuth }); x509Generator.AddExtension(X509Extensions.ExtendedKeyUsage, true, extendedKeyUsage.ToAsn1Object()); // algorithm can only be SHA1 ?? x509Generator.SetSignatureAlgorithm("sha1WithRSA"); // Set the key pair x509Generator.SetPublicKey(cerKp.Public); X509Certificate certificate = x509Generator.Generate(cerKp.Private); // export the certificate bytes byte[] certStream = DotNetUtilities.ToX509Certificate(certificate).Export(X509ContentType.Pkcs12, userPassword); // build the key parameter and the certificate entry var keyEntry = new AsymmetricKeyEntry(privateKey); var entry = new X509CertificateEntry(certificate); // build the PKCS#12 store to encapsulate the certificate var builder = new Pkcs12StoreBuilder(); builder.SetUseDerEncoding(true); builder.SetCertAlgorithm(PkcsObjectIdentifiers.Sha1WithRsaEncryption); builder.SetKeyAlgorithm(PkcsObjectIdentifiers.Sha1WithRsaEncryption); builder.Build(); // create a memorystream to hold the output var stream = new MemoryStream(10000); // create the individual store and set two entries for cert and key var store = new Pkcs12Store(); store.SetCertificateEntry("Created by Fluent Management", entry); store.SetKeyEntry("Created by Fluent Management", keyEntry, new[] { entry }); store.Save(stream, userPassword.ToCharArray(), new SecureRandom()); // Create the equivalent C# representation var cert = new X509Certificate2(stream.GetBuffer(), userPassword, X509KeyStorageFlags.Exportable); // set up the PEM writer too if (exportDirectory != null) { var textWriter = new StringWriter(); var pemWriter = new PemWriter(textWriter); pemWriter.WriteObject(cerKp.Private, "DESEDE", userPassword.ToCharArray(), new SecureRandom()); pemWriter.Writer.Flush(); string privateKeyPem = textWriter.ToString(); using (var writer = new StreamWriter(Path.Combine(exportDirectory, cert.Thumbprint + ".pem"))) { writer.WriteLine(privateKeyPem); } // also export the certs - first the .pfx byte[] privateKeyBytes = cert.Export(X509ContentType.Pfx, userPassword); using (var writer = new FileStream(Path.Combine(exportDirectory, cert.Thumbprint + ".pfx"), FileMode.OpenOrCreate, FileAccess.Write)) { writer.Write(privateKeyBytes, 0, privateKeyBytes.Length); } // also export the certs - then the .cer byte[] publicKeyBytes = cert.Export(X509ContentType.Cert); using (var writer = new FileStream(Path.Combine(exportDirectory, cert.Thumbprint + ".cer"), FileMode.OpenOrCreate, FileAccess.Write)) { writer.Write(publicKeyBytes, 0, publicKeyBytes.Length); } } // if specified then this add this certificate to the store if (addtoStore) { AddToMyStore(cert); } return(cert); }
/// <summary> /// Returns the encrypted Base64 string of the certificate chain+key. Subject is a string containing the name of the owner etc. /// /// Example usage: /// /// var res = TryParseNemID (File.ReadAllBytes ($PATH$)); /// if (res.Success) /// do stuff /// /// </summary> public static (bool Success, string Base64, string Subject, string TemporaryPassword) TryParseNemID(byte[] raw, bool keepPassword = false, bool generateTemporaryPassword = false, string certificatePassword = null) { try { string ascii = System.Text.Encoding.ASCII.GetString(raw); var ex = new Regex("pkcs12=\"(?<data>[A-Za-z0-9+/=\\s]*?)\";", RegexOptions.Multiline); bool isHTML = ex.IsMatch(ascii); //Assume the file was a NemID HTML file. string base64; if (keepPassword) { base64 = isHTML ? ex.Match(ascii).Groups["data"].ToString().Replace("\n", "") : Convert.ToBase64String(raw); return(true, base64, null, null); } var inputKeyStore = new Pkcs12Store(); if (isHTML) { string data = ex.Match(ascii).Groups["data"].ToString().Replace("\n", ""); var bytes = Convert.FromBase64String(data); using (var keyStream = new MemoryStream(bytes)) { inputKeyStore.Load(keyStream, certificatePassword == null ? new char[0] : certificatePassword.ToCharArray()); } } else { using (var keyStream = new MemoryStream(raw)) { inputKeyStore.Load(keyStream, certificatePassword == null ? new char[0] : certificatePassword.ToCharArray()); } } string keyAlias = inputKeyStore.Aliases.Cast <string> ().FirstOrDefault(inputKeyStore.IsKeyEntry); if (keyAlias == null) { throw new NotImplementedException("Alias"); } Org.BouncyCastle.X509.X509Certificate certificate = inputKeyStore.GetCertificate(keyAlias).Certificate; var certf = new X509Certificate2(DotNetUtilities.ToX509Certificate(certificate)); string subject = certf.Subject; if (generateTemporaryPassword) { string temporaryPassword = "******"; using (var ms = new MemoryStream()) { inputKeyStore.Save(ms, temporaryPassword.ToCharArray(), new SecureRandom()); return(true, Convert.ToBase64String(ms.ToArray()), subject, temporaryPassword); } } base64 = isHTML ? ex.Match(ascii).Groups["data"].ToString().Replace("\n", "") : Convert.ToBase64String(raw); return(true, base64, subject, null); } catch (Exception ex) { Console.WriteLine(ex); Console.WriteLine(ex.InnerException); } return(false, null, null, null); }
///// <summary> ///// Create a new certificate ///// </summary> ///// <param name="issuer">Issuer certificate, if null then self-sign</param> ///// <param name="subjectName">Subject name</param> ///// <param name="serialNumber">Serial number of certificate, if null then will generate a new one</param> ///// <param name="keySize">Size of RSA key</param> ///// <param name="notBefore">Start date of certificate</param> ///// <param name="notAfter">End date of certificate</param> ///// <param name="extensions">Array of extensions, if null then no extensions</param> ///// <param name="hashAlgorithm">Specify the signature hash algorithm</param> ///// <returns>The created X509 certificate</returns> public static SystemX509.X509Certificate2 CreateCert(SystemX509.X509Certificate2 issuer, SystemX509.X500DistinguishedName subjectName, byte[] serialNumber, int keySize, CertificateHashAlgorithm hashAlgorithm, DateTime notBefore, DateTime notAfter, SystemX509.X509ExtensionCollection extensions) { SecureRandom random = new SecureRandom(); X509V3CertificateGenerator builder = new X509V3CertificateGenerator(); AsymmetricCipherKeyPair bcSubjectKey = CreateRSAKey(keySize, random); AsymmetricCipherKeyPair bcSignKey = issuer == null ? bcSubjectKey : issuer.GetBCPrivateKey(); if (bcSignKey == null) { throw new ArgumentException("issuer"); } X509Name issuerNameObj = issuer == null?X509Name.GetInstance(Asn1Object.FromByteArray(subjectName.RawData)) : X509Name.GetInstance(Asn1Object.FromByteArray(issuer.SubjectName.RawData)); X509Name subjectNameObj = X509Name.GetInstance(Asn1Object.FromByteArray(subjectName.RawData)); BigInteger subjectSerial = new BigInteger(1, serialNumber != null ? serialNumber : Guid.NewGuid().ToByteArray()); BigInteger issuerSerial = issuer == null ? subjectSerial : new BigInteger(1, issuer.GetSerialNumber()); builder.SetIssuerDN(issuerNameObj); builder.SetSubjectDN(subjectNameObj); builder.SetSerialNumber(subjectSerial); builder.SetNotBefore(notBefore.ToUniversalTime()); builder.SetNotAfter(notAfter.ToUniversalTime()); builder.SetPublicKey(bcSubjectKey.Public); SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(bcSignKey.Public); AuthorityKeyIdentifier authKeyId = new AuthorityKeyIdentifier(info, new GeneralNames(new GeneralName(issuerNameObj)), issuerSerial); SubjectKeyIdentifier subjectKeyid = new SubjectKeyIdentifier(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(bcSubjectKey.Public)); builder.AddExtension(X509Extensions.AuthorityKeyIdentifier.Id, true, authKeyId); builder.AddExtension(X509Extensions.SubjectKeyIdentifier.Id, true, subjectKeyid); if (extensions != null) { foreach (SystemX509.X509Extension ext in extensions) { if (!ext.Oid.Value.Equals(X509Extensions.AuthorityKeyIdentifier.Id) && !ext.Oid.Value.Equals(X509Extensions.SubjectKeyIdentifier.Id) && !ext.Oid.Value.Equals(szOID_AUTHORITY_KEY_IDENTIFIER2)) { Asn1InputStream istm = new Asn1InputStream(ext.RawData); Asn1Object obj = istm.ReadObject(); builder.AddExtension(ext.Oid.Value, ext.Critical, obj); } } } X509Certificate cert = builder.Generate(CreateSignatureFactory(hashAlgorithm, bcSignKey, random)); Pkcs12StoreBuilder pkcs = new Pkcs12StoreBuilder(); Pkcs12Store store = pkcs.Build(); X509CertificateEntry entry = new X509CertificateEntry(cert); store.SetCertificateEntry("main", entry); AsymmetricKeyEntry key_entry = new AsymmetricKeyEntry(bcSubjectKey.Private); store.SetKeyEntry("main", key_entry, new[] { entry }); MemoryStream stm = new MemoryStream(); store.Save(stm, new char[0], new SecureRandom()); return(new SystemX509.X509Certificate2(stm.ToArray(), String.Empty, SystemX509.X509KeyStorageFlags.Exportable)); }
public override async Task PairAsync(string ipAddress, TextBox outputTextBox) { // Create SHA256 hash digest. This is not supported by server version < 7 // (need to use SHA1 for those cases) but that doesn't really matter right now. IDigest hashAlgorithm = new Sha256Digest(); int hashDigestSize = hashAlgorithm.GetDigestSize(); // Create and salt pin byte[] salt = this.GenerateRandomBytes(16); string pin = GenerateRandomPin(); byte[] saltAndPin = SaltPin(salt, pin); // Asymmetric key pair RsaKeyPairGenerator keyPairGenerator = new RsaKeyPairGenerator(); keyPairGenerator.Init(new KeyGenerationParameters(this.SecureRandom, 2048)); AsymmetricCipherKeyPair keyPair = keyPairGenerator.GenerateKeyPair(); // Certificate issuer and name X509Name name = new X509Name("CN=NVIDIA GameStream Client"); // Certificate serial number byte[] serialBytes = this.GenerateRandomBytes(8); BigInteger serial = new BigInteger(serialBytes).Abs(); // Expires in 20 years DateTime now = DateTime.UtcNow; DateTime expiration = now.AddYears(20); X509V3CertificateGenerator generator = new X509V3CertificateGenerator(); generator.SetSubjectDN(name); generator.SetIssuerDN(name); generator.SetSerialNumber(serial); generator.SetNotBefore(now); generator.SetNotAfter(expiration); generator.SetPublicKey(keyPair.Public); BouncyCastleX509Certificate certificate = generator.Generate( new Asn1SignatureFactory("SHA1WithRSA", keyPair.Private)); // Create PKCS12 certificate bytes. Pkcs12Store store = new Pkcs12Store(); X509CertificateEntry certificateEntry = new X509CertificateEntry(certificate); string friendlyName = "Moonlight Xbox"; string password = "******"; store.SetCertificateEntry(friendlyName, certificateEntry); store.SetKeyEntry( friendlyName, new AsymmetricKeyEntry(keyPair.Private), new X509CertificateEntry[] { certificateEntry }); byte[] pfxDataBytes; using (MemoryStream memoryStream = new MemoryStream(512)) { store.Save(memoryStream, password.ToCharArray(), this.SecureRandom); pfxDataBytes = memoryStream.ToArray(); } await CertificateEnrollmentManager.ImportPfxDataAsync( CryptographicBuffer.EncodeToBase64String(pfxDataBytes.AsBuffer()), password, ExportOption.NotExportable, KeyProtectionLevel.NoConsent, InstallOptions.DeleteExpired, friendlyName); // Create the system certificate. X509Certificate2 systemCertificate = new X509Certificate2( pfxDataBytes, password, X509KeyStorageFlags.PersistKeySet); string keyString; using (StringWriter keyWriter = new StringWriter()) { PemWriter pemWriter = new PemWriter(keyWriter); pemWriter.WriteObject(keyPair); keyString = keyWriter.ToString(); // Line endings must be UNIX style for GFE to accept the certificate. keyString = keyString.Replace(Environment.NewLine, "\n"); } string certString; using (StringWriter certWriter = new StringWriter()) { PemWriter pemWriter = new PemWriter(certWriter); pemWriter.WriteObject(certificate); certString = certWriter.ToString(); // Line endings must be UNIX style for GFE to accept the certificate. certString = certString.Replace(Environment.NewLine, "\n"); } byte[] pemCertBytes = Encoding.UTF8.GetBytes(certString); byte[] uniqueId = GenerateRandomBytes(8); // Create the HTTP client. HttpClientHandler handler = new HttpClientHandler(); handler.ServerCertificateCustomValidationCallback = (a, b, c, d) => true; handler.ClientCertificates.Add(systemCertificate); HttpClient httpClient = new HttpClient(handler); httpClient.DefaultRequestHeaders.Add("Accept-Language", "en-US,*"); httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0"); // Unpair before doing anything else in this test app. string uriString = string.Format( "http://{0}:47989/unpair?uniqueid={1}&uuid={2}", ipAddress, BytesToHex(uniqueId), Guid.NewGuid().ToString("N")); using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(uriString))) { using (HttpResponseMessage response = await httpClient.SendAsync(request)) { outputTextBox.Text = $"Unpair status code: {response.StatusCode}\n"; string responseContent = await response.Content.ReadAsStringAsync(); outputTextBox.Text += responseContent + "\n"; } } await Task.Delay(2000); outputTextBox.Text = $"Enter pin: {pin}"; // Get server certificate. // TODO: Call should have no timeout because it requires the user to enter a pin. PairResponse pairResponse = null; uriString = string.Format( "http://{0}:47989/pair?uniqueid={1}&uuid={2}&devicename=roth&updateState=1&phrase=getservercert&salt={3}&clientcert={4}", ipAddress, BytesToHex(uniqueId), Guid.NewGuid().ToString("N"), BytesToHex(salt), BytesToHex(pemCertBytes)); using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(uriString))) { using (HttpResponseMessage response = await httpClient.SendAsync(request)) { outputTextBox.Text = $"Get server cert status code: {response.StatusCode}\n"; string responseContent = await response.Content.ReadAsStringAsync(); outputTextBox.Text += responseContent + "\n"; using (StringReader reader = new StringReader(responseContent)) { XmlSerializer serializer = new XmlSerializer(typeof(PairResponse)); pairResponse = serializer.Deserialize(new StringReader(responseContent)) as PairResponse; } } } if (pairResponse == null || pairResponse.Paired != 1) { outputTextBox.Text += "Pairing failed.\n"; return; } if (string.IsNullOrEmpty(pairResponse.PlainCert)) { outputTextBox.Text += "Pairing already in progress.\n"; return; } // Parse server certificate byte[] serverCertBytes = HexToBytes(pairResponse.PlainCert); BouncyCastleX509Certificate serverCertificate = new X509CertificateParser().ReadCertificate(serverCertBytes); // Hash the salt and pin and use it to generate an AES key. byte[] hashedSaltAndPin = HashData(hashAlgorithm, saltAndPin); ICipherParameters aesKey = GenerateCipherKey(hashedSaltAndPin); // Generate a random challenge and encrypt it using AES. byte[] challenge = GenerateRandomBytes(16); byte[] encryptedChallenge = DoAesCipher(true, aesKey, challenge); await Task.Delay(2000); // Send the encrypted challenge to the server. // TODO: Call should have a timeout. uriString = string.Format( "http://{0}:47989/pair?uniqueid={1}&uuid={2}&devicename=roth&updateState=1&clientchallenge={3}", ipAddress, BytesToHex(uniqueId), Guid.NewGuid().ToString("N"), BytesToHex(encryptedChallenge)); using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(uriString))) { using (HttpResponseMessage response = await httpClient.SendAsync(request)) { outputTextBox.Text = $"Send challenge status code: {response.StatusCode}\n"; string responseContent = await response.Content.ReadAsStringAsync(); outputTextBox.Text += responseContent + "\n"; using (StringReader reader = new StringReader(responseContent)) { XmlSerializer serializer = new XmlSerializer(typeof(PairResponse)); pairResponse = serializer.Deserialize(new StringReader(responseContent)) as PairResponse; } } } if (pairResponse == null || pairResponse.Paired != 1) { outputTextBox.Text += "Pairing failed.\n"; return; } // Decode the server's response and subsequent challenge. byte[] encryptedServerChallengeResponse = HexToBytes(pairResponse.ChallengeResponse); byte[] decryptedServerChallengeResponse = DoAesCipher(false, aesKey, encryptedServerChallengeResponse); byte[] serverResponse = new byte[hashDigestSize]; byte[] serverChallenge = new byte[16]; Array.Copy(decryptedServerChallengeResponse, serverResponse, hashDigestSize); Array.Copy(decryptedServerChallengeResponse, hashDigestSize, serverChallenge, 0, 16); // Using another 16 byte secret, compute a challenge response hash using the secret, // our certificate signature, and the challenge. byte[] clientSecret = GenerateRandomBytes(16); byte[] challengeResponseHash = HashData( hashAlgorithm, ConcatenateByteArrays(serverChallenge, certificate.GetSignature(), clientSecret)); byte[] encryptedChallengeResponse = DoAesCipher(true, aesKey, challengeResponseHash); await Task.Delay(2000); // Send the challenge response to the server. // TODO: Call should have a timeout. uriString = string.Format( "http://{0}:47989/pair?uniqueid={1}&uuid={2}&devicename=roth&updateState=1&serverchallengeresp={3}", ipAddress, BytesToHex(uniqueId), Guid.NewGuid().ToString("N"), BytesToHex(encryptedChallengeResponse)); using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(uriString))) { using (HttpResponseMessage response = await httpClient.SendAsync(request)) { outputTextBox.Text = $"Send challenge response status code: {response.StatusCode}\n"; string responseContent = await response.Content.ReadAsStringAsync(); outputTextBox.Text += responseContent + "\n"; using (StringReader reader = new StringReader(responseContent)) { XmlSerializer serializer = new XmlSerializer(typeof(PairResponse)); pairResponse = serializer.Deserialize(new StringReader(responseContent)) as PairResponse; } } } if (pairResponse == null || pairResponse.Paired != 1) { outputTextBox.Text += "Pairing failed.\n"; // TODO: Unpair here by calling http://<blah>/unpair?uniqueid={1}&uuid={2}. return; } // Get the server's signed secret. byte[] serverSecretResponse = HexToBytes(pairResponse.PairingSecret); byte[] serverSecret = new byte[16]; byte[] serverSignature = new byte[256]; Array.Copy(serverSecretResponse, serverSecret, serverSecret.Length); Array.Copy(serverSecretResponse, serverSecret.Length, serverSignature, 0, serverSignature.Length); if (!VerifySignature(serverSecret, serverSignature, serverCertificate.GetPublicKey())) { outputTextBox.Text += "Pairing failed.\n"; // TODO: Unpair as above. return; } // Ensure the server challenge matched what we expected (the PIN was correct). byte[] serverChallengeResponseHash = HashData( hashAlgorithm, ConcatenateByteArrays( challenge, serverCertificate.GetSignature(), serverSecret)); if (!serverChallengeResponseHash.SequenceEqual(serverResponse)) { outputTextBox.Text += "Pairing failed due to wrong pin.\n"; // TODO: Unpair as above. return; } await Task.Delay(2000); // Send the server our signed secret // TODO: Call should have a timeout. byte[] signedSecret = SignData(clientSecret, keyPair.Private); byte[] clientPairingSecret = ConcatenateByteArrays( clientSecret, signedSecret); uriString = string.Format( "http://{0}:47989/pair?uniqueid={1}&uuid={2}&devicename=roth&updateState=1&clientpairingsecret={3}", ipAddress, BytesToHex(uniqueId), Guid.NewGuid().ToString("N"), BytesToHex(clientPairingSecret)); using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(uriString))) { using (HttpResponseMessage response = await httpClient.SendAsync(request)) { outputTextBox.Text = $"Send client pairing secret status code: {response.StatusCode}\n"; string responseContent = await response.Content.ReadAsStringAsync(); outputTextBox.Text += responseContent + "\n"; using (StringReader reader = new StringReader(responseContent)) { XmlSerializer serializer = new XmlSerializer(typeof(PairResponse)); pairResponse = serializer.Deserialize(new StringReader(responseContent)) as PairResponse; } } } if (pairResponse == null || pairResponse.Paired != 1) { outputTextBox.Text += "Pairing failed.\n"; // TODO: Unpair as above. return; } await Task.Delay(2000); // Do the initial challenge (seems neccessary for us to show as paired). // TODO: Call should have a timeout. uriString = string.Format( "https://{0}:47984/pair?uniqueid={1}&uuid={2}&devicename=roth&updateState=1&phrase=pairchallenge", ipAddress, BytesToHex(uniqueId), Guid.NewGuid().ToString("N")); using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, new Uri(uriString))) { using (HttpResponseMessage response = await httpClient.SendAsync(request)) { outputTextBox.Text = $"Send pair challenge status code: {response.StatusCode}\n"; string responseContent = await response.Content.ReadAsStringAsync(); outputTextBox.Text += responseContent + "\n"; using (StringReader reader = new StringReader(responseContent)) { XmlSerializer serializer = new XmlSerializer(typeof(PairResponse)); pairResponse = serializer.Deserialize(new StringReader(responseContent)) as PairResponse; } } } if (pairResponse == null || pairResponse.Paired != 1) { outputTextBox.Text += "Pairing failed.\n"; // TODO: Unpair as above. return; } await Task.Delay(2000); outputTextBox.Text = "Pairing succeeded!\n"; }
/// <summary> /// Creates a self signed certificate that can be used in SSL communications /// </summary> /// <param name="subjectDirName">A valid DirName formated string. Example: CN=ServerName</param> /// <param name="signatureBits">Bitstrength of signature algorithm. Supported Lengths are 160,256, and 384 </param> /// <param name="keyStrength">RSA key strength. Typically a multiple of 1024.</param> /// <returns></returns> public static X509Certificate2 CreateSelfSignedCertificate(string subjectDirName, int signatureBits, int keyStrength) { DateTime startDate = DateTime.UtcNow.AddYears(-1); DateTime endDate = DateTime.UtcNow.AddYears(100);; string signatureAlgorithm; switch (signatureBits) { case 160: signatureAlgorithm = "SHA1withRSA"; break; case 256: signatureAlgorithm = "SHA256withRSA"; break; case 384: signatureAlgorithm = "SHA384withRSA"; break; default: throw new ArgumentException("Invalid signature bit size.", "signatureBits"); } // Generating Random Numbers CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator(); SecureRandom random = new SecureRandom(randomGenerator); // Generate public/private keys. AsymmetricCipherKeyPair encryptionKeys; KeyGenerationParameters keyGenerationParameters = new KeyGenerationParameters(random, keyStrength); RsaKeyPairGenerator keyPairGenerator = new RsaKeyPairGenerator(); keyPairGenerator.Init(keyGenerationParameters); encryptionKeys = keyPairGenerator.GenerateKeyPair(); // The Certificate Generator X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator(); certificateGenerator.SetSerialNumber(BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random)); certificateGenerator.SetSignatureAlgorithm(signatureAlgorithm); certificateGenerator.SetIssuerDN(new X509Name(subjectDirName)); certificateGenerator.SetSubjectDN(new X509Name(subjectDirName)); certificateGenerator.SetNotBefore(startDate); certificateGenerator.SetNotAfter(endDate); certificateGenerator.SetPublicKey(encryptionKeys.Public); // selfsign certificate Org.BouncyCastle.X509.X509Certificate certificate = certificateGenerator.Generate(encryptionKeys.Private, random); var store = new Pkcs12Store(); string friendlyName = certificate.SubjectDN.ToString(); var certificateEntry = new X509CertificateEntry(certificate); store.SetCertificateEntry(friendlyName, certificateEntry); store.SetKeyEntry(friendlyName, new AsymmetricKeyEntry(encryptionKeys.Private), new[] { certificateEntry }); var stream = new MemoryStream(); store.Save(stream, "".ToCharArray(), random); //Verify that the certificate is valid. var convertedCertificate = new X509Certificate2(stream.ToArray(), "", X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); return(convertedCertificate); }