private async Task DeleteExistingFromStore(string storePath) { if (String.IsNullOrEmpty(storePath)) { return; } using (DirectoryCertificateStore store = (DirectoryCertificateStore)CertificateStoreIdentifier.OpenStore(storePath)) { X509Certificate2Collection certificates = await store.Enumerate(); foreach (var certificate in certificates) { if (store.GetPrivateKeyFilePath(certificate.Thumbprint) != null) { continue; } List <string> fields = Utils.ParseDistinguishedName(certificate.Subject); if (fields.Contains("CN=UA Local Discovery Server")) { continue; } DirectoryCertificateStore ds = store as DirectoryCertificateStore; if (ds != null) { string path = Utils.GetAbsoluteFilePath(m_application.CertificatePublicKeyPath, true, false, false); if (path != null) { if (String.Compare(path, ds.GetPublicKeyFilePath(certificate.Thumbprint), StringComparison.OrdinalIgnoreCase) == 0) { continue; } } path = Utils.GetAbsoluteFilePath(m_application.CertificatePrivateKeyPath, true, false, false); if (path != null) { if (String.Compare(path, ds.GetPrivateKeyFilePath(certificate.Thumbprint), StringComparison.OrdinalIgnoreCase) == 0) { continue; } } } await store.Delete(certificate.Thumbprint); } } }
/// <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 { RsaUtils.RSADispose(rsa); throw new CryptographicException("Can not encrypt IoTHub security token using generated public key!"); } } RsaUtils.RSADispose(rsa); // 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(); // 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); } } // add new one await store.Add(certificate); } 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; } }