/*
 * Copyright (c) 2012-2020 MIRACL UK Ltd.
 *
 * This file is part of MIRACL Core
 * (see https://github.com/miracl/core).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// To run test program 
// g++ -O2 testx509.cpp  core.a -o testx509

#include <stdio.h>
#include "core.h"  // for octet support only
#include "x509.h"

// assumes library support for all of these
#include "eddsa_Ed448.h"
#include "eddsa_Ed25519.h"
#include "ecdh_NIST256.h"
#include "ecdh_NIST521.h"
#include "rsa_RSA4096.h"
#include "rsa_RSA2048.h"

/* This simple driver program is hard-wired to support just one elliptic curve and one
   RSA bit length. To change replace the text string NIST256 in the main program to
   another curve and 2048 to some other value, where the curve and the RSA bit length
   are suppported by the library. Of course a more elaborate program could support
   muliple curves simultaneously */

#define CHOICE USE_NIST256

/* test driver program */
// Sample Certs. Uncomment one CA cert and one example cert. Note that CORE library must be built to support given curve.
// Sample Certs all created using OpenSSL - see http://blog.didierstevens.com/2008/12/30/howto-make-your-own-cert-with-openssl/
// Note - SSL currently only supports NIST curves. Howevever version 1.1.0 of OpenSSL now supports C25519

#if CHOICE==USE_NIST256

