Exemple #1
0
        public YubikeyPivDeviceHandle()
        {
            IntPtr dev = IntPtr.Zero;

            YubikeyPivNative.YkPivInit(ref dev, 0);
            State = dev;
        }
Exemple #2
0
        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);
        }
Exemple #3
0
        public int GetPinTriesLeft()
        {
            int triesLeft = -1;

            YubikeyPivNative.YkPivVerify(_deviceHandle.State, null, ref triesLeft);

            return(triesLeft);
        }
Exemple #4
0
        public bool Authenticate(byte[] managementKey)
        {
            if (managementKey == null || managementKey.Length != 24)
            {
                throw new ArgumentException("Must be 24 bytes");
            }

            return(YubikeyPivNative.YkPivAuthenticate(_deviceHandle.State, managementKey) == YubicoPivReturnCode.YKPIV_OK);
        }
Exemple #5
0
        //public bool SignData(byte[] toSign, out byte[] signature)
        //{
        //    byte key = 0x9A; // Slot 9a

        //    signature = null;
        //    byte[] result = new byte[256];
        //    int outputLength = result.Length;

        //    YubicoPivReturnCode code = YkPivSignData(_deviceHandle.State, toSign, toSign.Length, result, ref outputLength, YKPIV_ALGO_RSA2048, key);

        //    if (code != YubicoPivReturnCode.YKPIV_OK)
        //        return false;


        //    return true;
        //}

        public bool SetManagementKey(byte[] newKey)
        {
            if (newKey == null || newKey.Length != 24)
            {
                throw new ArgumentException("Must be 24 bytes");
            }

            return(YubikeyPivNative.YkPivSetManagementKey(_deviceHandle.State, newKey) == YubicoPivReturnCode.YKPIV_OK);
        }
Exemple #6
0
        public void Dispose()
        {
            if (State != IntPtr.Zero)
            {
                YubikeyPivNative.YkPivDone(State);
            }

            State = IntPtr.Zero;
        }
Exemple #7
0
        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);
        }
Exemple #8
0
        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);
            }
        }
Exemple #9
0
        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);
        }
Exemple #10
0
        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()));
        }
Exemple #11
0
        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);
        }
Exemple #12
0
        public X509Certificate2 GetCertificate9a()
        {
            byte[] data;
            int    length = 2048;

            YubicoPivReturnCode code;

            do
            {
                length *= 2;

                data = new byte[length];
                int tmpLength = length;
                code = YubikeyPivNative.YkPivFetchObject(_deviceHandle.State, YubikeyPivNative.YKPIV_OBJ_AUTHENTICATION, data, ref tmpLength);

                if (code == YubicoPivReturnCode.YKPIV_GENERIC_ERROR)
                {
                    // Object is not set
                    return(null);
                }

                if (code == YubicoPivReturnCode.YKPIV_OK && code == YubicoPivReturnCode.YKPIV_SIZE_ERROR)
                {
                    continue;
                }

                // Shift up 1 byte to skip the first
                Array.Copy(data, 1, data, 0, data.Length - 1);

                // Resize for later
                Array.Resize(ref data, tmpLength - 1);
            } while (code == YubicoPivReturnCode.YKPIV_SIZE_ERROR);

            if (code != YubicoPivReturnCode.YKPIV_OK)
            {
                throw new Exception("Unable to fetch for PIV certificate 9a: " + code);
            }

            int certLength;
            int offset = GetDataOffsetAndLength(data, out certLength);

            Array.Copy(data, offset, data, 0, certLength);
            //Array.Resize(ref data, certLength);

            return(new X509Certificate2(data));
        }
Exemple #13
0
        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);
        }
Exemple #14
0
        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);
        }
Exemple #15
0
        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);
        }
Exemple #16
0
        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);
        }
Exemple #17
0
        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));
        }
Exemple #18
0
        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);
        }
Exemple #19
0
 public void Dispose()
 {
     YubikeyPivNative.YkPivDisconnect(_deviceHandle.State);
     _deviceHandle.Dispose();
 }