723 lines
21 KiB
C
723 lines
21 KiB
C
/**
|
|
* @file certValidate.c
|
|
* @version $Format:%h%d$
|
|
*
|
|
* Standalone certificate parsing and chain validation test.
|
|
*/
|
|
/*
|
|
* Copyright (c) 2013-2017 INSIDE Secure Corporation
|
|
* Copyright (c) PeerSec Networks, 2002-2011
|
|
* All Rights Reserved
|
|
*
|
|
* The latest version of this code is available at http://www.matrixssl.org
|
|
*
|
|
* This software is open source; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This General Public License does NOT permit incorporating this software
|
|
* into proprietary programs. If you are unable to comply with the GPL, a
|
|
* commercial license for this software may be purchased from INSIDE at
|
|
* http://www.insidesecure.com/
|
|
*
|
|
* This program is distributed in WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
* See the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
* http://www.gnu.org/copyleft/gpl.html
|
|
*/
|
|
/******************************************************************************/
|
|
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include "matrixssl/matrixsslApi.h"
|
|
#include "core/psUtil.h"
|
|
|
|
/****************************** Local Functions *******************************/
|
|
|
|
#if defined(USE_CERT_VALIDATE) && defined(MATRIX_USE_FILE_SYSTEM)
|
|
|
|
/*
|
|
@example
|
|
./certValidate -c '../../testkeys/RSA/2048_RSA_CA.pem' -n 'localhost' ../../testkeys/RSA/2048_RSA.pem
|
|
./certValidate ../../testkeys/RSA/2048_RSA_CA.pem
|
|
*/
|
|
static void usage(void)
|
|
{
|
|
printf(
|
|
"\nusage: certValidate { options } <file>\n"
|
|
" options can be one or more of the following:\n"
|
|
" -c <file> - Root CA certificate file\n"
|
|
" Default: Root CA validation skipped\n"
|
|
" -s [subject] - Subject name to validate (eg www.example.com)\n"
|
|
" Default: Subject validation skipped\n"
|
|
" -f [pem|eff|sonar] - File format. Non-pem options imply scan mode\n"
|
|
" Default: pem\n"
|
|
" additional scan mode options:\n"
|
|
" -l [lineno] - Process single line from scan file (first line is 1)\n"
|
|
" -d - Dump DER output for failed certs in scan file\n"
|
|
" -S - Produce/compare scan summary file in <file>.log\n"
|
|
" example: certValidate -c ca_certs.pem -s www.matrixssl.org cert_chain.pem\n"
|
|
"\n");
|
|
}
|
|
|
|
/* Command line parameters, point directly in to argv[] */
|
|
char *g_cafile = NULL; /* Optional root CA file */
|
|
char *g_certfile = NULL; /* Cert chain file */
|
|
char *g_subject = NULL; /* Optional cert subject name to validate */
|
|
|
|
int g_pem = 0; /* Process a PEM certifiate file */
|
|
int g_sonar = 0; /* Process a Sonar certifiate scan file */
|
|
int g_eff = 0; /* Process an EFF certifiate scan file */
|
|
int g_summary = 0; /* Output/compare a summary file */
|
|
int g_der = 0; /* Output DER files when appropriate */
|
|
int g_line = 0; /* Process a single line from certificate scan */
|
|
|
|
static int32_t process_cmd_options(int argc, char **argv)
|
|
{
|
|
int optionChar;
|
|
char *e;
|
|
|
|
while ((optionChar = getopt(argc, argv, "c:df:l:s:S")) != -1)
|
|
{
|
|
switch (optionChar)
|
|
{
|
|
|
|
/* Optional filenae containing trusted root certificate(s) */
|
|
case 'c':
|
|
if (g_cafile)
|
|
{
|
|
printf("Multiple options '-%c'\n", optionChar);
|
|
return -1;
|
|
}
|
|
g_cafile = optarg;
|
|
break;
|
|
|
|
/* Optional name to validate for certificate subject */
|
|
case 's':
|
|
if (g_subject)
|
|
{
|
|
printf("Multiple options '-%c'\n", optionChar);
|
|
return -1;
|
|
}
|
|
g_subject = optarg;
|
|
break;
|
|
|
|
/* Optional Project Sonar mode */
|
|
case 'f':
|
|
if (g_pem + g_eff + g_sonar != 0)
|
|
{
|
|
printf("Multiple options '-%c'\n", optionChar);
|
|
return -1;
|
|
}
|
|
if (strcmp(optarg, "pem") == 0)
|
|
{
|
|
g_pem = 1;
|
|
}
|
|
else if (strcmp(optarg, "eff") == 0)
|
|
{
|
|
g_eff = 1;
|
|
printf("NOT CURRENTLY SUPPORTED '-%c %s'\n", optionChar, optarg);
|
|
return -1;
|
|
}
|
|
else if (strcmp(optarg, "sonar") == 0)
|
|
{
|
|
g_sonar = 1;
|
|
}
|
|
else
|
|
{
|
|
printf("Unknown argument '-%c %s'\n", optionChar, optarg);
|
|
return -1;
|
|
}
|
|
break;
|
|
|
|
/* Select single line (when rprocessing scan files) */
|
|
case 'l':
|
|
g_line = strtol(optarg, &e, 10);
|
|
if (e != (optarg + strlen(optarg))
|
|
|| g_line <= 0)
|
|
{
|
|
printf("Invalid argument '-%c %s'\n", optionChar, optarg);
|
|
return -1;
|
|
}
|
|
break;
|
|
|
|
case 'S':
|
|
g_summary = 1;
|
|
break;
|
|
|
|
/* Dump DER files (when processing scan files) */
|
|
case 'd':
|
|
g_der = 1;
|
|
break;
|
|
|
|
default:
|
|
printf("Unknown option '-%c'\n", optionChar);
|
|
return -1;
|
|
}
|
|
}
|
|
if (optind != argc - 1)
|
|
{
|
|
printf("Exactly one cert chain file must be provided.\n");
|
|
return -1;
|
|
}
|
|
g_certfile = argv[optind];
|
|
if (g_pem + g_eff + g_sonar == 0)
|
|
{
|
|
g_pem = 1;
|
|
}
|
|
if (g_pem)
|
|
{
|
|
if (g_line > 0)
|
|
{
|
|
printf("Ignoring -l argument in PEM mode.\n");
|
|
}
|
|
if (g_der > 0)
|
|
{
|
|
printf("Ignoring -d argument in PEM mode.\n");
|
|
}
|
|
if (g_summary > 0)
|
|
{
|
|
printf("Ignoring -S argument in PEM mode.\n");
|
|
}
|
|
}
|
|
return PS_SUCCESS;
|
|
}
|
|
|
|
static char *flagstostr(int flags)
|
|
{
|
|
static char f[80]; /* Not reentrant, but good enough for this test */
|
|
char *s = f;
|
|
|
|
if (flags)
|
|
{
|
|
s += sprintf(s, " (");
|
|
if (flags & PS_CERT_AUTH_FAIL_KEY_USAGE_FLAG)
|
|
{
|
|
s += sprintf(s, "KEY_USAGE ");
|
|
}
|
|
if (flags & PS_CERT_AUTH_FAIL_EKU_FLAG)
|
|
{
|
|
s += sprintf(s, "EXTENDED_KEY_USAGE ");
|
|
}
|
|
if (flags & PS_CERT_AUTH_FAIL_SUBJECT_FLAG)
|
|
{
|
|
s += sprintf(s, "SUBJECT ");
|
|
}
|
|
if (flags & PS_CERT_AUTH_FAIL_DATE_FLAG)
|
|
{
|
|
s += sprintf(s, "DATE ");
|
|
}
|
|
sprintf(s, ")");
|
|
return f;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
static char *errtostr(int rc)
|
|
{
|
|
static char e[80]; /* Not reentrant, but good enough for this test */
|
|
|
|
switch (rc)
|
|
{
|
|
case 0:
|
|
case PS_CERT_AUTH_PASS:
|
|
return "PASS";
|
|
case PS_PARSE_FAIL:
|
|
return "FAIL Parse";
|
|
case PS_CERT_AUTH_FAIL_BC:
|
|
return "FAIL Basic Constraints";
|
|
case PS_CERT_AUTH_FAIL_DN:
|
|
return "FAIL Distinguished Name Match";
|
|
case PS_CERT_AUTH_FAIL_SIG:
|
|
return "FAIL Signature Validation";
|
|
case PS_CERT_AUTH_FAIL_REVOKED:
|
|
return "FAIL Certificate Revoked";
|
|
case PS_CERT_AUTH_FAIL:
|
|
return "FAIL Authentication Fail";
|
|
case PS_CERT_AUTH_FAIL_EXTENSION:
|
|
return "FAIL Extension";
|
|
case PS_CERT_AUTH_FAIL_PATH_LEN:
|
|
return "FAIL Path Length";
|
|
case PS_CERT_AUTH_FAIL_AUTHKEY:
|
|
return "FAIL Auth Key / Subject Key Match";
|
|
default:
|
|
sprintf(e, "FAIL %d", rc);
|
|
return e;
|
|
}
|
|
}
|
|
|
|
# define PARSE_STATUS(A) { A, #A, 0 }
|
|
|
|
static struct
|
|
{
|
|
parse_status_e id;
|
|
const char name[32];
|
|
int count;
|
|
} parse_status[] = {
|
|
PARSE_STATUS(PS_X509_PARSE_SUCCESS),
|
|
PARSE_STATUS(PS_X509_PARSE_FAIL),
|
|
PARSE_STATUS(PS_X509_WEAK_KEY),
|
|
PARSE_STATUS(PS_X509_UNSUPPORTED_VERSION),
|
|
PARSE_STATUS(PS_X509_UNSUPPORTED_ECC_CURVE),
|
|
PARSE_STATUS(PS_X509_UNSUPPORTED_SIG_ALG),
|
|
PARSE_STATUS(PS_X509_UNSUPPORTED_KEY_ALG),
|
|
PARSE_STATUS(PS_X509_UNSUPPORTED_EXT),
|
|
PARSE_STATUS(PS_X509_DATE),
|
|
PARSE_STATUS(PS_X509_MISSING_NAME),
|
|
PARSE_STATUS(PS_X509_MISSING_RSA),
|
|
PARSE_STATUS(PS_X509_ALG_ID),
|
|
PARSE_STATUS(PS_X509_ISSUER_DN),
|
|
PARSE_STATUS(PS_X509_SIGNATURE),
|
|
PARSE_STATUS(PS_X509_SUBJECT_DN),
|
|
PARSE_STATUS(PS_X509_EOF),
|
|
PARSE_STATUS(PS_X509_SIG_MISMATCH),
|
|
{ 0 } /* List terminator */
|
|
};
|
|
|
|
/******************************************************************************/
|
|
/**
|
|
Process internet wide certificate scans from Project Sonar.
|
|
Supports uncompressed *_certs.gz files.
|
|
@see https://scans.io/study/sonar.ssl
|
|
*/
|
|
static void write_summary(FILE *fp)
|
|
{
|
|
int i, total = 0;
|
|
|
|
for (i = 0; *parse_status[i].name; i++)
|
|
{
|
|
total += parse_status[i].count;
|
|
}
|
|
for (i = 0; *parse_status[i].name; i++)
|
|
{
|
|
fprintf(fp, "%12d %3d %s\n",
|
|
parse_status[i].count,
|
|
(parse_status[i].count * 100) / total,
|
|
parse_status[i].name);
|
|
}
|
|
}
|
|
|
|
# define CERT_MAX_BYTES (1024 * 32)/* Must be < 64K for base64decode */
|
|
|
|
static int32_t process_sonar(void)
|
|
{
|
|
FILE *fp, *wfp;
|
|
char buf[CERT_MAX_BYTES];
|
|
char certbuf[CERT_MAX_BYTES]; /* Could be smaller due to base64 decode */
|
|
char outfile[32] = { 0 };
|
|
char *certhash, *cert64;
|
|
int32_t certhashlen, cert64len;
|
|
psSize_t certbuflen;
|
|
int32_t rc = 0, line = 0;
|
|
psX509Cert_t *cert;
|
|
|
|
if ((fp = fopen(g_certfile, "r")) == NULL)
|
|
{
|
|
perror("Error opening file");
|
|
return -1;
|
|
}
|
|
while (fgets(buf, CERT_MAX_BYTES, fp) != NULL)
|
|
{
|
|
line++;
|
|
if (g_line > 0)
|
|
{
|
|
if (line < g_line)
|
|
{
|
|
continue; /* Skip lines before selected one */
|
|
}
|
|
if (line > g_line)
|
|
{
|
|
break; /* Stop processing after selected line */
|
|
}
|
|
}
|
|
certhash = buf;
|
|
cert64 = strchr(buf, ',');
|
|
if (*cert64 == '\0')
|
|
{
|
|
printf("CSV parse failed on line %d\n", line);
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
*cert64 = '\0';
|
|
cert64++;
|
|
certhashlen = strlen(certhash);
|
|
cert64len = strlen(cert64);
|
|
if (certhashlen + cert64len + 2 >= CERT_MAX_BYTES)
|
|
{
|
|
printf("CERT_MAX_BYTES exceeded on line %d\n", line);
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
certbuflen = CERT_MAX_BYTES;
|
|
if (psBase64decode((unsigned char *) cert64, cert64len, (unsigned char *) certbuf, &certbuflen) != 0)
|
|
{
|
|
printf("Base64 parse failed on line %d\n", line);
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
if (certbuflen > SSL_MAX_PLAINTEXT_LEN)
|
|
{
|
|
printf("WARNING, %d byte cert\n", certbuflen);
|
|
}
|
|
if ((rc = psX509ParseCert(NULL, (unsigned char *) certbuf, certbuflen, &cert, 0)) < 0)
|
|
{
|
|
/* Output the cert we couldn't process. It can be viewd by openssl using:
|
|
openssl x509 -inform der -text -in SONAR_<num>.der */
|
|
if (!cert)
|
|
{
|
|
printf("X509 Memory allocation failed for line %d\n", line);
|
|
fclose(fp);
|
|
return -1;
|
|
}
|
|
switch (cert->parseStatus)
|
|
{
|
|
/* Additional diagnostics for certificate failures */
|
|
case PS_X509_MISSING_NAME:
|
|
/* TODO print other name components */
|
|
break;
|
|
case PS_X509_DATE:
|
|
if (!g_summary)
|
|
{
|
|
printf("%s-%s\n", cert->notBefore, cert->notAfter);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (!g_summary)
|
|
{
|
|
printf("%12d:X509 %s (%s)\n", line, errtostr(rc),
|
|
parse_status[cert->parseStatus].name);
|
|
}
|
|
if (g_der)
|
|
{
|
|
snprintf(outfile, 31, "SONAR_%012d.der", line);
|
|
if ((wfp = fopen(outfile, "w")) != NULL)
|
|
{
|
|
if (fwrite(certbuf, certbuflen, 1, wfp) != 1)
|
|
{
|
|
perror("Error writing file");
|
|
}
|
|
fclose(wfp);
|
|
}
|
|
else
|
|
{
|
|
perror("Error creating file");
|
|
}
|
|
}
|
|
parse_status[cert->parseStatus].count++;
|
|
psX509FreeCert(cert);
|
|
continue;
|
|
}
|
|
psAssert(cert->authStatus == 0);
|
|
if (!g_summary)
|
|
{
|
|
printf("%12d:%s\n", line, cert->subject.commonName);
|
|
}
|
|
parse_status[cert->parseStatus].count++;
|
|
psX509FreeCert(cert);
|
|
}
|
|
fclose(fp);
|
|
if (g_line > 0)
|
|
{
|
|
if (line == (g_line + 1))
|
|
{
|
|
printf("Processed line %d of %s\n", g_line, g_certfile);
|
|
}
|
|
else
|
|
{
|
|
printf("Error, line %d not found in %s\n", g_line, g_certfile);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printf("%d certificates processed\n", line);
|
|
}
|
|
if (!line)
|
|
{
|
|
return 0;
|
|
}
|
|
printf("Cert Count %% Parse Status\n");
|
|
if (g_summary)
|
|
{
|
|
FILE *lfp = NULL, *tfp = NULL;
|
|
char *lfname = NULL;
|
|
char *tfname = NULL;
|
|
lfname = malloc(strlen(g_certfile) + 5); /* 5 is .log\0 */
|
|
sprintf(lfname, "%s.log", g_certfile);
|
|
if ((lfp = fopen(lfname, "r")) == NULL)
|
|
{
|
|
/* No existing log file, create it */
|
|
if ((lfp = fopen(lfname, "w")) == NULL)
|
|
{
|
|
perror("Error opening file");
|
|
free(lfname);
|
|
return -1;
|
|
}
|
|
write_summary(lfp);
|
|
fclose(lfp);
|
|
printf("Wrote log file %s\n", lfname);
|
|
}
|
|
else
|
|
{
|
|
int match = 1;
|
|
/* Found log file, create a tmp comparison file */
|
|
tfname = malloc(strlen(lfname) + 5); /* 5 is .tmp\0 */
|
|
sprintf(tfname, "%s.tmp", lfname);
|
|
if ((tfp = fopen(tfname, "w+")) == NULL)
|
|
{
|
|
perror("Error opening file");
|
|
fclose(lfp);
|
|
free(lfname);
|
|
free(tfname);
|
|
return -1;
|
|
}
|
|
write_summary(tfp);
|
|
rewind(tfp);
|
|
while (fgets(buf, CERT_MAX_BYTES, lfp) != NULL)
|
|
{
|
|
if (fgets(certbuf, CERT_MAX_BYTES, tfp) == NULL)
|
|
{
|
|
match = 0;
|
|
break;
|
|
}
|
|
if (strncmp(buf, certbuf, CERT_MAX_BYTES) != 0)
|
|
{
|
|
match = 0;
|
|
break;
|
|
}
|
|
}
|
|
if (fgets(certbuf, CERT_MAX_BYTES, tfp) != NULL)
|
|
{
|
|
match = 0;
|
|
}
|
|
fclose(lfp);
|
|
fclose(tfp);
|
|
if (unlink(tfname) < 0)
|
|
{
|
|
perror("Error unlink file");
|
|
free(lfname);
|
|
free(tfname);
|
|
return -1;
|
|
}
|
|
if (match)
|
|
{
|
|
printf("MATCH Success for %s\n", lfname);
|
|
}
|
|
else
|
|
{
|
|
printf("MATCH FAIL for %s\n", lfname);
|
|
free(lfname);
|
|
free(tfname);
|
|
return -1;
|
|
}
|
|
}
|
|
free(lfname);
|
|
free(tfname);
|
|
}
|
|
else
|
|
{
|
|
write_summary(stdout);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*
|
|
Certificate validation test
|
|
*/
|
|
int main(int argc, char **argv)
|
|
{
|
|
psX509Cert_t *trusted, *chain, *cert;
|
|
psPool_t *pool;
|
|
int32 rc, i;
|
|
uint32 faildate, flags, depth;
|
|
|
|
rc = -1;
|
|
faildate = 0;
|
|
pool = NULL;
|
|
trusted = chain = NULL;
|
|
|
|
if (process_cmd_options(argc, argv) < 0)
|
|
{
|
|
usage();
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if ((rc = matrixSslOpen()) < 0)
|
|
{
|
|
fprintf(stderr, "MatrixSSL library init failure. Exiting\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if (g_cafile)
|
|
{
|
|
if ((rc = psX509ParseCertFile(pool, g_cafile, &trusted, 0)) < 0)
|
|
{
|
|
if (rc == PS_PLATFORM_FAIL)
|
|
{
|
|
printf("FAIL open file %s %d\n", g_cafile, rc);
|
|
}
|
|
else
|
|
{
|
|
printf("FAIL parse %s %d\n", g_cafile, rc);
|
|
}
|
|
goto L_EXIT;
|
|
}
|
|
printf(" Loaded root file %s\n", g_cafile);
|
|
for (cert = trusted, i = 0; cert != NULL; cert = cert->next, i++)
|
|
{
|
|
printf(" [%d]:%s\n", i, cert->subject.commonName);
|
|
psAssert(cert->authStatus == 0);
|
|
faildate |= cert->authFailFlags & PS_CERT_AUTH_FAIL_DATE_FLAG;
|
|
psAssert((cert->authFailFlags & ~faildate) == 0);
|
|
}
|
|
}
|
|
|
|
if (g_sonar)
|
|
{
|
|
rc = process_sonar();
|
|
goto L_EXIT;
|
|
}
|
|
|
|
if ((rc = psX509ParseCertFile(pool, g_certfile, &chain, 0)) < 0)
|
|
{
|
|
if (rc == PS_PLATFORM_FAIL)
|
|
{
|
|
printf("FAIL open file %s %d\n", g_certfile, rc);
|
|
}
|
|
else
|
|
{
|
|
printf("FAIL parse %s %d\n", g_certfile, rc);
|
|
}
|
|
goto L_EXIT;
|
|
}
|
|
printf(" Loaded chain file %s\n", g_certfile);
|
|
for (cert = chain, i = 0; cert != NULL; cert = cert->next, i++)
|
|
{
|
|
printf(" [%d]:%s\n", i, cert->subject.commonName);
|
|
psAssert(cert->authStatus == 0);
|
|
faildate |= cert->authFailFlags & PS_CERT_AUTH_FAIL_DATE_FLAG;
|
|
psAssert((cert->authFailFlags & ~faildate) == 0);
|
|
}
|
|
|
|
if (g_subject)
|
|
{
|
|
if (psX509ValidateGeneralName(g_subject) < 0)
|
|
{
|
|
printf("FAIL validate general name %s\n", g_subject);
|
|
goto L_EXIT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printf("WARN subject not provided, SUBJ validation will be skipped\n");
|
|
}
|
|
rc = matrixValidateCerts(pool, chain, trusted, g_subject, &cert, NULL, NULL);
|
|
if (rc < 0)
|
|
{
|
|
/* This check is here rather than above to allow self signed certs to pass without
|
|
specifiying a CA */
|
|
if (!trusted && rc == PS_CERT_AUTH_FAIL_DN)
|
|
{
|
|
printf("WARN Certificates parsed, but cannot be validated against any root cert\n");
|
|
rc = PS_SUCCESS;
|
|
goto L_EXIT;
|
|
}
|
|
printf("%s\n", errtostr(rc));
|
|
for (cert = chain, i = 0; cert != NULL; cert = cert->next, i++)
|
|
{
|
|
printf(" Validate:%s[%d]:%s FAIL %d, status=%d, flags=%u\n",
|
|
g_certfile, i, cert->subject.commonName, rc,
|
|
cert->authStatus, cert->authFailFlags);
|
|
if (cert->authStatus != PS_CERT_AUTH_PASS)
|
|
{
|
|
printf(" authStatus %s\n", errtostr(cert->authStatus));
|
|
}
|
|
if (cert->authFailFlags)
|
|
{
|
|
printf(" authFailFlags %s\n", flagstostr(cert->authFailFlags));
|
|
}
|
|
}
|
|
goto L_EXIT;
|
|
}
|
|
/* If faildate is set and we don't have an error in rc... */
|
|
psAssert(faildate == 0);
|
|
|
|
flags = depth = 0;
|
|
if (cert)
|
|
{
|
|
printf(" Validate %s:%s rc %d\n", g_certfile, cert->subject.commonName, rc);
|
|
}
|
|
for (cert = chain, i = 0; cert != NULL; cert = cert->next, i++)
|
|
{
|
|
printf(" [%d] authStatus=%d, authFailFlags=%u\n",
|
|
i, cert->authStatus, cert->authFailFlags);
|
|
if (cert->authStatus != PS_CERT_AUTH_PASS)
|
|
{
|
|
depth = i;
|
|
rc = cert->authStatus;
|
|
flags |= cert->authFailFlags;
|
|
}
|
|
else
|
|
{
|
|
psAssert(cert->authFailFlags == 0);
|
|
}
|
|
}
|
|
if (rc < 0)
|
|
{
|
|
printf("%s%s in %s[%d]\n", errtostr(rc), flagstostr(flags),
|
|
g_certfile, depth);
|
|
goto L_EXIT;
|
|
}
|
|
printf("PASS\n");
|
|
|
|
L_EXIT:
|
|
if (trusted)
|
|
{
|
|
psX509FreeCert(trusted);
|
|
}
|
|
if (chain)
|
|
{
|
|
psX509FreeCert(chain);
|
|
}
|
|
matrixSslClose();
|
|
|
|
if (rc < 0)
|
|
{
|
|
return EXIT_FAILURE;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#else
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
# ifndef USE_CERT_PARSE
|
|
printf("Please enable USE_CERT_PARSE for this test\n");
|
|
# endif
|
|
# ifndef USE_MATRIX_FILE_SYSTEM
|
|
printf("Please enable USE_MATRIX_FILE_SYSTEM for this test\n");
|
|
# endif
|
|
# ifdef USE_ONLY_PSK_CIPHER_SUITE
|
|
printf("Not applicable when USE_ONLY_PSK_CIPHER_SUITE defined\n");
|
|
# endif
|
|
# if !defined(USE_CLIENT_SIDE_SSL) && !defined(USE_CLIENT_AUTH)
|
|
printf("Certificate validation requires either USE_CLIENT_SIDE_SSL " \
|
|
"or USE_CLIENT_AUTH. Please enable one of those\n");
|
|
# endif
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
#endif /* USE_CERT_VALIDATE && MATRIX_USE_FILE_SYSTEM */
|
|
|
|
/******************************************************************************/
|
|
|