// ** CA is RSA 2048-bit based - for use with NIST256 build of library - assumes use of SHA256 in Certs
// RSA 2048 Self-Signed CA cert
char ca_b64[] = "MIIDuzCCAqOgAwIBAgIJAP44jcM1MOROMA0GCSqGSIb3DQEBCwUAMHQxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEfMB0GCSqGSIb3DQEJARYQbXNjb3R0QGluZGlnby5pZTAeFw0xNTExMjYwOTUwMzlaFw0yMDExMjUwOTUwMzlaMHQxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEfMB0GCSqGSIb3DQEJARYQbXNjb3R0QGluZGlnby5pZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANUs7/nri9J8zw8rW8JVszXP0ZqeLoQJaq2X28ebm8x5VT3okr9rnBjFjpx0YKQCAFQf8iSOOYuNpDvtZ/YpsjPbk2rg5sLY9G0eUMqrTuZ7moPSxnrXS5evizjD9Z9HqaqeNEYD3sPouPg+lhU1oAUQjUTJVFhEr1x0EnSEYbbrWtY9ZDSuZv+d4NIeqqPOYFd1yZc+LYZyQbAAQqwRLNPZH/rnIykLa6I7w7mGT7H6SBz2O09BtgpTHhalL40ecXa4ZOEze0xwzlc+mEFIrnmdadg3vQrJt42RVbo3LN6RfDIqUZOMOtQW/53pUR1lIpCwVWJTiOpmSEIEqhhjFq0CAwEAAaNQME4wHQYDVR0OBBYEFJrz6LHeT6FcjRahpUC3hAMxKRTCMB8GA1UdIwQYMBaAFJrz6LHeT6FcjRahpUC3hAMxKRTCMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADqkqCYVa3X8XO9Ufu6XIUoZafFPRjSeJXvEIWqlbm7ixJZ2FPOvf2eMc5RCZYigNKhsxru5Ojw0lPcpa8DDmEsdZDf7p0vlmf7T7xH9gtoInh4DzgI8HRHFc8R/z2/jLX7nlLoopKX5yp7F1gRACg0pd4tGpQ6EnBNcYZZghFH9UIRDmx+vDlwDCu8vyRPt35orrEiI4XGq/QkvxxAb5YWxQ4i06064ULfyCI7suu3KoobdM1aAaA8zhpOOBXKbq+Wi9IGFe/wiEMHLmfHdt9CBTjIWb//IHji4RT05kCmTVrx97pb7EHafuL3L10mM5cpTyBWKnb4kMFtx9yw+S2U=";
// an RSA 2048 CA-signed cert
//char cert_b64[]="MIIDcjCCAloCAQEwDQYJKoZIhvcNAQELBQAwdDELMAkGA1UEBhMCSUUxEDAOBgNVBAgMB0lyZWxhbmQxDzANBgNVBAcMBkR1YmxpbjEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMR8wHQYJKoZIhvcNAQkBFhBtc2NvdHRAaW5kaWdvLmllMB4XDTE1MTEyNjEwMzQzMFoXDTE3MTEyNTEwMzQzMFowgYkxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xETAPBgNVBAoMCENlcnRpVm94MQ0wCwYDVQQLDARMYWJzMQ0wCwYDVQQDDARNSUtFMSYwJAYJKoZIhvcNAQkBFhdtaWtlLnNjb3R0QGNlcnRpdm94LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMIoxaQHFQzfyNChrw+3i7FjRFMHZ4zspkjkAcJW21LdBCqrxU+sdjyBoSFlrlafQOHshbrEP93AKX1bfaYbuV4fzq7OlRaLxaK+b+xrOJdewMI2WZ5OwEzj3onZATISogIoB6dTdzJ41NuxuMqQ/DqOnVrRA0SoIespbQhB8FGHBLw0hJATBzUk+bqOIt0HmnMp2EbYgtuG4lYINU/lD3Qt16SunUukWRLtxqJkioie+dkhP2zm+bOlSVmeQb4Wp8AI14OKkTfkdYC8qCxb5eabg90Q33rQUhNwRQHhHwopZwD/BgodasoSrPfwUlj0awh6y87eMGcik5Q/mjkCk5MCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAFrd7R/67ClkbLhpiX++6QTOa47siUAB9v+Qil9hZfhPNeeM589ixYkD4zH5pOK2B0ea+CXEKkanQ6lXx9KV86yS7fq6Yww7wO0diecusHd0+P82i46Tq0nm8nlsnAuhYoFRUGa2m2DkB1HSsB0ts8DjzFLySonFjSSLHDU0ox9/uFbJMzipy3ijAA4XM0N4jRrUfrmxpA7DOOsbEbGkvvB7VK9+s9PHE/4dJTwhSteplUnhxVFkkDo/JwaLx4/IEQRlCF3KEQ5s3AwRHnbrIjOY2yONxHBtJEp7QN5aOHruwvMNRNheCBPiQJyLitUsFGr4voANmobkrFgYtu0tRMQ==";
// an ECDSA 256 CA-signed cert
char cert_b64[] = "MIICojCCAYoCAQMwDQYJKoZIhvcNAQELBQAwdDELMAkGA1UEBhMCSUUxEDAOBgNVBAgMB0lyZWxhbmQxDzANBgNVBAcMBkR1YmxpbjEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMR8wHQYJKoZIhvcNAQkBFhBtc2NvdHRAaW5kaWdvLmllMB4XDTE1MTEyNjEzNDcyOVoXDTE3MTEyNTEzNDcyOVowgYQxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xETAPBgNVBAoMCENlcnRpdm94MQ0wCwYDVQQLDARMYWJzMQ8wDQYDVQQDDAZtc2NvdHQxHzAdBgkqhkiG9w0BCQEWEG1zY290dEBpbmRpZ28uaWUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATO2iZiQZsXxzwBKnufKfZcsctNXZ4PmfJm638PmX9DQ3Xdb+nD5VxiOakNcB9xf5im8CriiOF5Z/7yPGyzUMbdMA0GCSqGSIb3DQEBCwUAA4IBAQAK5fMgGCCiPts8hMUZvYDpu8hd7qtPKPBc10QUccHb7PGrhqf/Ex2Gpj1aaURmx7SGZG0HX97LtkdW8KQpEoyaa60r7cjVA589TznxXKSGg5ggVoFJNpuZUm7VcolLjwIgTxtGbPzrvVMiZ4cl4PwFePXVKTl4f8XkOFX5gLmVSuCf729lEBmpx3IzqGmTjmnBixaApUElOKVeL7hiUKP3TqMUxZN+QNJBq4Mh9K9h4Sks2oneLwBwhMqQvpmcOb/7SucJn5N0IgJoGaMbfX0oCJJID1NSbagUSbFD1XciR2Ng9VtvnRP+htmEQ7jtww8phFdrWt5M5zPGOHUppqDx";

