]> source.dussan.org Git - jgit.git/commitdiff
GPG user ID matching: use case-insensitive matching 35/174135/1
authorThomas Wolf <thomas.wolf@paranor.ch>
Tue, 29 Dec 2020 09:15:20 +0000 (10:15 +0100)
committerThomas Wolf <thomas.wolf@paranor.ch>
Tue, 29 Dec 2020 09:15:20 +0000 (10:15 +0100)
Although not mentioned in the GPG documentation at [1], GPG uses
case-insensitive matching also for the '<' (exact e-mail) and '@'
(partial e-mail) operators. Matching for '=' (full exact match) is
case-sensitive. Compare [2].

[1] https://www.gnupg.org/documentation/manuals/gnupg/Specify-a-User-ID.html
[2] https://dev.gnupg.org/source/gnupg/browse/master/g10/keyring.c;22f7dddc34446a8c3e9eddf6cb281f16802351d7$890

Bug: 547789
Change-Id: I2f5ab65807d5dde3aa00ff032894701bbd8418c9
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgKeyLocatorTest.java
org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgKeyLocator.java

index 744620163de3e591b2d35cc6567a5c68b74d7aac..5f43378705ad284358c91a1bafffffb6476e612a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019, Thomas Wolf <thomas.wolf@paranor.ch> and others
+ * Copyright (C) 2019, 2020 Thomas Wolf <thomas.wolf@paranor.ch> and others
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -53,7 +53,7 @@ public class BouncyCastleGpgKeyLocatorTest {
                assertFalse(match(USER_ID, "<heinrichh>"));
                assertFalse(match(USER_ID, "<uni-duesseldorf>"));
                assertFalse(match(USER_ID, "<h@u>"));
-               assertFalse(match(USER_ID, "<HeinrichH@uni-duesseldorf.de>"));
+               assertTrue(match(USER_ID, "<HeinrichH@uni-duesseldorf.de>"));
                assertFalse(match(USER_ID.substring(0, USER_ID.length() - 1),
                                "<heinrichh@uni-duesseldorf.de>"));
                assertFalse(match("", "<>"));
@@ -72,8 +72,8 @@ public class BouncyCastleGpgKeyLocatorTest {
                assertFalse(match(USER_ID, "@ "));
                assertFalse(match(USER_ID, "@"));
                assertFalse(match(USER_ID, "@Heine"));
-               assertFalse(match(USER_ID, "@HeinrichH"));
-               assertFalse(match(USER_ID, "@Heinrich"));
+               assertTrue(match(USER_ID, "@HeinrichH"));
+               assertTrue(match(USER_ID, "@Heinrich"));
                assertFalse(match("", "@"));
                assertFalse(match("", "@h"));
        }
@@ -110,6 +110,7 @@ public class BouncyCastleGpgKeyLocatorTest {
        public void testExplicitFingerprint() throws Exception {
                assertFalse(match("John Fade <j.fade@example.com>", "0xfade"));
                assertFalse(match("John Fade <0xfade@example.com>", "0xfade"));
+               assertFalse(match("John Fade <0xfade@example.com>", "0xFADE"));
                assertFalse(match("", "0xfade"));
        }
 
@@ -128,7 +129,7 @@ public class BouncyCastleGpgKeyLocatorTest {
                assertTrue(match("John Fade <0xfade@example.com>", "*0xfade"));
                assertTrue(match("John Fade <0xfade@example.com>", "*0xFADE"));
                assertTrue(match("John Fade <0xfade@example.com>", "@0xfade"));
-               assertFalse(match("John Fade <0xfade@example.com>", "@0xFADE"));
+               assertTrue(match("John Fade <0xfade@example.com>", "@0xFADE"));
                assertFalse(match("", "0x"));
        }
 }
index eca45072bf2fa54c9a36980ba04c691b71091841..1389f8bd1b7d16ec61db1f960157216d9f68ec41 100644 (file)
@@ -219,23 +219,34 @@ public class BouncyCastleGpgKeyLocator {
                        int stop = toMatch.indexOf('>');
                        return begin >= 0 && end > begin + 1 && stop > 0
                                        && userId.substring(begin + 1, end)
-                                                       .equals(toMatch.substring(0, stop));
+                                                       .equalsIgnoreCase(toMatch.substring(0, stop));
                }
                case '@': {
                        int begin = userId.indexOf('<');
                        int end = userId.indexOf('>', begin + 1);
                        return begin >= 0 && end > begin + 1
-                                       && userId.substring(begin + 1, end).contains(toMatch);
+                                       && containsIgnoreCase(userId.substring(begin + 1, end),
+                                                       toMatch);
                }
                default:
                        if (toMatch.trim().isEmpty()) {
                                return false;
                        }
-                       return userId.toLowerCase(Locale.ROOT)
-                                       .contains(toMatch.toLowerCase(Locale.ROOT));
+                       return containsIgnoreCase(userId, toMatch);
                }
        }
 
+       private static boolean containsIgnoreCase(String a, String b) {
+               int alength = a.length();
+               int blength = b.length();
+               for (int i = 0; i + blength <= alength; i++) {
+                       if (a.regionMatches(true, i, b, 0, blength)) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
        private String toFingerprint(String keyId) {
                if (keyId.startsWith("0x")) { //$NON-NLS-1$
                        return keyId.substring(2);