public bool SetCHUID(Guid newId, out byte[] newChuid) { newChuid = new byte[] { 0x30, 0x19, 0xd4, 0xe7, 0x39, 0xda, 0x73, 0x9c, 0xed, 0x39, 0xce, 0x73, 0x9d, 0x83, 0x68, 0x58, 0x21, 0x08, 0x42, 0x10, 0x84, 0x21, 0x38, 0x42, 0x10, 0xc3, 0xf5, 0x34, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x08, 0x32, 0x30, 0x33, 0x30, 0x30, 0x31, 0x30, 0x31, 0x3e, 0x00, 0xfe, 0x00 }; int writeOffset = 29; byte[] guidBytes = newId.ToByteArray(); Array.Copy(guidBytes, 0, newChuid, writeOffset, guidBytes.Length); YubicoPivReturnCode code = YubikeyPivNative.YkPivSaveObject(_deviceHandle.State, YubikeyPivNative.YKPIV_OBJ_CHUID, newChuid, newChuid.Length); if (code != YubicoPivReturnCode.YKPIV_OK) { return(false); } return(true); }
public bool ResetDevice() { byte[] templ = { 0, YubikeyPivNative.YKPIV_INS_RESET, 0, 0 }; byte[] inData = new byte[0]; byte[] outData = new byte[256]; int outLength = outData.Length, sw = -1; YubicoPivReturnCode code = YubikeyPivNative.YkPivTransferData(_deviceHandle.State, templ, inData, inData.Length, outData, ref outLength, ref sw); return(code == YubicoPivReturnCode.YKPIV_OK && sw == 0x9000); }
internal YubikeyPivDevice(string name) { _deviceHandle = new YubikeyPivDeviceHandle(); YubicoPivReturnCode code = YubikeyPivNative.YkPivConnect(_deviceHandle.State, name); if (code != YubicoPivReturnCode.YKPIV_OK) { throw new Exception("Unable to connect to PIV: " + code); } }
public uint GetSerialNumber() { uint serial = 0; YubicoPivReturnCode code = YubikeyPivNative.YkPivGetSerial(_deviceHandle.State, ref serial); if (code != YubicoPivReturnCode.YKPIV_OK) { throw new Exception("Unable to get serialnumber: " + code); } return(serial); }
public bool VerifyPin(string pin, out int remainingTries) { int triesLeft = -1; YubicoPivReturnCode code = YubikeyPivNative.YkPivVerify(_deviceHandle.State, pin, ref triesLeft); remainingTries = triesLeft; if (code == YubicoPivReturnCode.YKPIV_OK) { return(true); } return(false); }
public Version GetVersion() { const int length = 256; StringBuilder sb = new StringBuilder(length); YubicoPivReturnCode code = YubikeyPivNative.YkPivGetVersion(_deviceHandle.State, sb, length); if (code != YubicoPivReturnCode.YKPIV_OK) { throw new Exception("Unable to fetch PIV version: " + code); } return(Version.Parse(sb.ToString())); }
public bool GetCHUID(out byte[] chuid) { byte[] tmp = new byte[2048]; int length = tmp.Length; YubicoPivReturnCode code = YubikeyPivNative.YkPivFetchObject(_deviceHandle.State, YubikeyPivNative.YKPIV_OBJ_CHUID, tmp, ref length); if (code != YubicoPivReturnCode.YKPIV_OK) { chuid = null; return(false); } chuid = new byte[length]; Array.Copy(tmp, chuid, length); return(true); }
public bool ChangePin(string oldPin, string pin, out int remainingTries) { byte[] templ = { 0, YubikeyPivNative.YKPIV_INS_CHANGE_REFERENCE, 0, 0x80 }; byte[] inData = new byte[16]; byte[] outData = new byte[256]; int outLength = outData.Length, sw = -1; for (int i = 0; i < inData.Length; i++) { inData[i] = 0xFF; } // Set up PUK and NEWPUK Encoding.ASCII.GetBytes(oldPin, 0, Math.Min(8, oldPin.Length), inData, 0); Encoding.ASCII.GetBytes(pin, 0, Math.Min(8, pin.Length), inData, 8); YubicoPivReturnCode code = YubikeyPivNative.YkPivTransferData(_deviceHandle.State, templ, inData, inData.Length, outData, ref outLength, ref sw); if (code != YubicoPivReturnCode.YKPIV_OK) { remainingTries = -1; return(false); } if (sw != 0x9000) { if ((sw >> 8) == 0x63) { remainingTries = sw & 0xff; return(false); } if (sw == 0x6983) { remainingTries = 0; return(false); } } remainingTries = -1; return(true); }
public bool UnblockPin(string puk, string newPin) { byte[] templ = { 0, YubikeyPivNative.YKPIV_INS_RESET_RETRY, 0, 0x80 }; byte[] inData = new byte[16]; byte[] outData = new byte[256]; int outLength = outData.Length, sw = -1; for (int i = 0; i < inData.Length; i++) { inData[i] = 0xFF; } // Set up PUK and NEWPUK Encoding.ASCII.GetBytes(puk, 0, Math.Min(8, puk.Length), inData, 0); Encoding.ASCII.GetBytes(newPin, 0, Math.Min(8, newPin.Length), inData, 8); YubicoPivReturnCode code = YubikeyPivNative.YkPivTransferData(_deviceHandle.State, templ, inData, inData.Length, outData, ref outLength, ref sw); return(code == YubicoPivReturnCode.YKPIV_OK); }
public YubicoPivReturnCode SetCertificate9a(X509Certificate2 cert) { byte[] certData = cert.GetRawCertData(); byte[] data = new byte[certData.Length + 1 + 3 + 5]; data[0] = 0x70; int offset = 1; offset += SetDataLength(data, offset, certData.Length); Array.Copy(certData, 0, data, offset, certData.Length); offset += certData.Length; data[offset++] = 0x71; data[offset++] = 1; data[offset++] = 0; // certinfo (gzip etc) data[offset++] = 0xFE; // LRC data[offset++] = 0; YubicoPivReturnCode code = YubikeyPivNative.YkPivSaveObject(_deviceHandle.State, YubikeyPivNative.YKPIV_OBJ_AUTHENTICATION, data, offset); return(code); }
public IEnumerable <string> ListDevices(bool filter = true) { byte[] data; using (YubikeyPivDeviceHandle deviceHandle = new YubikeyPivDeviceHandle()) { IntPtr ptr = IntPtr.Zero; try { int len = 2048; // A typical reader name is 32 chars long. This gives space for 64 readers. ptr = Marshal.AllocHGlobal(len); IntPtr dev = deviceHandle.State; YubicoPivReturnCode res = YubikeyPivNative.YkPivListReaders(dev, ptr, ref len); if (res != YubicoPivReturnCode.YKPIV_OK) { return(Enumerable.Empty <string>()); } data = new byte[len]; Marshal.Copy(ptr, data, 0, len); } finally { if (ptr != IntPtr.Zero) { Marshal.FreeHGlobal(ptr); } } } if (filter) { return(StringUtils.ParseStrings(data).Where(IsValidDevice)); } return(StringUtils.ParseStrings(data)); }
private void EnrollWorkerOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs) { string devName = YubikeyNeoManager.Instance.ListDevices().FirstOrDefault(); bool hasDevice = !string.IsNullOrEmpty(devName); if (!hasDevice) { throw new InvalidOperationException("No yubikey"); } // 0. Get lock on yubikey using (YubikeyNeoDevice dev = YubikeyNeoManager.Instance.OpenDevice(devName)) { // 1. Prep device info int deviceId = 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 = WindowsCertStoreUtilities.FindCertificate(_settings.EnrollmentAgentCertificate); string ca = _settings.CSREndpoint; string caTemplate = _settings.EnrollmentCaTemplate; string user = txtUser.Text; if (enrollmentAgent == 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; X509Certificate2 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; bool keyGenerated = pivTool.GenerateKey9a(algorithm.Value, out publicKey); if (!keyGenerated) { doWorkEventArgs.Cancel = true; _enrollWorkerMessage = "Unable to generate a keypair"; return; } _enrollWorker.ReportProgress(10); } // 11 - Yubico: Make CSR string csr; string csrError; bool madeCsr = MakeCsr(Utilities.ExportPublicKeyToPEMFormat(publicKey), pin, out csrError, out csr); if (!madeCsr) { doWorkEventArgs.Cancel = true; _enrollWorkerMessage = "Unable to generate a CSR" + Environment.NewLine + csrError; return; } _enrollWorker.ReportProgress(11); // 12 - Enroll string enrollError; bool enrolled = CertificateUtilities.Enroll(user, enrollmentAgent, ca, caTemplate, csr, out enrollError, out cert); if (!enrolled) { doWorkEventArgs.Cancel = true; _enrollWorkerMessage = "Unable to enroll a certificate." + Environment.NewLine + 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; } YubicoPivReturnCode imported = pivTool.SetCertificate9a(cert); if (imported != YubicoPivReturnCode.YKPIV_OK) { doWorkEventArgs.Cancel = true; _enrollWorkerMessage = $"Unable to import a certificate, return code {imported}"; return; } _enrollWorker.ReportProgress(13); } // 14 - Create enrolled item EnrolledYubikey newEnrollment = new EnrolledYubikey(); newEnrollment.DeviceSerial = deviceId; newEnrollment.Certificate.Serial = cert.SerialNumber; newEnrollment.Certificate.Thumbprint = cert.Thumbprint; newEnrollment.Certificate.Subject = cert.Subject; newEnrollment.Certificate.Issuer = cert.Issuer; newEnrollment.Certificate.StartDate = cert.NotBefore; newEnrollment.Certificate.ExpireDate = cert.NotAfter; newEnrollment.Certificate.RawCertificate = cert.RawData; newEnrollment.CA = ca; newEnrollment.Username = user; newEnrollment.ManagementKey = mgmKey; newEnrollment.PukKey = puk; newEnrollment.Chuid = BitConverter.ToString(chuid).Replace("-", ""); newEnrollment.EnrolledAt = DateTime.UtcNow; newEnrollment.YubikeyVersions.NeoFirmware = neoFirmware; newEnrollment.YubikeyVersions.PivApplet = pivFirmware.ToString(); _dataStore.Add(newEnrollment); _enrollWorker.ReportProgress(14); // 15 - Save store _dataStore.Save(MainForm.FileStore); _enrollWorker.ReportProgress(15); // Report doWorkEventArgs.Cancel = false; _enrollWorkerMessage = "Success"; } }
public bool GenerateKey9a(byte algorithm, out RSAParameters publicKey) { publicKey = new RSAParameters(); byte[] templ = { 0, YubikeyPivNative.YKPIV_INS_GENERATE_ASYMMETRIC, 0, 0x9A }; byte[] inData = new byte[5]; // TODO: Newer versions of yubico-piv-tool use 11 bytes of data, see: https://github.com/Yubico/yubico-piv-tool/blob/b08de955970c5cd544c740990fb68f496fedb814/tool/yubico-piv-tool.c#L122 byte[] outData = new byte[1024]; int outLength = outData.Length, sw = -1; // Set up IN inData[0] = 0xAC; inData[1] = 3; inData[2] = 0x80; inData[3] = 1; inData[4] = algorithm; YubicoPivReturnCode code = YubikeyPivNative.YkPivTransferData(_deviceHandle.State, templ, inData, inData.Length, outData, ref outLength, ref sw); if (code != YubicoPivReturnCode.YKPIV_OK) { return(false); } if (sw != 0x9000) { return(false); } // Skip first 2 bytes outData = outData.Skip(2).ToArray(); int dataLength; int offset = GetDataOffsetAndLength(outData, out dataLength); outData = outData.Skip(offset).ToArray(); if (outData[0] != 0x81) { throw new InvalidOperationException("Received bad public key from yubikey"); } Array.Copy(outData, 1, outData, 0, outData.Length - 1); offset = GetDataOffsetAndLength(outData, out dataLength); byte[] modulus = outData.Skip(offset).Take(dataLength).ToArray(); outData = outData.Skip(offset + dataLength).ToArray(); if (outData[0] != 0x82) { throw new InvalidOperationException("Received bad public key structure from yubikey"); } Array.Copy(outData, 1, outData, 0, outData.Length - 1); offset = GetDataOffsetAndLength(outData, out dataLength); byte[] exponent = outData.Skip(offset).Take(dataLength).ToArray(); publicKey.Modulus = modulus; publicKey.Exponent = exponent; return(true); }