// ** CA is ECC 256 based  - for use with NIST256 build of library
// ECDSA 256 Self-Signed CA cert
//char ca_b64[]="MIIB7TCCAZOgAwIBAgIJANp4nGS/VYj2MAoGCCqGSM49BAMCMFMxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xNTExMjYxMzI0MTBaFw0yMDExMjUxMzI0MTBaMFMxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABPb6IjYNKyfbEtL1aafzW1jrn6ALn3PnGm7AyX+pcvwG0GKmb3Z/uHzhT4GysNE0/GB1n4Y/mrORQIm2X98rRs6jUDBOMB0GA1UdDgQWBBSfXUNkgJVklIhuXq4DCnVYhsdzwDAfBgNVHSMEGDAWgBSfXUNkgJVklIhuXq4DCnVYhsdzwDAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIQDrZJ1tshwTl/jabU2i49EOgbWe0ZgE3QZywJclf5IVwwIgVmz79AAf7e098lyrOKYAqbwjHVyMZGfmkNNGIuIhp/Q=";
// an ECDSA 256 CA-signed cert
//char cert_b64[]="MIIBvjCCAWQCAQEwCgYIKoZIzj0EAwIwUzELMAkGA1UEBhMCSUUxEDAOBgNVBAgMB0lyZWxhbmQxDzANBgNVBAcMBkR1YmxpbjEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMB4XDTE1MTEyNjEzMjc1N1oXDTE3MTEyNTEzMjc1N1owgYIxCzAJBgNVBAYTAklFMRAwDgYDVQQIDAdJcmVsYW5kMQ8wDQYDVQQHDAZEdWJsaW4xETAPBgNVBAoMCENlcnRpdm94MQ0wCwYDVQQLDARMYWJzMQ0wCwYDVQQDDARtaWtlMR8wHQYJKoZIhvcNAQkBFhBtc2NvdHRAaW5kaWdvLmllMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEY42H52TfWMLueKB1o2Sq8uKaKErbHJ2GRAxrnJdNxex0hxZF5FUx7664BbPUolKhpvKTnJxDq5/gMqXzpKgR6DAKBggqhkjOPQQDAgNIADBFAiEA0ew08Xg32g7BwheslVKwXo9XRRx4kygYha1+cn0tvaUCIEKCEwnosZlAckjcZt8aHN5zslE9K9Y7XxTErTstthKc";
// an RSA 2048 CA-signed cert
//char cert_b64[]="MIICiDCCAi4CAQIwCgYIKoZIzj0EAwIwUzELMAkGA1UEBhMCSUUxEDAOBgNVBAgMB0lyZWxhbmQxDzANBgNVBAcMBkR1YmxpbjEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMB4XDTE1MTEyNjEzMzcwNVoXDTE3MTEyNTEzMzcwNVowgYExCzAJBgNVBAYTAklFMQ8wDQYDVQQIDAZJZWxhbmQxDzANBgNVBAcMBkR1YmxpbjERMA8GA1UECgwIQ2VydGl2b3gxDTALBgNVBAsMBExhYnMxDTALBgNVBAMMBE1pa2UxHzAdBgkqhkiG9w0BCQEWEG1zY290dEBpbmRpZ28uaWUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCjPBVwmPg8Gwx0+8xekmomptA0BDwS7NUfBetqDqNMNyji0bSe8LAfpciU7NW/HWfUE1lndCqSDDwnMJmwC5e3GAl/Bus+a+z8ruEhWGbn95xrHXFkOawbRlXuS7UcEQCvPr8KQHhNsg4cyV7Hn527CPUl27n+WN8/pANo01cTN/dQaK87naU0Mid09vktlMKSN0zyJOnc5CsaTLs+vCRKJ9sUL3d4IQIA2y7gvrTe+iY/QI26nqhGpNWYyFkAdy9PdHUEnDI6JsfF7jFh37yG7XEgDDA3asp/oi1T1+ZoASj2boL++opdqCzDndeWwzDWAWuvJ9wULd80ti6x737ZAgMBAAEwCgYIKoZIzj0EAwIDSAAwRQIgCDwgl98+9moBo+etaLt8MvB/z5Ti6i9neRTZkvoFl7YCIQDq//M3OB757fepErRzIQo3aFAFYjOooi6WdSqP3XqGIg==";

#endif

#if CHOICE==USE_ED25519

