/* * Private Helper method * will import certificate into App's key store */ private async Task <Certificate> ImportCertificateHelperAsync(string certFolder, string certFileName) { StorageFolder packageLocation = Windows.ApplicationModel.Package.Current.InstalledLocation; StorageFolder certificateFolder = await packageLocation.GetFolderAsync(certFolder); StorageFile certificate = await certificateFolder.GetFileAsync(certFileName); IBuffer buffer = await Windows.Storage.FileIO.ReadBufferAsync(certificate); string encodedString = Windows.Security.Cryptography.CryptographicBuffer.EncodeToBase64String(buffer); System.Diagnostics.Debug.WriteLine("Encoded Certificate: " + encodedString); await CertificateEnrollmentManager.ImportPfxDataAsync( encodedString, certificatePassword, ExportOption.NotExportable, KeyProtectionLevel.NoConsent, InstallOptions.DeleteExpired, "userCert"); IReadOnlyList <Windows.Security.Cryptography.Certificates.Certificate> certs = await Windows.Security.Cryptography.Certificates.CertificateStores.FindAllAsync(new Windows.Security.Cryptography.Certificates.CertificateQuery() { FriendlyName = "userCert" }); this.certificate = certs.FirstOrDefault(); System.Diagnostics.Debug.WriteLine("Certificate ready for user (CN): " + this.certificate.Subject); return(certs.FirstOrDefault()); }
private async void InstallClientCert_Click(object sender, RoutedEventArgs e) { InstallClientCertCompleted.Visibility = Visibility.Collapsed; try { Uri uri = new Uri("ms-appx:///Assets/tempClientCert.pfx"); var file = await StorageFile.GetFileFromApplicationUriAsync(uri); IBuffer buffer = await FileIO.ReadBufferAsync(file); //byte[] bytes; //CryptographicBuffer.CopyToByteArray(buffer, out bytes); string pfxData = CryptographicBuffer.EncodeToBase64String(buffer); // UserCertificateEnrollmentManager requires 'Shared User certificates' capability. //await CertificateEnrollmentManager.UserCertificateEnrollmentManager.ImportPfxDataAsync(...); await CertificateEnrollmentManager.ImportPfxDataAsync( pfxData, String.Empty, // password ExportOption.Exportable, KeyProtectionLevel.NoConsent, InstallOptions.None, "tempClientCert"); } catch (Exception ex) { DisplayException(ex); } InstallClientCertCompleted.Visibility = Visibility.Visible; }
/// <summary> /// Import an existing pfx certificate /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void ImportPfx_Click(object sender, RoutedEventArgs e) { TextBlock outputTextBlock = rootPage.FindName("OutputTextBlock") as TextBlock; try { outputTextBlock.Text = "Importing PFX certificate ..."; // Load the pfx certificate from resource string. ResourceLoader rl = new ResourceLoader(); string pfxCertificate = rl.GetString("Certificate"); string password = "******"; //password to access the certificate in PFX format string friendlyName = "test pfx certificate"; //call Certificate Enrollment funciton importPFXData to install the certificate await CertificateEnrollmentManager.ImportPfxDataAsync(pfxCertificate, password, ExportOption.NotExportable, KeyProtectionLevel.NoConsent, InstallOptions.None, friendlyName); outputTextBlock.Text += "\nCertificate installation succeeded. The certificate is in the appcontainer Personal certificate store"; } catch (Exception ex) { outputTextBlock.Text += "\nCertificate installation failed with error: " + ex.ToString(); } }
private async void ButtonSave_Click(object sender, RoutedEventArgs args) { using (new ControlDisabler(ButtonSave)) { if (clientCert != null) { try { await CertificateEnrollmentManager.ImportPfxDataAsync(clientCert, clientCertPassphrase, ExportOption.NotExportable, KeyProtectionLevel.NoConsent, InstallOptions.None, Constants.ClientCertFriendlyName); clientCert = null; } catch (Exception e) { await new ErrorContentDialog(e).ShowAsync(); return; } } var settings = new Storage.Settings { Server = serverAddress.Text, Organization = authOrg.Text, User = authUser.Text, Key = authKey.Password, }; settings.Store(); if (Window.Current.Content is Frame rootFrame && rootFrame.CanGoBack) { rootFrame.GoBack(); } } }
private async Task AddToWinCertStore() { Pkcs12Store store = new Pkcs12Store(); string friendlyName = "Limelight-Client"; var certEntry = new X509CertificateEntry(cert); store.SetCertificateEntry(friendlyName, certEntry); var keyEntry = new AsymmetricKeyEntry(keyPair.Private); store.SetKeyEntry(friendlyName, keyEntry, new[] { certEntry }); // Copy the Pkcs12Store to a stream using an arbitrary password const string password = "******"; var stream = new MemoryStream(); store.Save(stream, password.ToCharArray(), new SecureRandom()); // Write to .PFX string byte[] arr = stream.ToArray(); IBuffer buf = arr.AsBuffer(); string pfx = CryptographicBuffer.EncodeToBase64String(buf); await CertificateEnrollmentManager.ImportPfxDataAsync(pfx, password, ExportOption.NotExportable, KeyProtectionLevel.NoConsent, InstallOptions.None, friendlyName); }
private async void SetClientCertificate(ClientCertificate certificate) { if (certificate == null) { return; } try { var bytes = Convert.FromBase64String(certificate.RawData); } catch (Exception ex) { throw new HttpRequestException(FailureMessages.InvalidRawData, ex); } this.ClientCertificateOptions = ClientCertificateOption.Automatic; await CertificateEnrollmentManager.ImportPfxDataAsync(certificate.RawData, certificate.Passphrase, // the password is blank, but you can specify one here ExportOption.NotExportable, // there is no reason to keep the certificate Exportable KeyProtectionLevel.NoConsent, // whether any consent is required InstallOptions.DeleteExpired, // no installation options Package.Current.DisplayName); }
private async Task <Certificate> InstallClientCertificateAsync() { // Load the certificate from the clientCert.pfx file packaged with this sample. // This certificate has been signed with a trusted root certificate installed on the server. // The installation is done by running the setupServer.ps1 file, which should have been done // before running the app. // WARNING: Including a pfx file in the app package violates the Windows Store // certification requirements. We are shipping the pfx file with the package for demonstrating // the usage of client certificates. Apps that will be published through Windows Store // need to use other approaches to obtain a client certificate. StorageFile clientCertFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri(ClientCertUriPath)); IBuffer buffer = await FileIO.ReadBufferAsync(clientCertFile); AppendOutputLine("Reading certificate succeeded."); string clientCertData = Windows.Security.Cryptography.CryptographicBuffer.EncodeToBase64String(buffer); try { // Install the certificate to the app's certificate store. // The app certificate store is removed when the app is uninstalled. //To install a certificate to the CurrentUser\MY store, which is not app specific, // you need to use CertificateEnrollmentManager.UserCertificateEnrollmentManager.ImportPfxDataAsync(). // In order to call that method, an app must have the "sharedUserCertificates" capability. // There are two ways to add this capability: // // 1. You can double click on the Package.appxmanifest file from the // solution explorer, select the "Capabilities" tab in the opened page, and then check the // "Shared User Certificates" box from the capabilities list. // 2. You can right click on the Package.appxmanifest file from the // solution explorer, select "View Code", and add "sharedUserCertificates" under the <Capabilities> // element directly. // Package.appxmanifest in this sample shows this capability commented out. // // The certificate will remain even when the app is uninstalled. await CertificateEnrollmentManager.ImportPfxDataAsync( clientCertData, ClientCertPassword, ExportOption.Exportable, KeyProtectionLevel.NoConsent, InstallOptions.DeleteExpired, ClientCertFriendlyName); AppendOutputLine("Installing certificate succeeded."); // Return the certificate we just instaled. return(await FindCertificateFromStoreAsync()); } catch (Exception ex) { // This can happen if the certificate has already expired. AppendOutputLine("Installing certificate failed with" + ex.Message); return(null); } }
private async void ButtonClientCert_Click(object sender, RoutedEventArgs args) { using (new ControlDisabler(ButtonClientCert)) { var picker = new FileOpenPicker { ViewMode = PickerViewMode.List, SuggestedStartLocation = PickerLocationId.Downloads, }; picker.FileTypeFilter.Add(".pfx"); var file = await picker.PickSingleFileAsync(); if (file == null) { return; } var fileStream = await file.OpenReadAsync(); var certData = await new StreamReader(fileStream.AsStreamForRead()).ReadToEndAsync(); if (certData.IndexOf("-----BEGIN PKCS12-----") == -1) { await new ErrorContentDialog("Selected file is not a base64 PKCS12 certificate. Please use a certificate created using `certtool --load-certificate user.cert.pem --load-privkey user.key.pem --to-p12 --outfile user.pfx`") .ShowAsync(); return; } var passwordDialog = new CertPasswordContentDialog(); if (await passwordDialog.ShowAsync() != ContentDialogResult.Primary) { return; } var pass = passwordDialog.Password; try { // we're importing it with a temporary name to see if it's valid; "real" importing doesn't happen until save is pressed. await CertificateEnrollmentManager.ImportPfxDataAsync(certData, pass, ExportOption.NotExportable, KeyProtectionLevel.NoConsent, InstallOptions.None, Constants.ClientCertTempName); } catch (Exception e) { await new ErrorContentDialog(e) .ShowAsync(); return; } var certs = await CertificateStores.FindAllAsync(new CertificateQuery { FriendlyName = Constants.ClientCertTempName }); if (!certs.Where(c => c.HasPrivateKey).Any()) { await new ErrorContentDialog("Selected certificate contains no private key. Please use a certificate created using `certtool --load-certificate user.cert.pem --load-privkey user.key.pem --to-p12 --outfile user.pfx`") .ShowAsync(); return; } // everything looks good, remember values for saving clientCert = certData; clientCertPassphrase = pass; } }
/// <summary> /// Import an existing pfx certificate /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void RunSample_Click(object sender, RoutedEventArgs e) { CheckBox storeSelectionCheckbox = rootPage.FindName("UserStoreCheckBox") as CheckBox; TextBlock outputTextBlock = rootPage.FindName("OutputTextBlock") as TextBlock; PasswordBox pfxPasswordBox = rootPage.FindName("PfxPasswordBox") as PasswordBox; if (String.IsNullOrEmpty(pfxCertificate)) { outputTextBlock.Text = "Please select a valid PFX file\n"; return; } try { // Import PFX outputTextBlock.Text = "Importing PFX certificate ..."; string friendlyName = "test pfx certificate"; pfxPassword = pfxPasswordBox.Password; if (true == storeSelectionCheckbox.IsChecked) { // target store is User's Certificate Store // call User Certificate Enrollment function importPfxData to install the certificate await CertificateEnrollmentManager.UserCertificateEnrollmentManager.ImportPfxDataAsync( pfxCertificate, pfxPassword, ExportOption.NotExportable, KeyProtectionLevel.NoConsent, InstallOptions.None, friendlyName); outputTextBlock.Text += "\nCertificate installation succeeded. The certificate is in the User's certificate store"; } else { // target store is App's certificate store // call Certificate Enrollment function importPFXData to install the certificate await CertificateEnrollmentManager.ImportPfxDataAsync( pfxCertificate, pfxPassword, ExportOption.NotExportable, KeyProtectionLevel.NoConsent, InstallOptions.None, friendlyName); outputTextBlock.Text += "\nCertificate installation succeeded. The certificate is in the App's certificate store"; } } catch (Exception ex) { outputTextBlock.Text += "\nCertificate installation failed with error: " + ex.ToString(); } }
public void ManagementClientReturnsLocationList() { // Import certificate CertificateEnrollmentManager.ImportPfxDataAsync(_certificateString, _certificatePassword, ExportOption.NotExportable, KeyProtectionLevel.NoConsent, InstallOptions.None, "test").AsTask().Wait(); var credentials = new CertificateCloudCredentials(_subscription); var client = new ManagementClient(credentials); var result = client.Locations.List(); Assert.AreEqual(HttpStatusCode.OK, result.StatusCode); Assert.IsTrue(result.Locations.Count > 0); }
private async void SetClientCertificate(ClientCertificate certificate) { if (certificate == null) { return; } this.ClientCertificateOptions = ClientCertificateOption.Automatic; await CertificateEnrollmentManager.ImportPfxDataAsync(certificate.RawData, certificate.Passphrase, // the password is blank, but you can specify one here ExportOption.NotExportable, // there is no reason to keep the certificate Exportable KeyProtectionLevel.NoConsent, // whether any consent is required InstallOptions.DeleteExpired, // no installation options Package.Current.DisplayName); }
public async Task InstallAsync(string certResponse) { #region Bouncy castle PKCS #12 cert file generation var data = Convert.FromBase64String(certResponse); var parser = new X509CertificateParser(); var cert = parser.ReadCertificate(data); Pkcs12Store store = new Pkcs12StoreBuilder().Build(); X509CertificateEntry certEntry = new X509CertificateEntry(cert); store.SetCertificateEntry(cert.SubjectDN.ToString(), certEntry); // use DN as the Alias. AsymmetricKeyEntry keyEntry = new AsymmetricKeyEntry(_privateKey); store.SetKeyEntry(cert.SubjectDN.ToString() + "_key", keyEntry, new X509CertificateEntry[] { certEntry }); // string pfx = string.Empty; string password = ""; using (MemoryStream ms = new MemoryStream()) { store.Save(ms, password.ToCharArray(), _random); ms.Position = 0; await _storage.SetAsync("accessCert", ms.GetWindowsRuntimeBuffer()); StreamReader streamReader = new StreamReader(ms); // Write to .PFX string byte[] arr = ms.ToArray(); pfx = CryptographicBuffer.EncodeToBase64String(arr.AsBuffer()); } #endregion await _storage.SetAsync(StorageKeyNames.PrivateKey, pfx); await CertificateEnrollmentManager.ImportPfxDataAsync(pfx, password, ExportOption.NotExportable, KeyProtectionLevel.NoConsent, InstallOptions.None, "MAG_CERT"); // Store the registered cert subject if (cert.SubjectDN != null) { var valueList = cert.SubjectDN.GetValueList(X509Name.CN); if (valueList.Count > 0) { await _storage.SetAsync(StorageKeyNames.RegisteredCertSubject, (string)valueList[0]); } } }
private static async Task InstallCertificate(string filePath, string friendlyName) { //string certPath = @"Assets\BigsbyClientCert.pfx"; StorageFile file = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync(filePath); IBuffer buffer = await FileIO.ReadBufferAsync(file); string certData = CryptographicBuffer.EncodeToBase64String(buffer); // Will ask the user if they want this app to install the certificate if its not already installed. await CertificateEnrollmentManager.ImportPfxDataAsync( certData, "", ExportOption.NotExportable, KeyProtectionLevel.NoConsent, InstallOptions.None, friendlyName); }
public async Task <Certificate> GetIfExistsAsync() { var Certificate = await GetAsync(); try { if (Certificate == null) { string pfx = await _storage.GetTextAsync(StorageKeyNames.PrivateKey); if (pfx != null) { await CertificateEnrollmentManager.ImportPfxDataAsync(pfx, string.Empty, ExportOption.NotExportable, KeyProtectionLevel.NoConsent, InstallOptions.None, "MAG_CERT"); } Certificate = await GetAsync(); } } catch (Exception) { } return(Certificate); }
// Load a client certificate for accessing a PKI-secured server private async void LoadClientCertButton_Click(object sender, RoutedEventArgs e) { // Show the progress bar and a message ProgressStatus.Visibility = Visibility.Visible; MessagesTextBlock.Text = "Loading certificate ..."; try { // Import the certificate by providing: // -the encoded certificate string, // -the password (entered by the user) // -certificate options (export, key protection, install) // -a friendly name (the name of the pfx file) await CertificateEnrollmentManager.ImportPfxDataAsync( _certificateString, CertPasswordBox.Password, ExportOption.Exportable, KeyProtectionLevel.NoConsent, InstallOptions.None, _certificateName); // Report success MessagesTextBlock.Text = "Client certificate was successfully imported"; } catch (Exception ex) { // Report error MessagesTextBlock.Text = "Error loading certificate: " + ex.Message; } finally { // Hide progress bar and the password controls ProgressStatus.Visibility = Visibility.Collapsed; HideCertLogin(null, null); } }
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 }); string pfxData; using (MemoryStream memoryStream = new MemoryStream(512)) { store.Save(memoryStream, password.ToCharArray(), this.SecureRandom); pfxData = CryptographicBuffer.EncodeToBase64String(memoryStream.ToArray().AsBuffer()); } await CertificateEnrollmentManager.ImportPfxDataAsync( pfxData, password, ExportOption.NotExportable, KeyProtectionLevel.NoConsent, InstallOptions.DeleteExpired, friendlyName); // Read the UWP cert from the cert store Certificate uwpCertificate = (await CertificateStores.FindAllAsync( new CertificateQuery { FriendlyName = friendlyName }))[0]; 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. HttpBaseProtocolFilter filter = new HttpBaseProtocolFilter(); filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted); filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName); filter.ClientCertificate = uwpCertificate; HttpClient httpClient = new HttpClient(filter); // 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.SendRequestAsync(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.SendRequestAsync(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.SendRequestAsync(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.SendRequestAsync(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.SendRequestAsync(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.SendRequestAsync(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> /// Basic settings are configured on the view that is attached to this VM. /// </summary> /// <param name="screen"></param> public BasicSettingsViewModel(IScreen screen) { HostScreen = screen; // Look for a currently loaded cert and update the status... // We can't start this b.c. the ToProperty is lazy - and it won't // fire until Status is data-bound! LookupCertStatus = ReactiveCommand.CreateAsyncTask(a => SecurityUtils.FindCert(SecurityUtils.CERNCertName)); LookupCertStatus .Select(c => c == null ? "No Cert Loaded" : string.Format("Loaded (expires {0})", c.ValidTo.ToLocalTime().ToString("yyyy-MM-dd HH:mm"))) .ToProperty(this, x => x.Status, out _status, "", RxApp.MainThreadScheduler); LookupCertStatus .ExecuteAsync() .Subscribe(); // Error and status messages... var errors = new Subject <string>(); errors .ToProperty(this, x => x.Error, out _error, "", RxApp.MainThreadScheduler); // Given a file and a password, see if we can install it as a cert // in our internal repository. LoadFiles = ReactiveCommand.Create(); LoadFiles .Subscribe(x => errors.OnNext("")); var files = LoadFiles .Cast <Tuple <IReadOnlyList <StorageFile>, string> >(); files .Where(finfo => finfo.Item1 == null || finfo.Item1.Count != 1) .Select(f => "Invalid certificate file") .Subscribe(errors); files .Where(finfo => finfo.Item1 != null && finfo.Item1.Count == 1) .ObserveOn(RxApp.MainThreadScheduler) .Select(mf => { // We use this double subscribe because the readBufferAsync and ImportPfxDataAsync often return exceptions. // If we let the exception bubble all the way up, it terminates the sequence. Which means if the user entered // the wrong password they wouldn't get a chance to try again! return(Observable.Return(mf) .SelectMany(async f => { // Work around for the TplEventListener not working correctly. // https://social.msdn.microsoft.com/Forums/windowsapps/en-US/3e505e04-7f30-4313-aa47-275eaef333dd/systemargumentexception-use-of-undefined-keyword-value-1-for-event-taskscheduled-in-async?forum=wpdevelop await Task.Delay(1); var fs = f.Item1[0] as StorageFile; var buffer = await FileIO.ReadBufferAsync(fs); var cert = CryptographicBuffer.EncodeToBase64String(buffer); await CertificateEnrollmentManager.ImportPfxDataAsync(cert, f.Item2, ExportOption.NotExportable, KeyProtectionLevel.NoConsent, InstallOptions.DeleteExpired, SecurityUtils.CERNCertName); return Unit.Default; })); }) .Subscribe(c => c.Subscribe( g => LookupCertStatus.ExecuteAsync().Subscribe(), e => errors.OnNext(e.Message.TakeFirstLine()) )); // Set/Get the file expiration policy. CacheDecayOptions = ExpirationOptions.GetListExpirationOptions(); // Get the list of indico api keys we are watching // and hook up the MV for doing the api key manipulation ApiKeysForIndico = new ReactiveList <IndicoApiKey>(); ApiKeysForIndico.AddRange(IndicoApiKeyAccess.LoadAllKeys()); IndicoApiKeyAccess.IndicoApiKeysUpdated .Subscribe(_ => { using (ApiKeysForIndico.SuppressChangeNotifications()) { ApiKeysForIndico.Clear(); ApiKeysForIndico.AddRange(IndicoApiKeyAccess.LoadAllKeys()); } }); ShowIndicoApiKey = ReactiveCommand.Create(); ShowIndicoApiKey .Cast <IndicoApiKey>() .Select(x => new AddOrUpdateIndicoApiKeyViewModel(x)) .ToProperty(this, x => x.IndicoApiKey, out _indicoApiKeyVM, new AddOrUpdateIndicoApiKeyViewModel(null)); }