// SPDX-FileCopyrightText: 2023 Paul Schaub // // SPDX-License-Identifier: Apache-2.0 package sop.testsuite; import sop.Verification; import sop.util.UTCUtil; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Date; import java.util.List; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.fail; public class JUtils { /** * Return true, if the given
array
starts with
start
. * * @param array array * @param start start * @return true if array starts with start, false otherwise */ public static boolean arrayStartsWith(byte[] array, byte[] start) { return arrayStartsWith(array, start, 0); } /** * Return true, if the given
array
contains the given
start
at offset
offset
. * * @param array array * @param start start * @param offset offset * @return true, if array contains start at offset, false otherwise */ public static boolean arrayStartsWith(byte[] array, byte[] start, int offset) { if (offset < 0) { throw new IllegalArgumentException("Offset cannot be negative"); } if (start.length + offset > array.length) { return false; } for (int i = 0; i < start.length; i++) { if (array[offset + i] != start[i]) { return false; } } return true; } /** * Assert that the given
array
starts with
start
. * * @param array array * @param start start */ public static void assertArrayStartsWith(byte[] array, byte[] start) { if (!arrayStartsWith(array, start)) { byte[] actual = new byte[Math.min(start.length, array.length)]; System.arraycopy(array, 0, actual, 0, actual.length); fail("Array does not start with expected bytes.\n" + "Expected: <" + Arrays.toString(start) + ">\n" + "Actual: <" + Arrays.toString(actual) + ">"); } } /** * Assert that the given
array
contains
start
at
offset
. * * @param array array * @param start start * @param offset offset */ public static void assertArrayStartsWith(byte[] array, byte[] start, int offset) { if (!arrayStartsWith(array, start, offset)) { byte[] actual = new byte[Math.min(start.length, array.length - offset)]; System.arraycopy(array, offset, actual, 0, actual.length); fail("Array does not start with expected bytes at offset " + offset + ".\n" + "Expected: <" + Arrays.toString(start) + ">\n" + "Actual: <" + Arrays.toString(actual) + ">"); } } public static boolean arrayEndsWith(byte[] array, byte[] end) { return arrayEndsWith(array, end, 0); } public static boolean arrayEndsWith(byte[] array, byte[] end, int offset) { if (end.length + offset > array.length) { return false; } for (int i = 0; i < end.length; i++) { int arrOff = array.length - end.length - offset; if (end[i] != array[arrOff + i]) { return false; } } return true; } public static void assertArrayEndsWith(byte[] array, byte[] end) { assertArrayEndsWith(array, end, 0); } public static void assertArrayEndsWith(byte[] array, byte[] end, int offset) { if (!arrayEndsWith(array, end, offset)) { byte[] actual = new byte[Math.min(end.length, array.length - offset)]; System.arraycopy(array, array.length - actual.length, actual, 0, actual.length); fail("Array does not end with the expected bytes.\n" + "Expected: <" + Arrays.toString(end) + ">\n" + "Actual: <" + Arrays.toString(actual) + ">"); } } public static void assertArrayEndsWithIgnoreNewlines(byte[] array, byte[] end) { int offset = 0; while (offset < array.length && array[array.length - 1 - offset] == (byte) 10) { offset++; } assertArrayEndsWith(array, end, offset); } /** * Assert equality of the given two ascii armored byte arrays, ignoring armor header lines. * * @param first first ascii armored bytes * @param second second ascii armored bytes */ public static void assertAsciiArmorEquals(byte[] first, byte[] second) { byte[] firstCleaned = removeArmorHeaders(first); byte[] secondCleaned = removeArmorHeaders(second); assertArrayEquals(firstCleaned, secondCleaned); } /** * Remove armor headers "Comment:", "Version:", "MessageID:", "Hash:" and "Charset:" along with their values * from the given ascii armored byte array. * * @param armor ascii armored byte array * @return ascii armored byte array with header lines removed */ public static byte[] removeArmorHeaders(byte[] armor) { String string = new String(armor, StandardCharsets.UTF_8); string = string.replaceAll("Comment: .+\\R", "") .replaceAll("Version: .+\\R", "") .replaceAll("MessageID: .+\\R", "") .replaceAll("Hash: .+\\R", "") .replaceAll("Charset: .+\\R", ""); return string.getBytes(StandardCharsets.UTF_8); } public static void assertSignedBy(List verifications, String primaryFingerprint) { for (Verification verification : verifications) { if (verification.getSigningCertFingerprint().equals(primaryFingerprint)) { return; } } if (verifications.isEmpty()) { fail("Verification list is empty."); } fail("Verification list does not contain verification by cert " + primaryFingerprint + ":\n" + Arrays.toString(verifications.toArray(new Verification[0]))); } public static void assertSignedBy(List verifications, String signingFingerprint, String primaryFingerprint) { for (Verification verification : verifications) { if (verification.getSigningCertFingerprint().equals(primaryFingerprint) && verification.getSigningKeyFingerprint().equals(signingFingerprint)) { return; } } if (verifications.isEmpty()) { fail("Verification list is empty."); } fail("Verification list does not contain verification by key " + signingFingerprint + " on cert " + primaryFingerprint + ":\n" + Arrays.toString(verifications.toArray(new Verification[0]))); } public static void assertSignedBy(List verifications, String primaryFingerprint, Date signatureDate) { for (Verification verification : verifications) { if (verification.getSigningCertFingerprint().equals(primaryFingerprint) && verification.getCreationTime().equals(signatureDate)) { return; } } if (verifications.isEmpty()) { fail("Verification list is empty."); } fail("Verification list does not contain verification by cert " + primaryFingerprint + " made at " + UTCUtil.formatUTCDate(signatureDate) + ":\n" + Arrays.toString(verifications.toArray(new Verification[0]))); } public static void assertSignedBy(List verifications, String signingFingerprint, String primaryFingerprint, Date signatureDate) { for (Verification verification : verifications) { if (verification.getSigningCertFingerprint().equals(primaryFingerprint) && verification.getSigningKeyFingerprint().equals(signingFingerprint) && verification.getCreationTime().equals(signatureDate)) { return; } } if (verifications.isEmpty()) { fail("Verification list is empty."); } fail("Verification list does not contain verification by key" + signingFingerprint + " on cert " + primaryFingerprint + " made at " + UTCUtil.formatUTCDate(signatureDate) + ":\n" + Arrays.toString(verifications.toArray(new Verification[0]))); } }