// **CA is EDDSA Ed25519 based. Self-signed cert
char ca_b64[]= "MIIBRTCB+KADAgECAhNBrGyCRdfc0WyPpPd+LB8LEiK4MAUGAytlcDAZMRcwFQYDVQQDDA5NaWtlJ3Mgcm9vdCBDQTAeFw0yMzA1MDExNjAwMDlaFw0yNDA0MzAxNjAwMDlaMBkxFzAVBgNVBAMMDk1pa2UncyByb290IENBMCowBQYDK2VwAyEAh8YXRWdICdF8CcR1P0RCO4xD+s5i8Pzpq8KHid/TQaajUzBRMB0GA1UdDgQWBBQAS56sNYWyao4k6DS/M81i+wqjIzAfBgNVHSMEGDAWgBQAS56sNYWyao4k6DS/M81i+wqjIzAPBgNVHRMBAf8EBTADAQH/MAUGAytlcANBAJWIicxVB6ynhjjkJgNtcL/kmixU7l/V1j/N0AtenDgT+yrMhDW9n9JC+Ze5qpX3Eu3VkdkpN3G9anmBXp3LtAk=";
// EDDSA Ed25519 CA-signed Cert
char cert_b64[]="MIHdMIGQAgEBMAUGAytlcDAZMRcwFQYDVQQDDA5NaWtlJ3Mgcm9vdCBDQTAeFw0yMzA1MDExNjA1NDhaFw0yNDA0MzAxNjA1NDhaMB0xGzAZBgNVBAMMEk1pa2UncyBzZXJ2ZXIgY2VydDAqMAUGAytlcAMhANvhwg8UhnGMGt0bKoGt5IHkvHwyEwWj4GkLQ7XIqJeVMAUGAytlcANBAESWzTJbz/YVwLFrDKVqYxHc86YGjPa8lekAC8UciIKu9d1Xoko3ssfhNiXkYkl3M0yEnIkD2F2DfGKbt8LSmQE=";

#endif

#if CHOICE==USE_ED448

// **CA is EDDSA Ed448 based. Self-signed cert
char ca_b64[]= "MIIBkjCCARKgAwIBAgIUWnfFe8sR7CGIz3eN1CfyHdTz14kwBQYDK2VxMBkxFzAVBgNVBAMMDk1pa2UncyByb290IENBMB4XDTIzMDUwMTE2NDQxMloXDTI0MDQzMDE2NDQxMlowGTEXMBUGA1UEAwwOTWlrZSdzIHJvb3QgQ0EwQzAFBgMrZXEDOgACd4YB/lGYUck4KxQMJ+lshkHnBuigmwPALPQGARv26SK/EOi0DIMMpyp3oG+pnPpnqbqtDtesCYCjUzBRMB0GA1UdDgQWBBRygDXbx5h57oo1D91LitQV2PE2dzAfBgNVHSMEGDAWgBRygDXbx5h57oo1D91LitQV2PE2dzAPBgNVHRMBAf8EBTADAQH/MAUGAytlcQNzAI17NGvKrGAH5hKLUHC1+Qv5RvT4IKlWg5GnRGTccc5tCrimveoMbu2KTlNXaOHS8y/sZT1qddukAFLzR/1ehZqOnYLM7dwlgYdksAx0olo5+/MYfj3hw5noh1pMObnJREfTPTSg1gqFI+gObB1UoSsBAA=="; 
// EDDSA Ed448 CA-signed Cert
char cert_b64[]="MIIBIzCBpAIBATAFBgMrZXEwGTEXMBUGA1UEAwwOTWlrZSdzIHJvb3QgQ0EwHhcNMjMwNTAxMTY0NjQzWhcNMjQwNDMwMTY0NjQzWjAYMRYwFAYDVQQDDA1NaWtlJ3Mgc2VydmVyMEMwBQYDK2VxAzoAgYh3CQP+EgId5/TZjAsuxh7Y9nPYtN5CYeN8vLjPuRqQncja3MyhRJaOrUEKSnBK+zYbkdXMQQwAMAUGAytlcQNzAPcm8DVSRZA1r0QqsSsHv6xBy1ASaoz4RFyelFMUD4f6ERMaxTzs0LKQHtcx5G9vqOxvQyCgkEu2AOcUQLtEXcoOSLH8fy0+5yEbbs6uPA1hi/oGpy580SR/5K5odY35fe1kwhz9YUvT4suTRHocnpcsAA==";
#endif

