#include "common.h"
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/x509.h>
#include <openssl/evp.h>
#include <openssl/ec.h>
#include <openssl/bn.h>

// Test for signature parsing regression
// This test ensures the fix for the buffer overflow vulnerability in ASN.1 DER signature parsing remains effective

// External declaration of the public function we're testing
extern int eid_vwr_check_data_validity(const void* photo, int plen,
		const void* photohash, int hashlen,
		const void* datafile, int datfilelen,
		const void* datasig, int datsiglen,
		const void* addrfile, int addfilelen,
		const void* addrsig, int addsiglen,
		const void* cert, int certlen);

#define TEST_RV_OK 0
#define TEST_RV_FAIL 1

#define verbose_assert(a) { if(!(a)) { printf("ASSERTION FAILED: %s\n", #a); return TEST_RV_FAIL; } else { printf("ASSERTION OK: %s\n", #a); } }

int main(void) {
    printf("Testing signature parsing regression...\n");
    
    // Create a test EC key and certificate for testing
    EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_secp384r1);
    verbose_assert(eckey != NULL);
    verbose_assert(EC_KEY_generate_key(eckey) == 1);
    
    // Create a self-signed certificate
    X509 *cert = X509_new();
    verbose_assert(cert != NULL);
    verbose_assert(X509_set_version(cert, 2) == 1); // v3 certificate
    
    // Set certificate validity
    X509_gmtime_adj(X509_get_notBefore(cert), 0);
    X509_gmtime_adj(X509_get_notAfter(cert), 365 * 24 * 3600); // 1 year
    
    // Set public key
    EVP_PKEY *pkey = EVP_PKEY_new();
    verbose_assert(pkey != NULL);
    verbose_assert(EVP_PKEY_set1_EC_KEY(pkey, eckey) == 1);
    verbose_assert(X509_set_pubkey(cert, pkey) == 1);
    
    // Set serial number
    ASN1_INTEGER_set(X509_get_serialNumber(cert), 1);
    
    // Set issuer and subject names
    X509_NAME *name = X509_NAME_new();
    X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char*)"Test", -1, -1, 0);
    X509_set_issuer_name(cert, name);
    X509_set_subject_name(cert, name);
    X509_NAME_free(name);
    
    EVP_PKEY_free(pkey);
    
    // Create test data
    unsigned char photo_data[] = "test_photo_data";
    unsigned char photo_hash[48] = {0}; // SHA384 length
    unsigned char data_file[] = "test_identity_data";
    unsigned char addr_file[] = "test_address_data";
    
    // Create a mock certificate (just need some valid bytes for testing)
    unsigned char mock_cert[] = {
        0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0x8a, 0x7c, 0x22, 0x1d, 0x23, 0x45, 0x67,
        0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x01, 0x02, 0x03, 0x04,
        0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
        0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
        0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34,
        0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44,
        0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54,
        0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64,
        0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74,
        0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84,
        0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94,
        0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
        0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4,
        0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4,
        0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4,
        0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4,
        0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4,
        0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
    };
    
    // Test case 1: Valid short form DER signature should not crash
    printf("Test 1: Valid short form DER signature...\n");
    unsigned char short_form_datasig[] = {
        0x30, 0x45,  // SEQUENCE, length 69 bytes (short form)
        0x02, 0x20,  // INTEGER, length 32 bytes (r component)
        0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
        0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
        0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
        0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
        0x02, 0x21,  // INTEGER, length 33 bytes (s component)
        0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
        0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
        0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
        0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40,
        0x41
    };
    
    unsigned char short_form_addrsig[] = {
        0x30, 0x44,  // SEQUENCE, length 68 bytes (short form)
        0x02, 0x20,  // INTEGER, length 32 bytes (r component)
        0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
        0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
        0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
        0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
        0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
        0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40,
        0x02, 0x20,  // INTEGER, length 32 bytes (s component)
        0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
        0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
        0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
        0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60
    };
    
    int result1 = eid_vwr_check_data_validity(
        photo_data, sizeof(photo_data),
        photo_hash, sizeof(photo_hash),
        data_file, sizeof(data_file),
        short_form_datasig, sizeof(short_form_datasig),
        addr_file, sizeof(addr_file),
        short_form_addrsig, sizeof(short_form_addrsig),
        mock_cert, sizeof(mock_cert)
    );
    printf("Result: %s (expected: failure due to invalid signature, but no crash)\n", result1 == 1 ? "success" : "failure");
    
    // Test case 2: Long form DER signature (the case that was broken)
    printf("Test 2: Long form DER signature (the problematic case)...\n");
    unsigned char long_form_datasig[] = {
        0x30, 0x81, 0x82,  // SEQUENCE, length 130 bytes (long form)
        0x02, 0x41,  // INTEGER, length 65 bytes (r component)
        0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
        0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
        0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
        0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
        0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
        0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
        0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
        0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40,
        0x41,
        0x02, 0x41,  // INTEGER, length 65 bytes (s component)
        0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
        0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60,
        0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
        0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
        0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
        0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80,
        0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
        0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90,
        0x91
    };
    
    unsigned char long_form_addrsig[] = {
        0x30, 0x81, 0x81,  // SEQUENCE, length 129 bytes (long form)
        0x02, 0x41,  // INTEGER, length 65 bytes (r component)
        0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,
        0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0,
        0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8,
        0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0,
        0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
        0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
        0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
        0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0,
        0xe1,
        0x02, 0x40,  // INTEGER, length 64 bytes (s component)
        0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
        0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0x00,
        0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
        0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
        0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
        0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
        0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
        0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40
    };
    
    int result2 = eid_vwr_check_data_validity(
        photo_data, sizeof(photo_data),
        photo_hash, sizeof(photo_hash),
        data_file, sizeof(data_file),
        long_form_datasig, sizeof(long_form_datasig),
        addr_file, sizeof(addr_file),
        long_form_addrsig, sizeof(long_form_addrsig),
        mock_cert, sizeof(mock_cert)
    );
    printf("Result: %s (expected: failure due to invalid signature, but no crash)\n", result2 == 1 ? "success" : "failure");
    
    // Test case 3: Dangerous signature that would cause buffer overflow in old code
    printf("Test 3: Dangerous signature that would cause buffer overflow...\n");
    unsigned char dangerous_datasig[] = {
        0x30, 0x85,  // Claims 5 length bytes follow (dangerous - would cause buffer overflow)
        0x01, 0x02, 0x03  // Not enough data for claimed length
    };
    
    unsigned char dangerous_addrsig[] = {0x30, 0x01, 0x02};  // Minimal invalid signature
    
    int result3 = eid_vwr_check_data_validity(
        photo_data, sizeof(photo_data),
        photo_hash, sizeof(photo_hash),
        data_file, sizeof(data_file),
        dangerous_datasig, sizeof(dangerous_datasig),
        addr_file, sizeof(addr_file),
        dangerous_addrsig, sizeof(dangerous_addrsig),
        mock_cert, sizeof(mock_cert)
    );
    printf("Result: %s (expected: failure, but no crash due to bounds checking)\n", result3 == 1 ? "success" : "failure");
    
    // Cleanup
    X509_free(cert);
    EC_KEY_free(eckey);
    
    printf("Signature parsing regression tests completed successfully.\n");
    printf("All tests passed - no crashes detected, bounds checking works correctly.\n");
    return TEST_RV_OK;
}
