private void EnrollWorkerOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs) { string devName = YubikeyPivManager.Instance.ListDevices().FirstOrDefault(); bool hasDevice = !string.IsNullOrEmpty(devName); if (!hasDevice) { throw new InvalidOperationException("No yubikey"); } // 0. Get lock on yubikey using (YubikeyPivDevice dev = YubikeyPivManager.Instance.OpenDevice(devName)) { // 1. Prep device info int deviceId = (int)dev.GetSerialNumber(); string neoFirmware = dev.GetVersion().ToString(); Version pivFirmware; using (YubikeyPivDevice piv = YubikeyPivManager.Instance.OpenDevice(devName)) pivFirmware = piv.GetVersion(); _enrollWorker.ReportProgress(1); // 2 - Generate PUK, prep PIN byte[] randomKey = Utilities.GenerateRandomKey(); string puk = Utilities.MapBytesToString(randomKey.Take(8).ToArray()); string pin = txtPin.Text; _enrollWorker.ReportProgress(2); // 3 - Prep CA WindowsCertificate enrollmentAgent_std = WindowsCertStoreUtilities.FindCertificate(_settings.EnrollmentAgentCertificate); WindowsCertificate enrollmentAgent_adm = WindowsCertStoreUtilities.FindCertificate(_settings.EnrollmentAgentCertificate); string ca = _settings.CSREndpoint; string caTemplate = _settings.EnrollmentCaTemplate; string std_user = txtStdUser.Text; //std string adm_user = txtAdmUser.Text; //adm if (enrollmentAgent_std == null) { doWorkEventArgs.Cancel = true; _enrollWorkerMessage = "Unable to find the certificate with thumbprint: " + _settings.EnrollmentAgentCertificate; return; } _enrollWorker.ReportProgress(3); // 4 - Prep Management Key // TODO: Consider a new key every time? byte[] mgmKey = _settings.EnrollmentManagementKey; _enrollWorker.ReportProgress(4); RSAParameters publicKey_std = new RSAParameters(); RSAParameters publicKey_adm = new RSAParameters(); X509Certificate2 std_cert; X509Certificate2 adm_cert; byte[] chuid; using (YubikeyPivDevice pivTool = YubikeyPivManager.Instance.OpenDevice(devName)) { // 5 - Yubico: Reset device pivTool.BlockPin(); pivTool.BlockPuk(); bool reset = pivTool.ResetDevice(); if (!reset) { doWorkEventArgs.Cancel = true; _enrollWorkerMessage = "Unable to reset the YubiKey"; return; } _enrollWorker.ReportProgress(5); // 6 - Yubico: Management Key bool authenticated = pivTool.Authenticate(YubikeyPivDevice.DefaultManagementKey); if (!authenticated) { doWorkEventArgs.Cancel = true; _enrollWorkerMessage = "Unable to authenticate with the YubiKey"; return; } bool setMgmKey = pivTool.SetManagementKey(mgmKey); if (!setMgmKey) { doWorkEventArgs.Cancel = true; _enrollWorkerMessage = "Unable to set the management key"; return; } _enrollWorker.ReportProgress(6); // 7 - Yubico: Set CHUID bool setChuid = pivTool.SetCHUID(Guid.NewGuid(), out chuid); if (!setChuid) { doWorkEventArgs.Cancel = true; _enrollWorkerMessage = "Unable to set CHUID"; return; } _enrollWorker.ReportProgress(7); // 8 - Yubico: PIN int tmp; bool setPin = pivTool.ChangePin(YubikeyPivDevice.DefaultPin, pin, out tmp); if (!setPin) { doWorkEventArgs.Cancel = true; _enrollWorkerMessage = "Unable to set the PIN code"; return; } _enrollWorker.ReportProgress(8); // 9 - Yubico: PUK bool setPuk = pivTool.ChangePuk(YubikeyPivDevice.DefaultPuk, puk, out tmp); if (!setPuk) { doWorkEventArgs.Cancel = true; _enrollWorkerMessage = "Unable to set the PUK code"; return; } _enrollWorker.ReportProgress(9); // 10 - Yubico: Generate Key YubikeyAlgorithm algorithm = (YubikeyAlgorithm)drpAlgorithm.SelectedItem; if (std_user != "") { try { pivTool.GenerateKey9a(algorithm.Value, out publicKey_std); } catch { doWorkEventArgs.Cancel = true; _enrollWorkerMessage = "Unable to generate a keypair for Standard User"; return; } } if (adm_user != "") { try { pivTool.GenerateKey9d(algorithm.Value, out publicKey_adm); } catch { doWorkEventArgs.Cancel = true; _enrollWorkerMessage = "Unable to generate a keypair for Admin User"; return; } } _enrollWorker.ReportProgress(10); } // 11 - Yubico: Make CSR string csr_std = null; string csr_adm = null; string csrError = null; if (std_user != "") { try { MakeCsr_std(Utilities.ExportPublicKeyToPEMFormat(publicKey_std), pin, out csrError, out csr_std); } catch { doWorkEventArgs.Cancel = true; _enrollWorkerMessage = "Unable to generate a CSR for Standard User" + Environment.NewLine + csrError; return; } } if (adm_user != "") { try { MakeCsr_adm(Utilities.ExportPublicKeyToPEMFormat(publicKey_adm), pin, out csrError, out csr_adm); } catch { doWorkEventArgs.Cancel = true; _enrollWorkerMessage = "Unable to generate a CSR for Admin User" + Environment.NewLine + csrError; return; } } _enrollWorker.ReportProgress(11); // 12 - Enroll string std_enrollError = null; string adm_enrollError = null; bool std_enrolled = true; bool adm_enrolled = true; if (std_user != "") { std_enrolled = CertificateUtilities.Enroll(std_user, enrollmentAgent_std, ca, caTemplate, csr_std, out std_enrollError, out std_cert); } else { std_cert = null; } if (adm_user != "") { adm_enrolled = CertificateUtilities.Enroll(adm_user, enrollmentAgent_adm, ca, caTemplate, csr_adm, out adm_enrollError, out adm_cert); } else { adm_cert = null; } if (!std_enrolled) { doWorkEventArgs.Cancel = true; _enrollWorkerMessage = "Unable to enroll a certificate for Standard User." + Environment.NewLine + std_enrollError; return; } if (!adm_enrolled) { doWorkEventArgs.Cancel = true; _enrollWorkerMessage = "Unable to enroll a certificate for Admin User." + Environment.NewLine + adm_enrollError; return; } _enrollWorker.ReportProgress(12); using (YubikeyPivDevice pivTool = YubikeyPivManager.Instance.OpenDevice(devName)) { // 13 - Yubico: Import Cert bool authenticatedForCert = pivTool.Authenticate(mgmKey); if (!authenticatedForCert) { doWorkEventArgs.Cancel = true; _enrollWorkerMessage = "Unable to authenticate prior to importing a certificate"; return; } if (std_user != "") { try { pivTool.SetCertificate9a(std_cert); } catch { doWorkEventArgs.Cancel = true; _enrollWorkerMessage = $"Unable to import a certificate"; return; } } if (adm_user != "") { try { pivTool.SetCertificate9d(adm_cert); } catch { doWorkEventArgs.Cancel = true; _enrollWorkerMessage = $"Unable to import a certificate"; return; } } _enrollWorker.ReportProgress(13); } // 14 - Create enrolled item for Standard User if (std_user != "") { EnrolledYubikey newEnrollment_std = new EnrolledYubikey(); newEnrollment_std.DeviceSerial = deviceId; newEnrollment_std.Certificate.Serial = std_cert.SerialNumber; newEnrollment_std.Certificate.Thumbprint = std_cert.Thumbprint; newEnrollment_std.Certificate.Subject = std_cert.Subject; newEnrollment_std.Certificate.Issuer = std_cert.Issuer; newEnrollment_std.Certificate.StartDate = std_cert.NotBefore; newEnrollment_std.Certificate.ExpireDate = std_cert.NotAfter; newEnrollment_std.Certificate.RawCertificate = std_cert.RawData; newEnrollment_std.CA = ca; newEnrollment_std.Username = std_user; newEnrollment_std.Slot = "Standard User"; newEnrollment_std.ManagementKey = mgmKey; newEnrollment_std.PukKey = puk; newEnrollment_std.Chuid = BitConverter.ToString(chuid).Replace("-", ""); newEnrollment_std.EnrolledAt = DateTime.UtcNow; newEnrollment_std.YubikeyVersions.NeoFirmware = neoFirmware; newEnrollment_std.YubikeyVersions.PivApplet = pivFirmware.ToString(); _dataStore.Add(newEnrollment_std); } // 14 - Create enrolled item for Admin User if (adm_user != "") { EnrolledYubikey newEnrollment_adm = new EnrolledYubikey(); newEnrollment_adm.DeviceSerial = deviceId; newEnrollment_adm.Certificate.Serial = adm_cert.SerialNumber; newEnrollment_adm.Certificate.Thumbprint = adm_cert.Thumbprint; newEnrollment_adm.Certificate.Subject = adm_cert.Subject; newEnrollment_adm.Certificate.Issuer = adm_cert.Issuer; newEnrollment_adm.Certificate.StartDate = adm_cert.NotBefore; newEnrollment_adm.Certificate.ExpireDate = adm_cert.NotAfter; newEnrollment_adm.Certificate.RawCertificate = adm_cert.RawData; newEnrollment_adm.CA = ca; newEnrollment_adm.Username = adm_user; newEnrollment_adm.Slot = "Admin User"; newEnrollment_adm.ManagementKey = mgmKey; newEnrollment_adm.PukKey = puk; newEnrollment_adm.Chuid = BitConverter.ToString(chuid).Replace("-", ""); newEnrollment_adm.EnrolledAt = DateTime.UtcNow; newEnrollment_adm.YubikeyVersions.NeoFirmware = neoFirmware; newEnrollment_adm.YubikeyVersions.PivApplet = pivFirmware.ToString(); _dataStore.Add(newEnrollment_adm); } _enrollWorker.ReportProgress(14); // 15 - Save store _dataStore.Save(MainForm.FileStore); _enrollWorker.ReportProgress(15); // Report doWorkEventArgs.Cancel = false; _enrollWorkerMessage = "Success"; } }