char io[5000];
octet IO = {0, sizeof(io), io};

#define MAXMODBYTES 72
#define MAXFFLEN 16

char sig[MAXMODBYTES * MAXFFLEN];
octet SIG = {0, sizeof(sig), sig};

char r[MAXMODBYTES];
octet R = {0, sizeof(r), r};

char s[MAXMODBYTES];
octet S = {0, sizeof(s), s};

char cakey[MAXMODBYTES * MAXFFLEN];
octet CAKEY = {0, sizeof(cakey), cakey};

char certkey[MAXMODBYTES * MAXFFLEN];
octet CERTKEY = {0, sizeof(certkey), certkey};

char h[5000];
octet H = {0, sizeof(h), h};

char hh[5000];
octet HH = {0, sizeof(hh), hh};

char hp[RFS_RSA2048];
octet HP = {0, sizeof(hp), hp};


void print_out(char *des, octet *c, int index, int len)
{
    int i;
    printf("%s [", des);
    for (i = 0; i < len; i++)
        printf("%c", c->val[index + i]);
    printf("]\n");
}

void print_date(char *des, octet *c, int index)
{
    int i = index;
    printf("%s [", des);
    if (i == 0) printf("]\n");
    else printf("20%c%c-%c%c-%c%c %c%c:%c%c:%c%c]\n", c->val[i], c->val[i + 1], c->val[i + 2], c->val[i + 3], c->val[i + 4], c->val[i + 5], c->val[i + 6], c->val[i + 7], c->val[i + 8], c->val[i + 9], c->val[i + 10], c->val[i + 11]);
}

