PKCS#11 URI builder

Implementation note: As recommended by PKCS#11 URI specification Pkcs11UriBuilder class percent-encodes the whole value of the "id" attribute which is supposed to be handled as arbitrary binary data. Therefore it is not possible to construct URIs with arbitrary string value of the "id" attribute.

Implementation note: Validation of each individual attribute value is performed by the setter of corresponding Pkcs11UriBuilder class property with the exception to UnknownPathAttributes and UnknownQueryAttributes properties whose values are validated when ToString() or ToPkcs11Uri() method is called.

        public void _01_Pkcs11UriInSignatureCreationApplication()
        {
            if (Platform.UnmanagedLongSize != 8 || Platform.StructPackingSize != 0)
                Assert.Inconclusive("Test cannot be executed on this platform");

            // PKCS#11 URI can be acquired i.e. from configuration file as a simple string...
            string uri = @"<pkcs11:serial=7BFF2737350B262C;
                            type=private;
                            object=John%20Doe
                            ?module-path=pkcs11.dll&
                            pin-value=11111111>";

            Assert.IsNotNull(uri);

            // ...or it can be easily constructed with Pkcs11UriBuilder
            Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
            pkcs11UriBuilder.Serial = "7BFF2737350B262C";
            pkcs11UriBuilder.Type = CKO.CKO_PRIVATE_KEY;
            pkcs11UriBuilder.Object = "John Doe";
            pkcs11UriBuilder.ModulePath = "pkcs11.dll";
            pkcs11UriBuilder.PinValue = "11111111";
            uri = pkcs11UriBuilder.ToString();

            Assert.IsNotNull(uri);

            // Warning: Please note that PIN stored in PKCS#11 URI can pose a security risk and therefore other options
            //          should be carefully considered. For example an application may ask for a PIN with a GUI dialog etc.

            // Use PKCS#11 URI acquired from Settings class to identify private key in signature creation method
            byte[] signature = SignData(ConvertUtils.Utf8StringToBytes("Hello world"), Settings.PrivateKeyUri);

            // Do something interesting with the signature
            Assert.IsNotNull(signature);
        }
        public void Pkcs11UriInSignatureCreationApplication()
        {
            byte[] dataToSign = ConvertUtils.Utf8StringToBytes("Hello world");
            
            // PKCS#11 URI can be acquired i.e. from configuration file as a simple string...
            string uri = @"<pkcs11:serial=7BFF2737350B262C;
                            type=private;
                            object=John%20Doe
                            ?module-path=siecap11.dll&
                            pin-value=11111111>";

            // ...or it can be easily constructed with Pkcs11UriBuilder
            Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
            pkcs11UriBuilder.Serial = "7BFF2737350B262C";
            pkcs11UriBuilder.Type = CKO.CKO_PRIVATE_KEY;
            pkcs11UriBuilder.Object = "John Doe";
            pkcs11UriBuilder.ModulePath = "siecap11.dll";
            pkcs11UriBuilder.PinValue = "11111111";
            uri = pkcs11UriBuilder.ToString();

            // Warning: Please note that PIN stored in PKCS#11 URI can pose a security risk and therefore other options
            //          should be carefully considered. For example an application may ask for a PIN with a GUI dialog etc.

            // Use PKCS#11 URI to identify private key in signature creation method
            byte[] signature = SignData(dataToSign, uri);

            // Do something interesting with the signature
        }
        public void _02_LibraryInfoMatches()
        {
            if (Platform.UnmanagedLongSize != 4 || Platform.StructPackingSize != 1)
                Assert.Inconclusive("Test cannot be executed on this platform");

            using (Pkcs11 pkcs11 = new Pkcs11(Settings.Pkcs11LibraryPath, Settings.UseOsLocking))
            {
                LibraryInfo libraryInfo = pkcs11.GetInfo();

                // Empty URI
                Pkcs11Uri pkcs11uri = new Pkcs11Uri(@"pkcs11:");
                Assert.IsTrue(Pkcs11UriUtils.Matches(pkcs11uri, libraryInfo));

                // Unknown path attribute in URI
                pkcs11uri = new Pkcs11Uri(@"pkcs11:vendor=foobar");
                Assert.IsFalse(Pkcs11UriUtils.Matches(pkcs11uri, libraryInfo));

                // All attributes matching
                Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.LibraryManufacturer = libraryInfo.ManufacturerId;
                pkcs11UriBuilder.LibraryDescription = libraryInfo.LibraryDescription;
                pkcs11UriBuilder.LibraryVersion = libraryInfo.LibraryVersion;
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                Assert.IsTrue(Pkcs11UriUtils.Matches(pkcs11uri, libraryInfo));

                // LibraryManufacturer nonmatching
                pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.LibraryManufacturer = "foobar";
                pkcs11UriBuilder.LibraryDescription = libraryInfo.LibraryDescription;
                pkcs11UriBuilder.LibraryVersion = libraryInfo.LibraryVersion;
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                Assert.IsFalse(Pkcs11UriUtils.Matches(pkcs11uri, libraryInfo));

                // LibraryDescription nonmatching
                pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.LibraryManufacturer = libraryInfo.ManufacturerId;
                pkcs11UriBuilder.LibraryDescription = "foobar";
                pkcs11UriBuilder.LibraryVersion = libraryInfo.LibraryVersion;
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                Assert.IsFalse(Pkcs11UriUtils.Matches(pkcs11uri, libraryInfo));

                // LibraryVersion nonmatching
                pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.LibraryManufacturer = libraryInfo.ManufacturerId;
                pkcs11UriBuilder.LibraryDescription = libraryInfo.LibraryDescription;
                pkcs11UriBuilder.LibraryVersion = "0";
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                Assert.IsFalse(Pkcs11UriUtils.Matches(pkcs11uri, libraryInfo));
            }
        }
        public void LibraryInfoMatchesHLA()
        {
            using (HLA.Pkcs11 pkcs11 = new HLA.Pkcs11(Settings.Pkcs11LibraryPath, false))
            {
                HLA.LibraryInfo libraryInfo = pkcs11.GetInfo();

                // Empty URI
                Pkcs11Uri pkcs11uri = new Pkcs11Uri(@"pkcs11:");
                Assert.IsTrue(Pkcs11UriUtils.Matches(pkcs11uri, libraryInfo));

                // Unknown path attribute in URI
                pkcs11uri = new Pkcs11Uri(@"pkcs11:vendor=foobar");
                Assert.IsFalse(Pkcs11UriUtils.Matches(pkcs11uri, libraryInfo));

                // All attributes matching
                Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.LibraryManufacturer = libraryInfo.ManufacturerId;
                pkcs11UriBuilder.LibraryDescription = libraryInfo.LibraryDescription;
                pkcs11UriBuilder.LibraryVersion = libraryInfo.LibraryVersion;
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                Assert.IsTrue(Pkcs11UriUtils.Matches(pkcs11uri, libraryInfo));

                // LibraryManufacturer nonmatching
                pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.LibraryManufacturer = "foobar";
                pkcs11UriBuilder.LibraryDescription = libraryInfo.LibraryDescription;
                pkcs11UriBuilder.LibraryVersion = libraryInfo.LibraryVersion;
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                Assert.IsFalse(Pkcs11UriUtils.Matches(pkcs11uri, libraryInfo));

                // LibraryDescription nonmatching
                pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.LibraryManufacturer = libraryInfo.ManufacturerId;
                pkcs11UriBuilder.LibraryDescription = "foobar";
                pkcs11UriBuilder.LibraryVersion = libraryInfo.LibraryVersion;
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                Assert.IsFalse(Pkcs11UriUtils.Matches(pkcs11uri, libraryInfo));

                // LibraryVersion nonmatching
                pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.LibraryManufacturer = libraryInfo.ManufacturerId;
                pkcs11UriBuilder.LibraryDescription = libraryInfo.LibraryDescription;
                pkcs11UriBuilder.LibraryVersion = "0";
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                Assert.IsFalse(Pkcs11UriUtils.Matches(pkcs11uri, libraryInfo));
            }
        }
        public void VendorSpecificQueryAttributeWithoutValue()
        {
            string uri = @"pkcs11:?vendor=";

            // Build URI
            Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
            pkcs11UriBuilder.UnknownQueryAttributes = new Dictionary<string, List<string>>();
            pkcs11UriBuilder.UnknownQueryAttributes.Add("vendor", new List<string> { string.Empty });
            Assert.IsTrue(uri == pkcs11UriBuilder.ToString());

            // Parse URI
            Pkcs11Uri pkcs11uri = new Pkcs11Uri(uri);
            Assert.IsTrue(pkcs11uri.DefinesLibrary == false);
            Assert.IsTrue(pkcs11uri.DefinesSlot == false);
            Assert.IsTrue(pkcs11uri.DefinesToken == false);
            Assert.IsTrue(pkcs11uri.DefinesObject == false);
            Assert.IsTrue(pkcs11uri.UnknownQueryAttributes != null && pkcs11uri.UnknownQueryAttributes.Count == 1);
            Assert.IsTrue(pkcs11uri.UnknownQueryAttributes["vendor"].Count == 1);
            Assert.IsTrue(pkcs11uri.UnknownQueryAttributes["vendor"][0] == string.Empty);
        }
        public void VendorSpecificQueryAttributeWithValidNameAndValue()
        {
            string uri = @"pkcs11:?" + _pk11VendorAttrNameChars + "=" + _pk11QueryChars + _pctEncodedUnicodeChar;

            // Build URI
            Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
            pkcs11UriBuilder.UnknownQueryAttributes = new Dictionary<string, List<string>>();
            pkcs11UriBuilder.UnknownQueryAttributes.Add(_pk11VendorAttrNameChars, new List<string> { _pk11QueryChars + _unicodeChar });
            Assert.IsTrue(uri == pkcs11UriBuilder.ToString());

            // Parse URI
            Pkcs11Uri pkcs11uri = new Pkcs11Uri(uri);
            Assert.IsTrue(pkcs11uri.DefinesLibrary == false);
            Assert.IsTrue(pkcs11uri.DefinesSlot == false);
            Assert.IsTrue(pkcs11uri.DefinesToken == false);
            Assert.IsTrue(pkcs11uri.DefinesObject == false);
            Assert.IsTrue(pkcs11uri.UnknownQueryAttributes != null && pkcs11uri.UnknownQueryAttributes.Count == 1);
            Assert.IsTrue(pkcs11uri.UnknownQueryAttributes[_pk11VendorAttrNameChars].Count == 1);
            Assert.IsTrue(pkcs11uri.UnknownQueryAttributes[_pk11VendorAttrNameChars][0] == _pk11QueryChars + _unicodeChar);
        }
        public void LibraryVersionWithTwoDots()
        {
            string uri = @"pkcs11:library-version=1.2.3";

            try
            {
                // Build URI
                Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.LibraryVersion = "1.2.3";
                Assert.Fail("Exception expected but not thrown");
            }
            catch (Exception ex)
            {
                Assert.IsTrue(ex is Pkcs11UriException);
            }

            try
            {
                // Parse URI
                Pkcs11Uri pkcs11uri = new Pkcs11Uri(uri);
                Assert.Fail("Exception expected but not thrown");
            }
            catch (Exception ex)
            {
                Assert.IsTrue(ex is Pkcs11UriException);
            }
        }
        public void _06_GetMatchingSlotList()
        {
            if (Platform.UnmanagedLongSize != 4 || Platform.StructPackingSize != 1)
                Assert.Inconclusive("Test cannot be executed on this platform");

            using (Pkcs11 pkcs11 = new Pkcs11(Settings.Pkcs11LibraryPath, Settings.UseOsLocking))
            {
                // Get all slots
                List<Slot> allSlots = pkcs11.GetSlotList(true);
                Assert.IsTrue(allSlots != null && allSlots.Count > 0);

                // Empty URI
                Pkcs11Uri pkcs11uri = new Pkcs11Uri(@"pkcs11:");
                List<Slot> matchedSlots = Pkcs11UriUtils.GetMatchingSlotList(pkcs11uri, pkcs11, true);
                Assert.IsTrue(matchedSlots.Count == allSlots.Count);

                // Unknown path attribute in URI
                pkcs11uri = new Pkcs11Uri(@"pkcs11:vendor=foobar");
                matchedSlots = Pkcs11UriUtils.GetMatchingSlotList(pkcs11uri, pkcs11, true);
                Assert.IsTrue(matchedSlots.Count == 0);

                // All attributes matching one slot
                LibraryInfo libraryInfo = pkcs11.GetInfo();
                SlotInfo slotInfo = allSlots[0].GetSlotInfo();
                TokenInfo tokenInfo = allSlots[0].GetTokenInfo();

                Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.LibraryManufacturer = libraryInfo.ManufacturerId;
                pkcs11UriBuilder.LibraryDescription = libraryInfo.LibraryDescription;
                pkcs11UriBuilder.LibraryVersion = libraryInfo.LibraryVersion;
                pkcs11UriBuilder.SlotManufacturer = slotInfo.ManufacturerId;
                pkcs11UriBuilder.SlotDescription = slotInfo.SlotDescription;
                pkcs11UriBuilder.SlotId = slotInfo.SlotId;
                pkcs11UriBuilder.Token = tokenInfo.Label;
                pkcs11UriBuilder.Manufacturer = tokenInfo.ManufacturerId;
                pkcs11UriBuilder.Serial = tokenInfo.SerialNumber;
                pkcs11UriBuilder.Model = tokenInfo.Model;
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();

                matchedSlots = Pkcs11UriUtils.GetMatchingSlotList(pkcs11uri, pkcs11, true);
                Assert.IsTrue(matchedSlots.Count == 1);

                // One attribute nonmatching
                pkcs11UriBuilder.Serial = "foobar";
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                matchedSlots = Pkcs11UriUtils.GetMatchingSlotList(pkcs11uri, pkcs11, true);
                Assert.IsTrue(matchedSlots.Count == 0);
            }
        }
        public void SlotIdWithValidValue()
        {
            string uri = @"pkcs11:slot-id=18446744073709551615";

            // Build URI without length checking
            Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder(false);
            pkcs11UriBuilder.SlotId = 18446744073709551615;
            Assert.IsTrue(uri == pkcs11UriBuilder.ToString());

            // Parse URI without length checking
            Pkcs11Uri pkcs11uri = new Pkcs11Uri(uri, false);
            Assert.IsTrue(pkcs11uri.DefinesLibrary == false);
            Assert.IsTrue(pkcs11uri.DefinesSlot == true);
            Assert.IsTrue(pkcs11uri.DefinesToken == false);
            Assert.IsTrue(pkcs11uri.DefinesObject == false);
            Assert.IsTrue(pkcs11uri.SlotId == 18446744073709551615);

            // Build URI with length checking
            pkcs11UriBuilder = new Pkcs11UriBuilder(true);
            pkcs11UriBuilder.SlotId = 18446744073709551615;
            Assert.IsTrue(uri == pkcs11UriBuilder.ToString());

            // Parse URI with length checking
            pkcs11uri = new Pkcs11Uri(uri, true);
            Assert.IsTrue(pkcs11uri.DefinesLibrary == false);
            Assert.IsTrue(pkcs11uri.DefinesSlot == true);
            Assert.IsTrue(pkcs11uri.DefinesToken == false);
            Assert.IsTrue(pkcs11uri.DefinesObject == false);
            Assert.IsTrue(pkcs11uri.SlotId == 18446744073709551615);
        }
        public void VendorSpecificPathAttributeWithIncompleteName()
        {
            string uri = @"pkcs11:=" + _pk11PathChars + _pctEncodedUnicodeChar;

            try
            {
                // Build URI
                Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.UnknownPathAttributes = new Dictionary<string, string>();
                pkcs11UriBuilder.UnknownPathAttributes.Add(string.Empty, _pk11PathChars + _unicodeChar);
                Assert.IsTrue(uri == pkcs11UriBuilder.ToString());
                Assert.Fail("Exception expected but not thrown");
            }
            catch (Exception ex)
            {
                Assert.IsTrue(ex is Pkcs11UriException);
            }

            try
            {
                // Parse URI
                Pkcs11Uri pkcs11uri = new Pkcs11Uri(uri);
                Assert.Fail("Exception expected but not thrown");
            }
            catch (Exception ex)
            {
                Assert.IsTrue(ex is Pkcs11UriException);
            }
        }
        public void LibraryManufacturerWithValidValue()
        {
            string uri = @"pkcs11:library-manufacturer=" + _pk11PathChars + _pctEncodedUnicodeChar;

            // Build URI without length checking
            Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder(false);
            pkcs11UriBuilder.LibraryManufacturer = _pk11PathChars + _unicodeChar;
            Assert.IsTrue(uri == pkcs11UriBuilder.ToString());

            // Parse URI without length checking
            Pkcs11Uri pkcs11uri = new Pkcs11Uri(uri, false);
            Assert.IsTrue(pkcs11uri.DefinesLibrary == true);
            Assert.IsTrue(pkcs11uri.DefinesSlot == false);
            Assert.IsTrue(pkcs11uri.DefinesToken == false);
            Assert.IsTrue(pkcs11uri.DefinesObject == false);
            Assert.IsTrue(pkcs11uri.LibraryManufacturer == _pk11PathChars + _unicodeChar);

            try
            {
                // Build URI with length checking
                pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.LibraryManufacturer = _pk11PathChars + _unicodeChar;
                Assert.Fail("Exception expected but not thrown");
            }
            catch (Exception ex)
            {
                Assert.IsTrue(ex is ArgumentOutOfRangeException);
            }

            try
            {
                // Parse URI with length checking
                pkcs11uri = new Pkcs11Uri(uri);
                Assert.Fail("Exception expected but not thrown");
            }
            catch (Exception ex)
            {
                Assert.IsTrue(ex is Pkcs11UriException);
            }
        }
        public void IdWithValidValue()
        {
            string uri = @"pkcs11:id=" + _pk11PathChars + _pctEncodedUnicodeChar;

            // Note: Builder cannot be used to produce URI like this one

            // Parse URI
            Pkcs11Uri pkcs11uri = new Pkcs11Uri(uri);
            Assert.IsTrue(pkcs11uri.DefinesLibrary == false);
            Assert.IsTrue(pkcs11uri.DefinesSlot == false);
            Assert.IsTrue(pkcs11uri.DefinesToken == false);
            Assert.IsTrue(pkcs11uri.DefinesObject == true);
            Assert.IsTrue(Helpers.ByteArraysMatch(pkcs11uri.Id, ConvertUtils.Utf8StringToBytes(_pk11PathChars + _unicodeChar)));

            uri = @"pkcs11:id=%41%42%43%44%45%46%47%48%49%4A%4B%4C%4D%4E%4F%50%51%52%53%54%55%56%57%58%59%5A%61%62%63%64%65%66%67%68%69%6A%6B%6C%6D%6E%6F%70%71%72%73%74%75%76%77%78%79%7A%30%31%32%33%34%35%36%37%38%39%2D%2E%5F%7E%3A%5B%5D%40%21%24%27%28%29%2A%2B%2C%3D%26%C3%A4";

            // Build URI without length checking
            Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder(false);
            pkcs11UriBuilder.Id = ConvertUtils.Utf8StringToBytes(_pk11PathChars + _unicodeChar);
            Assert.IsTrue(uri == pkcs11UriBuilder.ToString());

            // Parse URI without length checking
            pkcs11uri = new Pkcs11Uri(uri, false);
            Assert.IsTrue(pkcs11uri.DefinesLibrary == false);
            Assert.IsTrue(pkcs11uri.DefinesSlot == false);
            Assert.IsTrue(pkcs11uri.DefinesToken == false);
            Assert.IsTrue(pkcs11uri.DefinesObject == true);
            Assert.IsTrue(Helpers.ByteArraysMatch(pkcs11uri.Id, ConvertUtils.Utf8StringToBytes(_pk11PathChars + _unicodeChar)));

            // Build URI with length checking
            pkcs11UriBuilder = new Pkcs11UriBuilder();
            pkcs11UriBuilder.Id = ConvertUtils.Utf8StringToBytes(_pk11PathChars + _unicodeChar);
            Assert.IsTrue(uri == pkcs11UriBuilder.ToString());

            // Parse URI with length checking
            pkcs11uri = new Pkcs11Uri(uri);
            Assert.IsTrue(pkcs11uri.DefinesLibrary == false);
            Assert.IsTrue(pkcs11uri.DefinesSlot == false);
            Assert.IsTrue(pkcs11uri.DefinesToken == false);
            Assert.IsTrue(pkcs11uri.DefinesObject == true);
            Assert.IsTrue(Helpers.ByteArraysMatch(pkcs11uri.Id, ConvertUtils.Utf8StringToBytes(_pk11PathChars + _unicodeChar)));
        }
        public void IdWithoutValue()
        {
            string uri = @"pkcs11:id=";

            // Build URI
            Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
            pkcs11UriBuilder.Id = new byte[0];
            Assert.IsTrue(uri == pkcs11UriBuilder.ToString());

            // Parse URI
            Pkcs11Uri pkcs11uri = new Pkcs11Uri(uri);
            Assert.IsTrue(pkcs11uri.DefinesLibrary == false);
            Assert.IsTrue(pkcs11uri.DefinesSlot == false);
            Assert.IsTrue(pkcs11uri.DefinesToken == false);
            Assert.IsTrue(pkcs11uri.DefinesObject == true);
            Assert.IsTrue(pkcs11uri.Id != null && pkcs11uri.Id.Length == 0);
        }
        public void UnknownType()
        {
            string uri = @"pkcs11:type=otp";

            try
            {
                // Build URI
                Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.Type = CKO.CKO_OTP_KEY;
                Assert.Fail("Exception expected but not thrown");
            }
            catch (Exception ex)
            {
                Assert.IsTrue(ex is Pkcs11UriException);
            }

            try
            {
                // Parse URI
                Pkcs11Uri pkcs11uri = new Pkcs11Uri(uri);
                Assert.Fail("Exception expected but not thrown");
            }
            catch (Exception ex)
            {
                Assert.IsTrue(ex is Pkcs11UriException);
            }
        }
        public void KnownTypes()
        {
            string[] uris = new string[]
            {
                @"pkcs11:type=public",
                @"pkcs11:type=private",
                @"pkcs11:type=cert",
                @"pkcs11:type=secret-key",
                @"pkcs11:type=data"
            };

            foreach (string uri in uris)
            {
                // Parse URI
                Pkcs11Uri pkcs11uri = new Pkcs11Uri(uri);
                Assert.IsTrue(pkcs11uri.DefinesLibrary == false);
                Assert.IsTrue(pkcs11uri.DefinesSlot == false);
                Assert.IsTrue(pkcs11uri.DefinesToken == false);
                Assert.IsTrue(pkcs11uri.DefinesObject == true);
                Assert.IsTrue(pkcs11uri.Type != null);

                // Build URI
                Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.Type = pkcs11uri.Type;
                Assert.IsTrue(uri == pkcs11UriBuilder.ToString());
            }
        }
        public void ObjectDescriptionWithValidValue()
        {
            string uri = @"pkcs11:object=" + _pk11PathChars + _pctEncodedUnicodeChar;

            // Build URI without length checking
            Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder(false);
            pkcs11UriBuilder.Object = _pk11PathChars + _unicodeChar;
            Assert.IsTrue(uri == pkcs11UriBuilder.ToString());

            // Parse URI without length checking
            Pkcs11Uri pkcs11uri = new Pkcs11Uri(uri, false);
            Assert.IsTrue(pkcs11uri.DefinesLibrary == false);
            Assert.IsTrue(pkcs11uri.DefinesSlot == false);
            Assert.IsTrue(pkcs11uri.DefinesToken == false);
            Assert.IsTrue(pkcs11uri.DefinesObject == true);
            Assert.IsTrue(pkcs11uri.Object == _pk11PathChars + _unicodeChar);

            // Build URI with length checking
            pkcs11UriBuilder = new Pkcs11UriBuilder();
            pkcs11UriBuilder.Object = _pk11PathChars + _unicodeChar;
            Assert.IsTrue(uri == pkcs11UriBuilder.ToString());

            // Parse URI with length checking
            pkcs11uri = new Pkcs11Uri(uri);
            Assert.IsTrue(pkcs11uri.DefinesLibrary == false);
            Assert.IsTrue(pkcs11uri.DefinesSlot == false);
            Assert.IsTrue(pkcs11uri.DefinesToken == false);
            Assert.IsTrue(pkcs11uri.DefinesObject == true);
            Assert.IsTrue(pkcs11uri.Object == _pk11PathChars + _unicodeChar);
        }
        public void VendorSpecificQueryAttributeWithMultipleValues()
        {
            string uri = @"pkcs11:?vendor=foo&vendor=bar";

            // Build URI
            Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
            pkcs11UriBuilder.UnknownQueryAttributes = new Dictionary<string, List<string>>();
            pkcs11UriBuilder.UnknownQueryAttributes.Add("vendor", new List<string> { "foo", "bar" });
            Assert.IsTrue(uri == pkcs11UriBuilder.ToString());

            // Parse URI
            Pkcs11Uri pkcs11uri = new Pkcs11Uri(uri);
            Assert.IsTrue(pkcs11uri.DefinesLibrary == false);
            Assert.IsTrue(pkcs11uri.DefinesToken == false);
            Assert.IsTrue(pkcs11uri.DefinesObject == false);
            Assert.IsTrue(pkcs11uri.UnknownQueryAttributes != null && pkcs11uri.UnknownQueryAttributes.Count == 1);
            Assert.IsTrue(pkcs11uri.UnknownQueryAttributes["vendor"].Count == 2);
            Assert.IsTrue(pkcs11uri.UnknownQueryAttributes["vendor"][0] == "foo");
            Assert.IsTrue(pkcs11uri.UnknownQueryAttributes["vendor"][1] == "bar");
        }
        public void UriWithoutPathAttributes()
        {
            string uri = @"pkcs11:";
            uri += @"?";
            uri += @"module-path=foo&module-name=bar&";
            uri += @"pin-value=foo&pin-source=bar";

            // Build URI
            Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
            pkcs11UriBuilder.ModulePath = "foo";
            pkcs11UriBuilder.ModuleName = "bar";
            pkcs11UriBuilder.PinValue = "foo";
            pkcs11UriBuilder.PinSource = "bar";
            Assert.IsTrue(uri == pkcs11UriBuilder.ToString());

            // Parse URI
            Pkcs11Uri pkcs11uri = new Pkcs11Uri(uri);
            Assert.IsTrue(pkcs11uri.DefinesLibrary == false);
            Assert.IsTrue(pkcs11uri.DefinesToken == false);
            Assert.IsTrue(pkcs11uri.DefinesObject == false);
            Assert.IsTrue(pkcs11uri.UnknownPathAttributes == null);
            Assert.IsTrue(pkcs11uri.UnknownQueryAttributes == null);
            Assert.IsTrue(pkcs11uri.LibraryManufacturer == null);
            Assert.IsTrue(pkcs11uri.LibraryDescription == null);
            Assert.IsTrue(pkcs11uri.LibraryVersion == null);
            Assert.IsTrue(pkcs11uri.SlotManufacturer == null);
            Assert.IsTrue(pkcs11uri.SlotDescription == null);
            Assert.IsTrue(pkcs11uri.SlotId == null);
            Assert.IsTrue(pkcs11uri.Manufacturer == null);
            Assert.IsTrue(pkcs11uri.Model == null);
            Assert.IsTrue(pkcs11uri.Serial == null);
            Assert.IsTrue(pkcs11uri.Token == null);
            Assert.IsTrue(pkcs11uri.Type == null);
            Assert.IsTrue(pkcs11uri.Object == null);
            Assert.IsTrue(Helpers.ByteArraysMatch(pkcs11uri.Id, null));
            Assert.IsTrue(pkcs11uri.ModulePath == "foo");
            Assert.IsTrue(pkcs11uri.ModuleName == "bar");
            Assert.IsTrue(pkcs11uri.PinValue == "foo");
            Assert.IsTrue(pkcs11uri.PinSource == "bar");
        }
        public void ModelWithoutValue()
        {
            string uri = @"pkcs11:model=";

            // Build URI
            Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
            pkcs11UriBuilder.Model = string.Empty;
            Assert.IsTrue(uri == pkcs11UriBuilder.ToString());

            // Parse URI
            Pkcs11Uri pkcs11uri = new Pkcs11Uri(uri);
            Assert.IsTrue(pkcs11uri.DefinesLibrary == false);
            Assert.IsTrue(pkcs11uri.DefinesSlot == false);
            Assert.IsTrue(pkcs11uri.DefinesToken == true);
            Assert.IsTrue(pkcs11uri.DefinesObject == false);
            Assert.IsTrue(pkcs11uri.Model == string.Empty);
        }
        public void _03_SlotInfoMatches()
        {
            if (Platform.UnmanagedLongSize != 4 || Platform.StructPackingSize != 1)
                Assert.Inconclusive("Test cannot be executed on this platform");

            using (Pkcs11 pkcs11 = new Pkcs11(Settings.Pkcs11LibraryPath, Settings.UseOsLocking))
            {
                List<Slot> slots = pkcs11.GetSlotList(true);
                Assert.IsTrue(slots != null && slots.Count > 0);
                SlotInfo slotInfo = slots[0].GetSlotInfo();

                // Empty URI
                Pkcs11Uri pkcs11uri = new Pkcs11Uri(@"pkcs11:");
                Assert.IsTrue(Pkcs11UriUtils.Matches(pkcs11uri, slotInfo));

                // Unknown path attribute in URI
                pkcs11uri = new Pkcs11Uri(@"pkcs11:vendor=foobar");
                Assert.IsFalse(Pkcs11UriUtils.Matches(pkcs11uri, slotInfo));

                // All attributes matching
                Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.SlotManufacturer = slotInfo.ManufacturerId;
                pkcs11UriBuilder.SlotDescription = slotInfo.SlotDescription;
                pkcs11UriBuilder.SlotId = slotInfo.SlotId;
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                Assert.IsTrue(Pkcs11UriUtils.Matches(pkcs11uri, slotInfo));

                // Manufacturer nonmatching
                pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.SlotManufacturer = "foobar";
                pkcs11UriBuilder.SlotDescription = slotInfo.SlotDescription;
                pkcs11UriBuilder.SlotId = slotInfo.SlotId;
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                Assert.IsFalse(Pkcs11UriUtils.Matches(pkcs11uri, slotInfo));

                // Description nonmatching
                pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.SlotManufacturer = slotInfo.ManufacturerId;
                pkcs11UriBuilder.SlotDescription = "foobar";
                pkcs11UriBuilder.SlotId = slotInfo.SlotId;
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                Assert.IsFalse(Pkcs11UriUtils.Matches(pkcs11uri, slotInfo));

                // Slot id nonmatching
                pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.SlotManufacturer = slotInfo.ManufacturerId;
                pkcs11UriBuilder.SlotDescription = slotInfo.SlotDescription;
                pkcs11UriBuilder.SlotId = slotInfo.SlotId + 1;
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                Assert.IsFalse(Pkcs11UriUtils.Matches(pkcs11uri, slotInfo));
            }
        }
        public void _04_TokenInfoMatches()
        {
            if (Platform.UnmanagedLongSize != 4 || Platform.StructPackingSize != 1)
                Assert.Inconclusive("Test cannot be executed on this platform");

            using (Pkcs11 pkcs11 = new Pkcs11(Settings.Pkcs11LibraryPath, Settings.UseOsLocking))
            {
                List<Slot> slots = pkcs11.GetSlotList(true);
                Assert.IsTrue(slots != null && slots.Count > 0);
                TokenInfo tokenInfo = slots[0].GetTokenInfo();

                // Empty URI
                Pkcs11Uri pkcs11uri = new Pkcs11Uri(@"pkcs11:");
                Assert.IsTrue(Pkcs11UriUtils.Matches(pkcs11uri, tokenInfo));

                // Unknown path attribute in URI
                pkcs11uri = new Pkcs11Uri(@"pkcs11:vendor=foobar");
                Assert.IsFalse(Pkcs11UriUtils.Matches(pkcs11uri, tokenInfo));

                // All attributes matching
                Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.Token = tokenInfo.Label;
                pkcs11UriBuilder.Manufacturer = tokenInfo.ManufacturerId;
                pkcs11UriBuilder.Serial = tokenInfo.SerialNumber;
                pkcs11UriBuilder.Model = tokenInfo.Model;
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                Assert.IsTrue(Pkcs11UriUtils.Matches(pkcs11uri, tokenInfo));

                // Token nonmatching
                pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.Token = "foobar";
                pkcs11UriBuilder.Manufacturer = tokenInfo.ManufacturerId;
                pkcs11UriBuilder.Serial = tokenInfo.SerialNumber;
                pkcs11UriBuilder.Model = tokenInfo.Model;
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                Assert.IsFalse(Pkcs11UriUtils.Matches(pkcs11uri, tokenInfo));

                // Manufacturer nonmatching
                pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.Token = tokenInfo.Label;
                pkcs11UriBuilder.Manufacturer = "foobar";
                pkcs11UriBuilder.Serial = tokenInfo.SerialNumber;
                pkcs11UriBuilder.Model = tokenInfo.Model;
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                Assert.IsFalse(Pkcs11UriUtils.Matches(pkcs11uri, tokenInfo));

                // Serial nonmatching
                pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.Token = tokenInfo.Label;
                pkcs11UriBuilder.Manufacturer = tokenInfo.ManufacturerId;
                pkcs11UriBuilder.Serial = "foobar";
                pkcs11UriBuilder.Model = tokenInfo.Model;
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                Assert.IsFalse(Pkcs11UriUtils.Matches(pkcs11uri, tokenInfo));

                // Model nonmatching
                pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.Token = tokenInfo.Label;
                pkcs11UriBuilder.Manufacturer = tokenInfo.ManufacturerId;
                pkcs11UriBuilder.Serial = tokenInfo.SerialNumber;
                pkcs11UriBuilder.Model = "foobar";
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                Assert.IsFalse(Pkcs11UriUtils.Matches(pkcs11uri, tokenInfo));
            }
        }
        public void GetMatchingSlotListLLA4()
        {
            // Skip test on incompatible platforms
            if (UnmanagedLong.Size != 4)
                return;

            using (LLA4.Pkcs11 pkcs11 = new LLA4.Pkcs11(Settings.Pkcs11LibraryPath, false))
            {
                CKR rv = pkcs11.C_Initialize(null);
                Assert.IsTrue(rv == CKR.CKR_OK);

                // Get all slots
                uint allSlotsCount = 0;
                rv = pkcs11.C_GetSlotList(true, null, ref allSlotsCount);
                Assert.IsTrue(rv == CKR.CKR_OK);
                Assert.IsTrue(allSlotsCount > 0);
                uint[] allSlots = new uint[allSlotsCount];
                rv = pkcs11.C_GetSlotList(true, allSlots, ref allSlotsCount);
                Assert.IsTrue(rv == CKR.CKR_OK);

                // Empty URI
                Pkcs11Uri pkcs11uri = new Pkcs11Uri(@"pkcs11:");
                uint[] matchedSlots = null;
                rv = Pkcs11UriUtils.GetMatchingSlotList(pkcs11uri, pkcs11, true, out matchedSlots);
                Assert.IsTrue(rv == CKR.CKR_OK);
                Assert.IsTrue(matchedSlots.Length == allSlots.Length);

                // Unknown path attribute in URI
                pkcs11uri = new Pkcs11Uri(@"pkcs11:vendor=foobar");
                rv = Pkcs11UriUtils.GetMatchingSlotList(pkcs11uri, pkcs11, true, out matchedSlots);
                Assert.IsTrue(rv == CKR.CKR_OK);
                Assert.IsTrue(matchedSlots.Length == 0);

                // All attributes matching one slot
                LLA4.CK_INFO libraryInfo = new LLA4.CK_INFO();
                rv = pkcs11.C_GetInfo(ref libraryInfo);
                Assert.IsTrue(rv == CKR.CKR_OK);
                LLA4.CK_SLOT_INFO slotInfo = new LLA4.CK_SLOT_INFO();
                rv = pkcs11.C_GetSlotInfo(allSlots[0], ref slotInfo);
                Assert.IsTrue(rv == CKR.CKR_OK);
                LLA4.CK_TOKEN_INFO tokenInfo = new LLA4.CK_TOKEN_INFO();
                rv = pkcs11.C_GetTokenInfo(allSlots[0], ref tokenInfo);
                Assert.IsTrue(rv == CKR.CKR_OK);

                Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.LibraryManufacturer = ConvertUtils.BytesToUtf8String(libraryInfo.ManufacturerId, true);
                pkcs11UriBuilder.LibraryDescription = ConvertUtils.BytesToUtf8String(libraryInfo.LibraryDescription, true);
                pkcs11UriBuilder.LibraryVersion = ConvertUtils.CkVersionToString(libraryInfo.LibraryVersion);
                pkcs11UriBuilder.SlotManufacturer = ConvertUtils.BytesToUtf8String(slotInfo.ManufacturerId, true);
                pkcs11UriBuilder.SlotDescription = ConvertUtils.BytesToUtf8String(slotInfo.SlotDescription, true);
                pkcs11UriBuilder.SlotId = allSlots[0];
                pkcs11UriBuilder.Token = ConvertUtils.BytesToUtf8String(tokenInfo.Label, true);
                pkcs11UriBuilder.Manufacturer = ConvertUtils.BytesToUtf8String(tokenInfo.ManufacturerId, true);
                pkcs11UriBuilder.Serial = ConvertUtils.BytesToUtf8String(tokenInfo.SerialNumber, true);
                pkcs11UriBuilder.Model = ConvertUtils.BytesToUtf8String(tokenInfo.Model, true);
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();

                rv = Pkcs11UriUtils.GetMatchingSlotList(pkcs11uri, pkcs11, true, out matchedSlots);
                Assert.IsTrue(rv == CKR.CKR_OK);
                Assert.IsTrue(matchedSlots.Length == 1);

                // One attribute nonmatching
                pkcs11UriBuilder.Serial = "foobar";
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                rv = Pkcs11UriUtils.GetMatchingSlotList(pkcs11uri, pkcs11, true, out matchedSlots);
                Assert.IsTrue(rv == CKR.CKR_OK);
                Assert.IsTrue(matchedSlots.Length == 0);

                rv = pkcs11.C_Finalize(IntPtr.Zero);
                Assert.IsTrue(rv == CKR.CKR_OK);
            }
        }
        public void PinSourceWithoutValue()
        {
            string uri = @"pkcs11:?pin-source=";
            
            // Build URI
            Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
            pkcs11UriBuilder.PinSource = string.Empty;
            Assert.IsTrue(uri == pkcs11UriBuilder.ToString());

            // Parse URI
            Pkcs11Uri pkcs11uri = new Pkcs11Uri(uri);
            Assert.IsTrue(pkcs11uri.DefinesLibrary == false);
            Assert.IsTrue(pkcs11uri.DefinesSlot == false);
            Assert.IsTrue(pkcs11uri.DefinesToken == false);
            Assert.IsTrue(pkcs11uri.DefinesObject == false);
            Assert.IsTrue(pkcs11uri.PinSource == string.Empty);
        }
        public void SlotManufacturerWithoutValue()
        {
            string uri = @"pkcs11:slot-manufacturer=";

            // Build URI
            Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
            pkcs11UriBuilder.SlotManufacturer = string.Empty;
            Assert.IsTrue(uri == pkcs11UriBuilder.ToString());

            // Parse URI
            Pkcs11Uri pkcs11uri = new Pkcs11Uri(uri);
            Assert.IsTrue(pkcs11uri.DefinesLibrary == false);
            Assert.IsTrue(pkcs11uri.DefinesSlot == true);
            Assert.IsTrue(pkcs11uri.DefinesToken == false);
            Assert.IsTrue(pkcs11uri.DefinesObject == false);
            Assert.IsTrue(pkcs11uri.SlotManufacturer == string.Empty);
        }
        public void GetMatchingSlotListHLA4()
        {
            // Skip test on incompatible platforms
            if (UnmanagedLong.Size != 4)
                return;

            using (HLA4.Pkcs11 pkcs11 = new HLA4.Pkcs11(Settings.Pkcs11LibraryPath, false))
            {
                // Get all slots
                List<HLA4.Slot> allSlots = pkcs11.GetSlotList(true);
                Assert.IsTrue(allSlots != null && allSlots.Count > 0);

                // Empty URI
                Pkcs11Uri pkcs11uri = new Pkcs11Uri(@"pkcs11:");
                List<HLA4.Slot> matchedSlots = Pkcs11UriUtils.GetMatchingSlotList(pkcs11uri, pkcs11, true);
                Assert.IsTrue(matchedSlots.Count == allSlots.Count);

                // Unknown path attribute in URI
                pkcs11uri = new Pkcs11Uri(@"pkcs11:vendor=foobar");
                matchedSlots = Pkcs11UriUtils.GetMatchingSlotList(pkcs11uri, pkcs11, true);
                Assert.IsTrue(matchedSlots.Count == 0);

                // All attributes matching one slot
                HLA4.LibraryInfo libraryInfo = pkcs11.GetInfo();
                HLA4.SlotInfo slotInfo = allSlots[0].GetSlotInfo();
                HLA4.TokenInfo tokenInfo = allSlots[0].GetTokenInfo();

                Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.LibraryManufacturer = libraryInfo.ManufacturerId;
                pkcs11UriBuilder.LibraryDescription = libraryInfo.LibraryDescription;
                pkcs11UriBuilder.LibraryVersion = libraryInfo.LibraryVersion;
                pkcs11UriBuilder.SlotManufacturer = slotInfo.ManufacturerId;
                pkcs11UriBuilder.SlotDescription = slotInfo.SlotDescription;
                pkcs11UriBuilder.SlotId = slotInfo.SlotId;
                pkcs11UriBuilder.Token = tokenInfo.Label;
                pkcs11UriBuilder.Manufacturer = tokenInfo.ManufacturerId;
                pkcs11UriBuilder.Serial = tokenInfo.SerialNumber;
                pkcs11UriBuilder.Model = tokenInfo.Model;
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();

                matchedSlots = Pkcs11UriUtils.GetMatchingSlotList(pkcs11uri, pkcs11, true);
                Assert.IsTrue(matchedSlots.Count == 1);

                // One attribute nonmatching
                pkcs11UriBuilder.Serial = "foobar";
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                matchedSlots = Pkcs11UriUtils.GetMatchingSlotList(pkcs11uri, pkcs11, true);
                Assert.IsTrue(matchedSlots.Count == 0);
            }
        }
        public void ModulePathWithValidValue()
        {
            string uri = @"pkcs11:?module-path=" + _pk11QueryChars + _pctEncodedUnicodeChar;

            // Build URI
            Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
            pkcs11UriBuilder.ModulePath = _pk11QueryChars + _unicodeChar;
            Assert.IsTrue(uri == pkcs11UriBuilder.ToString());

            // Parse URI
            Pkcs11Uri pkcs11uri = new Pkcs11Uri(uri);
            Assert.IsTrue(pkcs11uri.DefinesLibrary == false);
            Assert.IsTrue(pkcs11uri.DefinesSlot == false);
            Assert.IsTrue(pkcs11uri.DefinesToken == false);
            Assert.IsTrue(pkcs11uri.DefinesObject == false);
            Assert.IsTrue(pkcs11uri.ModulePath == _pk11QueryChars + _unicodeChar);
        }
        public void SlotInfoMatchesHLA8()
        {
            // Skip test on incompatible platforms
            if (UnmanagedLong.Size != 8)
                return;

            using (HLA8.Pkcs11 pkcs11 = new HLA8.Pkcs11(Settings.Pkcs11LibraryPath, false))
            {
                List<HLA8.Slot> slots = pkcs11.GetSlotList(true);
                Assert.IsTrue(slots != null && slots.Count > 0);
                HLA8.SlotInfo slotInfo = slots[0].GetSlotInfo();

                // Empty URI
                Pkcs11Uri pkcs11uri = new Pkcs11Uri(@"pkcs11:");
                Assert.IsTrue(Pkcs11UriUtils.Matches(pkcs11uri, slotInfo));

                // Unknown path attribute in URI
                pkcs11uri = new Pkcs11Uri(@"pkcs11:vendor=foobar");
                Assert.IsFalse(Pkcs11UriUtils.Matches(pkcs11uri, slotInfo));

                // All attributes matching
                Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.SlotManufacturer = slotInfo.ManufacturerId;
                pkcs11UriBuilder.SlotDescription = slotInfo.SlotDescription;
                pkcs11UriBuilder.SlotId = slotInfo.SlotId;
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                Assert.IsTrue(Pkcs11UriUtils.Matches(pkcs11uri, slotInfo));

                // Manufacturer nonmatching
                pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.SlotManufacturer = "foobar";
                pkcs11UriBuilder.SlotDescription = slotInfo.SlotDescription;
                pkcs11UriBuilder.SlotId = slotInfo.SlotId;
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                Assert.IsFalse(Pkcs11UriUtils.Matches(pkcs11uri, slotInfo));

                // Description nonmatching
                pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.SlotManufacturer = slotInfo.ManufacturerId;
                pkcs11UriBuilder.SlotDescription = "foobar";
                pkcs11UriBuilder.SlotId = slotInfo.SlotId;
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                Assert.IsFalse(Pkcs11UriUtils.Matches(pkcs11uri, slotInfo));

                // Slot id nonmatching
                pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.SlotManufacturer = slotInfo.ManufacturerId;
                pkcs11UriBuilder.SlotDescription = slotInfo.SlotDescription;
                pkcs11UriBuilder.SlotId = slotInfo.SlotId + 1;
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                Assert.IsFalse(Pkcs11UriUtils.Matches(pkcs11uri, slotInfo));
            }
        }
        public void VendorSpecificQueryAttributeWithInvalidName()
        {
            string uri = @"pkcs11:?.=" + _pk11QueryChars + _pctEncodedUnicodeChar;

            try
            {
                // Build URI
                Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.UnknownQueryAttributes = new Dictionary<string, List<string>>();
                pkcs11UriBuilder.UnknownQueryAttributes.Add(".", new List<string> { _pk11QueryChars + _unicodeChar });
                Assert.IsTrue(uri == pkcs11UriBuilder.ToString());
                Assert.Fail("Exception expected but not thrown");
            }
            catch (Exception ex)
            {
                Assert.IsTrue(ex is Pkcs11UriException);
            }

            try
            {
                // Parse URI
                Pkcs11Uri pkcs11uri = new Pkcs11Uri(uri);
                Assert.Fail("Exception expected but not thrown");
            }
            catch (Exception ex)
            {
                Assert.IsTrue(ex is Pkcs11UriException);
            }
        }
        public void TokenInfoMatchesHLA4()
        {
            // Skip test on incompatible platforms
            if (UnmanagedLong.Size != 4)
                return;

            using (HLA4.Pkcs11 pkcs11 = new HLA4.Pkcs11(Settings.Pkcs11LibraryPath, false))
            {
                List<HLA4.Slot> slots = pkcs11.GetSlotList(true);
                Assert.IsTrue(slots != null && slots.Count > 0);
                HLA4.TokenInfo tokenInfo = slots[0].GetTokenInfo();

                // Empty URI
                Pkcs11Uri pkcs11uri = new Pkcs11Uri(@"pkcs11:");
                Assert.IsTrue(Pkcs11UriUtils.Matches(pkcs11uri, tokenInfo));

                // Unknown path attribute in URI
                pkcs11uri = new Pkcs11Uri(@"pkcs11:vendor=foobar");
                Assert.IsFalse(Pkcs11UriUtils.Matches(pkcs11uri, tokenInfo));

                // All attributes matching
                Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.Token = tokenInfo.Label;
                pkcs11UriBuilder.Manufacturer = tokenInfo.ManufacturerId;
                pkcs11UriBuilder.Serial = tokenInfo.SerialNumber;
                pkcs11UriBuilder.Model = tokenInfo.Model;
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                Assert.IsTrue(Pkcs11UriUtils.Matches(pkcs11uri, tokenInfo));

                // Token nonmatching
                pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.Token = "foobar";
                pkcs11UriBuilder.Manufacturer = tokenInfo.ManufacturerId;
                pkcs11UriBuilder.Serial = tokenInfo.SerialNumber;
                pkcs11UriBuilder.Model = tokenInfo.Model;
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                Assert.IsFalse(Pkcs11UriUtils.Matches(pkcs11uri, tokenInfo));

                // Manufacturer nonmatching
                pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.Token = tokenInfo.Label;
                pkcs11UriBuilder.Manufacturer = "foobar";
                pkcs11UriBuilder.Serial = tokenInfo.SerialNumber;
                pkcs11UriBuilder.Model = tokenInfo.Model;
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                Assert.IsFalse(Pkcs11UriUtils.Matches(pkcs11uri, tokenInfo));

                // Serial nonmatching
                pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.Token = tokenInfo.Label;
                pkcs11UriBuilder.Manufacturer = tokenInfo.ManufacturerId;
                pkcs11UriBuilder.Serial = "foobar";
                pkcs11UriBuilder.Model = tokenInfo.Model;
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                Assert.IsFalse(Pkcs11UriUtils.Matches(pkcs11uri, tokenInfo));

                // Model nonmatching
                pkcs11UriBuilder = new Pkcs11UriBuilder();
                pkcs11UriBuilder.Token = tokenInfo.Label;
                pkcs11UriBuilder.Manufacturer = tokenInfo.ManufacturerId;
                pkcs11UriBuilder.Serial = tokenInfo.SerialNumber;
                pkcs11UriBuilder.Model = "foobar";
                pkcs11uri = pkcs11UriBuilder.ToPkcs11Uri();
                Assert.IsFalse(Pkcs11UriUtils.Matches(pkcs11uri, tokenInfo));
            }
        }
        public void UriWithoutQueryAttributes()
        {
            string uri = @"pkcs11:";
            uri += @"library-manufacturer=foo;library-description=bar;library-version=1;";
            uri += @"slot-manufacturer=foo;slot-description=bar;slot-id=1;";
            uri += @"manufacturer=foo;model=bar;serial=foo;token=bar;";
            uri += @"type=private;object=foo;id=%62%61%72";

            // Build URI
            Pkcs11UriBuilder pkcs11UriBuilder = new Pkcs11UriBuilder();
            pkcs11UriBuilder.LibraryManufacturer = "foo";
            pkcs11UriBuilder.LibraryDescription = "bar";
            pkcs11UriBuilder.LibraryVersion = "1";
            pkcs11UriBuilder.SlotManufacturer = "foo";
            pkcs11UriBuilder.SlotDescription = "bar";
            pkcs11UriBuilder.SlotId = 1;
            pkcs11UriBuilder.Manufacturer = "foo";
            pkcs11UriBuilder.Model = "bar";
            pkcs11UriBuilder.Serial = "foo";
            pkcs11UriBuilder.Token = "bar";
            pkcs11UriBuilder.Type = CKO.CKO_PRIVATE_KEY;
            pkcs11UriBuilder.Object = "foo";
            pkcs11UriBuilder.Id = ConvertUtils.Utf8StringToBytes("bar");
            Assert.IsTrue(uri == pkcs11UriBuilder.ToString());

            // Parse URI
            Pkcs11Uri pkcs11uri = new Pkcs11Uri(uri);
            Assert.IsTrue(pkcs11uri.DefinesLibrary == true);
            Assert.IsTrue(pkcs11uri.DefinesToken == true);
            Assert.IsTrue(pkcs11uri.DefinesObject == true);
            Assert.IsTrue(pkcs11uri.UnknownPathAttributes == null);
            Assert.IsTrue(pkcs11uri.UnknownQueryAttributes == null);
            Assert.IsTrue(pkcs11uri.LibraryManufacturer == "foo");
            Assert.IsTrue(pkcs11uri.LibraryDescription == "bar");
            Assert.IsTrue(pkcs11uri.LibraryVersion == "1.0");
            Assert.IsTrue(pkcs11uri.SlotManufacturer == "foo");
            Assert.IsTrue(pkcs11uri.SlotDescription == "bar");
            Assert.IsTrue(pkcs11uri.SlotId == 1);
            Assert.IsTrue(pkcs11uri.Manufacturer == "foo");
            Assert.IsTrue(pkcs11uri.Model == "bar");
            Assert.IsTrue(pkcs11uri.Serial == "foo");
            Assert.IsTrue(pkcs11uri.Token == "bar");
            Assert.IsTrue(pkcs11uri.Type == CKO.CKO_PRIVATE_KEY);
            Assert.IsTrue(pkcs11uri.Object == "foo");
            Assert.IsTrue(Helpers.ByteArraysMatch(pkcs11uri.Id, ConvertUtils.Utf8StringToBytes("bar")));
            Assert.IsTrue(pkcs11uri.ModulePath == null);
            Assert.IsTrue(pkcs11uri.ModuleName == null);
            Assert.IsTrue(pkcs11uri.PinValue == null);
            Assert.IsTrue(pkcs11uri.PinSource == null);
        }