/* =============================================================================
 * Copyright (c) 2021 Michael Baeuerle
 *
 * All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, and/or sell copies of the Software, and to permit persons
 * to whom the Software is furnished to do so, provided that the above
 * copyright notice(s) and this permission notice appear in all copies of
 * the Software and that both the above copyright notice(s) and this
 * permission notice appear in supporting documentation.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
 * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY
 * SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * Except as contained in this notice, the name of a copyright holder
 * shall not be used in advertising or otherwise to promote the sale, use
 * or other dealings in this Software without prior written authorization
 * of the copyright holder.
 *
 * SPDX-License-Identifier: ICU
 */

/* Test program for new cl_verify_multi() API available since version 3.3 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "canlock.h"


/* ========================================================================== */
/* Test program for new cl_verify_multi() API from version 3.3 */

int main(void)
{
   cl_hash_version reject_hash[3];
   const char *c_keys, *c_locks;
   int rv;
   int failed = 0;

   /* Example from RFC8315 Section 5.1 */
   printf("Test 1\n\n");
   c_keys  = "sha256:qv1VXHYiCGjkX/N1nhfYKcAeUn8bCVhrWhoKuBSnpMA=";
   c_locks = "sha256:s/pmK/3grrz++29ce2/mQydzJuc7iqHn1nqcJiQTPMc=";
   printf("Deactivated hash algorithms: None\n");
   printf("Keys : %s\n", c_keys);
   printf("Locks: %s\n", c_locks);
   rv = cl_verify_multi(NULL, c_keys, c_locks);
   printf("\n");
   printf("%s\n\n", "Expected result: GOOD");
   if (rv)
   {
      printf("BAD: Result was not as expected\n");
      failed = 1;
   }
   else
   {
      printf("GOOD\n");
   }
   printf("\n----------------------------------------"
          "----------------------------------------\n\n");

   /* Example from RFC8315 Section 5.1 */
   printf("Test 2\n\n");
   c_keys  = "sha256:qv1VXHYiCGjkX/N1nhfYKcAeUn8bCVhrWhoKuBSnpMA=";
   c_locks = "sha256:s/pmK/3grrz++29ce2/mQydzJuc7iqHn1nqcJiQTPMc=";
   printf("Deactivated hash algorithms: None (with empty list)\n");
   reject_hash[0] = CL_INVALID;
   printf("Keys : %s\n", c_keys);
   printf("Locks: %s\n", c_locks);
   rv = cl_verify_multi(reject_hash, c_keys, c_locks);
   printf("\n");
   printf("%s\n\n", "Expected result: GOOD");
   if (rv)
   {
      printf("BAD: Result was not as expected\n");
      failed = 1;
   }
   else
   {
      printf("GOOD\n");
   }
   printf("\n----------------------------------------"
          "----------------------------------------\n\n");

   /* Example from RFC8315 Section 5.1 */
   printf("Test 3\n\n");
   c_keys  = "sha256:qv1VXHYiCGjkX/N1nhfYKcAeUn8bCVhrWhoKuBSnpMA=";
   c_locks = "sha256:s/pmK/3grrz++29ce2/mQydzJuc7iqHn1nqcJiQTPMc=";
   printf("Deactivated hash algorithms: SHA256\n");
   reject_hash[0] = CL_SHA256;
   reject_hash[1] = CL_INVALID;
   printf("Keys : %s\n", c_keys);
   printf("Locks: %s\n", c_locks);
   rv = cl_verify_multi(reject_hash, c_keys, c_locks);
   printf("\n");
   printf("%s\n\n", "Expected result: BAD");
   if (!rv)
   {
      printf("GOOD: Result was not as expected\n");
      failed = 1;
   }
   else
   {
      printf("BAD\n");
   }
   printf("\n----------------------------------------"
          "----------------------------------------\n\n");

   /* Example from RFC8315 Section 5.3 */
   printf("Test 4\n\n");
   c_keys  = "sha256:qv1VXHYiCGjkX/N1nhfYKcAeUn8bCVhrWhoKuBSnpMA= "
             "sha256:yM0ep490Fzt83CLYYAytm3S2HasHhYG4LAeAlmuSEys= "
             "sha256:sSkDke97Dh78/d+Diu1i3dQ2Fp/EMK3xE2GfEqZlvK8= "
             "ShA1:aaaBBBcccDDDeeeFFF";
   c_locks = "sha256:s/pmK/3grrz++29ce2/mQydzJuc7iqHn1nqcJiQTPMc= "
             "sha256:NSBTz7BfcQFTCen+U4lQ0VS8VIlZao2b8mxD/xJaaeE= "
             "sha256:RrKLp7YCQc9T8HmgSbxwIDlnCDWsgy1awqtiDuhedRo= "
             "sha1:bNXHc6ohSmeHaRHHW56BIWZJt+4=";
   printf("Deactivated hash algorithms: None\n");
   printf("Keys : %s\n", c_keys);
   printf("Locks: %s\n", c_locks);
   rv = cl_verify_multi(NULL, c_keys, c_locks);
   printf("\n");
   printf("%s\n\n", "Expected result: GOOD");
   if (rv)
   {
      printf("BAD: Result was not as expected\n");
      failed = 1;
   }
   else
   {
      printf("GOOD\n");
   }
   printf("\n----------------------------------------"
          "----------------------------------------\n\n");

   /* Example from RFC8315 Section 5.3 */
   printf("Test 5\n\n");
   c_keys  = "sha256:qv1VXHYiCGjkX/N1nhfYKcAeUn8bCVhrWhoKuBSnpMA= "
             "sha256:yM0ep490Fzt83CLYYAytm3S2HasHhYG4LAeAlmuSEys= "
             "sha256:sSkDke97Dh78/d+Diu1i3dQ2Fp/EMK3xE2GfEqZlvK8= "
             "ShA1:aaaBBBcccDDDeeeFFF";
   c_locks = "sha256:s/pmK/3grrz++29ce2/mQydzJuc7iqHn1nqcJiQTPMc= "
             "sha256:NSBTz7BfcQFTCen+U4lQ0VS8VIlZao2b8mxD/xJaaeE= "
             "sha256:RrKLp7YCQc9T8HmgSbxwIDlnCDWsgy1awqtiDuhedRo= "
             "sha1:bNXHc6ohSmeHaRHHW56BIWZJt+4=";
   printf("Deactivated hash algorithms: SHA1, SHA256\n");
   reject_hash[0] = CL_SHA1;
   reject_hash[1] = CL_SHA256;
   reject_hash[2] = CL_INVALID;
   printf("Keys : %s\n", c_keys);
   printf("Locks: %s\n", c_locks);
   rv = cl_verify_multi(reject_hash, c_keys, c_locks);
   printf("\n");
   printf("%s\n\n", "Expected result: BAD");
   if (!rv)
   {
      printf("GOOD: Result was not as expected\n");
      failed = 1;
   }
   else
   {
      printf("BAD\n");
   }
   printf("\n----------------------------------------"
          "----------------------------------------\n\n");

   /* Example from RFC8315 Section 5.3 */
   printf("Test 6\n\n");
   c_keys  = "sha256:qv1VXHYiCGjkX/N1nhfYKcAeUn8bCVhrWhoKuBSnpMA= "
             "sha256:yM0ep490Fzt83CLYYAytm3S2HasHhYG4LAeAlmuSEys= "
             "sha256:sSkDke97Dh78/d+Diu1i3dQ2Fp/EMK3xE2GfEqZlvK8= "
             "ShA1:aaaBBBcccDDDeeeFFF";
   c_locks = "sha256:s/pmK/3grrz++29ce2/mQydzJuc7iqHn1nqcJiQTPMc= "
             "sha256:NSBTz7BfcQFTCen+U4lQ0VS8VIlZao2b8mxD/xJaaeE= "
             "sha256:RrKLp7YCQc9T8HmgSbxwIDlnCDWsgy1awqtiDuhedRo= "
             "sha1:bNXHc6ohSmeHaRHHW56BIWZJt+4=";
   printf("Deactivated hash algorithms: SHA256\n");
   reject_hash[0] = CL_SHA256;
   reject_hash[1] = CL_INVALID;
   printf("Keys : %s\n", c_keys);
   printf("Locks: %s\n", c_locks);
   rv = cl_verify_multi(reject_hash, c_keys, c_locks);
   printf("\n");
   printf("%s\n\n", "Expected result: GOOD");
   if (rv)
   {
      printf("BAD: Result was not as expected\n");
      failed = 1;
   }
   else
   {
      printf("GOOD\n");
   }
   printf("\n----------------------------------------"
          "----------------------------------------\n\n");

   /* Example from RFC8315 Section 5.3 */
   printf("Test 7\n\n");
   c_keys  = "sha256:qv1VXHYiCGjkX/N1nhfYKcAeUn8bCVhrWhoKuBSnpMA= "
             "sha256:yM0ep490Fzt83CLYYAytm3S2HasHhYG4LAeAlmuSEys= "
             "sha256:sSkDke97Dh78/d+Diu1i3dQ2Fp/EMK3xE2GfEqZlvK8= "
             "ShA1:aaaBBBcccDDDeeeFFF";
   c_locks = "sha256:s/pmK/3grrz++29ce2/mQydzJuc7iqHn1nqcJiQTPMc= "
             "sha256:NSBTz7BfcQFTCen+U4lQ0VS8VIlZao2b8mxD/xJaaeE= "
             "sha256:RrKLp7YCQc9T8HmgSbxwIDlnCDWsgy1awqtiDuhedRo=";
   printf("Deactivated hash algorithms: SHA256\n");
   reject_hash[0] = CL_SHA256;
   reject_hash[1] = CL_INVALID;
   printf("Keys : %s\n", c_keys);
   printf("Locks: %s\n", c_locks);
   rv = cl_verify_multi(reject_hash, c_keys, c_locks);
   printf("\n");
   printf("%s\n\n", "Expected result: BAD");
   if (!rv)
   {
      printf("GOOD: Result was not as expected\n");
      failed = 1;
   }
   else
   {
      printf("BAD\n");
   }
   printf("\n----------------------------------------"
          "----------------------------------------\n\n");

   /*
    * Example from RFC8315 Section 5.3
    * Use some more whitespace between the elements to test the parser.
    */
   printf("Test 8\n\n");
   c_keys  = "   sha256:qv1VXHYiCGjkX/N1nhfYKcAeUn8bCVhrWhoKuBSnpMA= "
             "   sha256:yM0ep490Fzt83CLYYAytm3S2HasHhYG4LAeAlmuSEys= "
             "   sha256:sSkDke97Dh78/d+Diu1i3dQ2Fp/EMK3xE2GfEqZlvK8= "
             "   ShA1:aaaBBBcccDDDeeeFFF                             ";
   c_locks = "   sha256:s/pmK/3grrz++29ce2/mQydzJuc7iqHn1nqcJiQTPMc= "
             "   sha1:bNXHc6ohSmeHaRHHW56BIWZJt+4=                   "
             "   sha256:NSBTz7BfcQFTCen+U4lQ0VS8VIlZao2b8mxD/xJaaeE= "
             "   sha256:RrKLp7YCQc9T8HmgSbxwIDlnCDWsgy1awqtiDuhedRo= ";
   printf("Deactivated hash algorithms: SHA256\n");
   reject_hash[0] = CL_SHA256;
   reject_hash[1] = CL_INVALID;
   printf("Keys : %s\n", c_keys);
   printf("Locks: %s\n", c_locks);
   rv = cl_verify_multi(reject_hash, c_keys, c_locks);
   printf("\n");
   printf("%s\n\n", "Expected result: GOOD");
   if (rv)
   {
      printf("BAD: Result was not as expected\n");
      failed = 1;
   }
   else
   {
      printf("GOOD\n");
   }
   printf("\n----------------------------------------"
          "----------------------------------------\n\n");

   /* Test with SHA512 */
   printf("Test 9\n\n");
   c_keys  = "Sha512:ryoikFW3wKefmYr+zDzKn16ngNf1eYbZ0DN+3yqCbkid3HxU5K99G7RcNEx1UxiL3ZQfwg1+TDhH96D+tCcXGQ==";
   c_locks = "shA512:Hq6MQ2JMzGf56agcqYPEMnoWHbQMSAG0eE0ABHgktP8cKL6/A4bvydjUAa0h7sHUU8vdfWXK7eUYG/pnDxgitg==";
   printf("Deactivated hash algorithms: SHA1, SHA256\n");
   reject_hash[0] = CL_SHA1;
   reject_hash[1] = CL_SHA256;
   reject_hash[2] = CL_INVALID;
   printf("Keys : %s\n", c_keys);
   printf("Locks: %s\n", c_locks);
   rv = cl_verify_multi(reject_hash, c_keys, c_locks);
   printf("\n");
   printf("%s\n\n", "Expected result: GOOD");
   if (rv)
   {
      printf("BAD: Result was not as expected\n");
      failed = 1;
   }
   else
   {
      printf("GOOD\n");
   }
   printf("\n----------------------------------------"
          "----------------------------------------\n\n");

   /* Test with SHA384 and some unsupported hash algorithm */
   printf("Test 10\n\n");
   c_keys  = "unsupported:xxx sha384:MhUl2H4gnJ6Wsji2Ybloz1mzvVX7zKqhfuzBOW+l8t86pVUlio4Vx7E+6KkGAfTZ";
   c_locks = "unsupported:yyy sha384:CwL4/RWxnWroRrDuWoV/caCyg9zHNYthlxMU64V660K2VF6PUQN3eqruyPPQ1Gfh";
   printf("Deactivated hash algorithms: SHA1, SHA224\n");
   reject_hash[0] = CL_SHA1;
   reject_hash[1] = CL_SHA224;
   reject_hash[2] = CL_INVALID;
   printf("Keys : %s\n", c_keys);
   printf("Locks: %s\n", c_locks);
   rv = cl_verify_multi(reject_hash, c_keys, c_locks);
   printf("\n");
   printf("%s\n\n", "Expected result: GOOD");
   if (rv)
   {
      printf("BAD: Result was not as expected\n");
      failed = 1;
   }
   else
   {
      printf("GOOD\n");
   }
   printf("\n----------------------------------------"
          "----------------------------------------\n\n");

   /* Check for success */
   if (!failed) exit(EXIT_SUCCESS);
   exit(EXIT_FAILURE);
}


/* EOF */