int main()
{
    int res, len, sha;
    int c, ic;
    RSA2048::rsa_public_key PK;
    pktype st, ca, pt;

    printf("First check signature on self-signed cert and extract CA public key\n");
    OCT_frombase64(&IO, ca_b64);
    printf("CA Self-Signed Cert= \n");
    OCT_output(&IO);
    printf("\n");

    st = X509_extract_cert_sig(&IO, &SIG); // returns signature type

    if (st.type == 0)
    {
        printf("Unable to extract cert signature\n");
        return 0;
    }

    if (st.type == X509_ECC)
    {
        OCT_chop(&SIG, &S, SIG.len / 2);
        OCT_copy(&R, &SIG);
        printf("ECDSA SIG= \n");
        OCT_output(&R);
        OCT_output(&S);
        printf("\n");
    }

    if (st.type == X509_ECD)
    {
        printf("EDDSA SIG= \n");
        OCT_output(&SIG);
        printf("\n");
    }

    if (st.type == X509_RSA)
    {
        printf("RSA SIG= \n");
        OCT_output(&SIG);
        printf("\n");
    }

    if (st.hash == X509_H256) printf("Hashed with SHA256\n");
    if (st.hash == X509_H384) printf("Hashed with SHA384\n");
    if (st.hash == X509_H512) printf("Hashed with SHA512\n");

// Extract Cert from signed Cert

    c = X509_extract_cert(&IO, &H);

    printf("\nCert= \n");
    OCT_output(&H);
    printf("\n");

// show some details
    printf("Issuer Details\n");
    ic = X509_find_issuer(&H,&len);
    c = X509_find_entity_property(&H, &X509_ON, ic, &len);
    print_out((char *)"owner=", &H, c, len);
    c = X509_find_entity_property(&H, &X509_CN, ic, &len);
    print_out((char *)"country=", &H, c, len);
    c = X509_find_entity_property(&H, &X509_EN, ic, &len);
    print_out((char *)"email=", &H, c, len);
    c = X509_find_entity_property(&H, &X509_MN, ic, &len);
    print_out((char *)"Common Name=", &H, c, len);
    printf("\n");

    ca = X509_extract_public_key(&H, &CAKEY);

    if (ca.type == 0)
    {
        printf("Not supported by library\n");
        return 0;
    }
    //if (ca.type != st.type)
    if (!X509_self_signed(&H))
    {
        printf("Not self-signed\n");
    }

    if (ca.type == X509_ECD)
    {
        printf("EXTRACTED EDDSA PUBLIC KEY= \n");
        OCT_output(&CAKEY);
    }
    if (ca.type == X509_ECC)
    {
        printf("EXTRACTED ECDSA PUBLIC KEY= \n");
        OCT_output(&CAKEY);
    }
    if (ca.type == X509_RSA)
    {
        printf("EXTRACTED RSA PUBLIC KEY= \n");
        OCT_output(&CAKEY);
    }
    printf("\n");

// Cert is self-signed - so check signature

    printf("Checking Self-Signed Signature\n");
    if (ca.type == X509_ECC)
    {
        if (ca.curve != CHOICE)
        {
            printf("Curve is not supported\n");
            return 0;
        }
        res = NIST256::ECP_PUBLIC_KEY_VALIDATE(&CAKEY);
        if (res != 0)
        {
            printf("ECP Public Key is invalid!\n");
            return 0;
        }
        else printf("ECP Public Key is Valid\n");

        sha = 0;

        if (st.hash == X509_H256) sha = SHA256;
        if (st.hash == X509_H384) sha = SHA384;
        if (st.hash == X509_H512) sha = SHA512;
        if (sha == 0)
        {
            printf("Hash Function not supported\n");
            return 0;
        }

        if (NIST256::ECP_VP_DSA(sha, &CAKEY, &H, &R, &S) != 0)
        {
            printf("***ECDSA Verification Failed\n");
            return 0;
        }
        else
            printf("ECDSA Signature/Verification succeeded \n");
    }

    if (ca.type == X509_ECD)
    {
        if (ca.curve != CHOICE)
        {
            printf("Curve is not supported %d\n",ca.curve);
            return 0;
        }
        if (ca.curve == USE_ED25519)
        {
            if (!Ed25519::EDDSA_VERIFY(false,&CAKEY,NULL,&H,&SIG))
            {
                printf("***EDDSA Verification Failed\n");
                return 0;
            }
            else
                printf("EDDSA Signature/Verification succeeded \n");
        }
        if (ca.curve == USE_ED448)
        {
            if (!Ed448::EDDSA_VERIFY(false,&CAKEY,NULL,&H,&SIG))
            {
                printf("***EDDSA Verification Failed %d\n",SIG.len);
                return 0;
            }
            else
                printf("EDDSA Signature/Verification succeeded \n");
        }
    }
    if (ca.type == X509_RSA)
    {
        if (ca.curve != 2048)
        {
            printf("RSA bit size is not supported\n");
            return 0;
        }
        PK.e = 65537; // assuming this!
        RSA2048::RSA_fromOctet(PK.n, &CAKEY);

        sha = 0;

        if (st.hash == X509_H256) sha = SHA256;
        if (st.hash == X509_H384) sha = SHA384;
        if (st.hash == X509_H512) sha = SHA512;
        if (sha == 0)
        {
            printf("Hash Function not supported\n");
            return 0;
        }
        core::PKCS15(sha, &H, &HP);

        RSA2048::RSA_ENCRYPT(&PK, &SIG, &HH);

        if (OCT_comp(&HP, &HH))
            printf("RSA Signature/Verification succeeded \n");
        else
        {
            printf("***RSA Verification Failed\n");
            return 0;
        }
    }

    printf("\nNext check CA signature on cert, and extract public key\n");

    OCT_frombase64(&IO, cert_b64);
    printf("Example Cert= \n");
    OCT_output(&IO);
    printf("\n");

    st = X509_extract_cert_sig(&IO, &SIG);

    if (st.type == 0)
    {
        printf("Unable to check cert signature\n");
        return 0;
    }

    if (st.type == X509_ECC)
    {
        OCT_chop(&SIG, &S, SIG.len / 2);
        OCT_copy(&R, &SIG);
        printf("SIG= \n");
        OCT_output(&R);

        OCT_output(&S);

        printf("\n");
    }

    if (st.type == X509_ECD)
    {
        printf("SIG= \n");
        OCT_output(&SIG);
        printf("\n");
    }

    if (st.type == X509_RSA)
    {
        printf("SIG= \n");
        OCT_output(&SIG);
        printf("\n");
    }

    c = X509_extract_cert(&IO, &H);

    printf("Cert= \n");
    OCT_output(&H);
    printf("\n");

    printf("Subject Details\n");
    ic = X509_find_subject(&H,&len);
    c = X509_find_entity_property(&H, &X509_ON, ic, &len);
    print_out((char *)"owner=", &H, c, len);
    c = X509_find_entity_property(&H, &X509_CN, ic, &len);
    print_out((char *)"country=", &H, c, len);
    c = X509_find_entity_property(&H, &X509_EN, ic, &len);
    print_out((char *)"email=", &H, c, len);
    c = X509_find_entity_property(&H, &X509_MN, ic, &len);
    print_out((char *)"Common Name=", &H, c, len);
    printf("\n");

    ic = X509_find_validity(&H);
    c = X509_find_start_date(&H, ic);
    print_date((char *)"start date= ", &H, c);
    c = X509_find_expiry_date(&H, ic);
    print_date((char *)"expiry date=", &H, c);
    printf("\n");

    pt = X509_extract_public_key(&H, &CERTKEY);

    if (pt.type == 0)
    {
        printf("Not supported by library\n");
        return 0;
    }

    if (pt.type == X509_ECC)
    {
        printf("EXTRACTED ECDSA PUBLIC KEY= \n");
        OCT_output(&CERTKEY);
    }
    if (pt.type == X509_ECD)
    {
        printf("EXTRACTED EDDSA PUBLIC KEY= \n");
        OCT_output(&CERTKEY);
    }
    if (pt.type == X509_RSA)
    {
        printf("EXTRACTED RSA PUBLIC KEY= \n");
        OCT_output(&CERTKEY);
    }

    printf("\n");

    /* Check CA signature */

    if (ca.type == X509_ECC)
    {
        printf("Checking CA's ECDSA Signature on Cert\n");
        res = NIST256::ECP_PUBLIC_KEY_VALIDATE(&CAKEY);
        if (res != 0)
            printf("ECP Public Key is invalid!\n");
        else printf("ECP Public Key is Valid\n");

        sha = 0;

        if (st.hash == X509_H256) sha = SHA256;
        if (st.hash == X509_H384) sha = SHA384;
        if (st.hash == X509_H512) sha = SHA512;
        if (sha == 0)
        {
            printf("Hash Function not supported\n");
            return 0;
        }

        if (NIST256::ECP_VP_DSA(sha, &CAKEY, &H, &R, &S) != 0)
            printf("***ECDSA Verification Failed\n");
        else
            printf("ECDSA Signature/Verification succeeded \n");
    }

    if (ca.type == X509_ECD)
    {
        printf("Checking CA's EDDSA Signature on Cert\n");
        if (ca.curve == USE_ED25519)
        {
            if (!Ed25519::EDDSA_VERIFY(false,&CAKEY,NULL,&H,&SIG))
            {
                printf("***EDDSA Verification Failed\n");
                return 0;
            }
            else
                printf("EDDSA Signature/Verification succeeded \n");
        } 
        if (ca.curve == USE_ED448)
        {
            if (!Ed448::EDDSA_VERIFY(false,&CAKEY,NULL,&H,&SIG))
            {
                printf("***EDDSA Verification Failed\n");
                return 0;
            }
            else
                printf("EDDSA Signature/Verification succeeded \n");
        } 
    }

    if (ca.type == X509_RSA)
    {
        printf("Checking CA's RSA Signature on Cert\n");
        PK.e = 65537; // assuming this!
        RSA2048::RSA_fromOctet(PK.n, &CAKEY);

        sha = 0;

        if (st.hash == X509_H256) sha = SHA256;
        if (st.hash == X509_H384) sha = SHA384;
        if (st.hash == X509_H512) sha = SHA512;
        if (sha == 0)
        {
            printf("Hash Function not supported\n");
            return 0;
        }
        core::PKCS15(sha, &H, &HP);

        RSA_ENCRYPT(&PK, &SIG, &HH);

        if (OCT_comp(&HP, &HH))
            printf("RSA Signature/Verification succeeded \n");
        else
            printf("***RSA Verification Failed\n");

    }

    return 0;
}
