/* cert-basic.c - basic test for the certificate management.
* Copyright (C) 2001, 2002, 2004, 2005 g10 Code GmbH
*
* This file is part of KSBA.
*
* KSBA is free software; 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 3 of the License, or
* (at your option) any later version.
*
* KSBA is distributed in the hope that it will be useful,
* but 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, see .
*/
#include
#include
#include
#include
#include
#include "../src/ksba.h"
#define _KSBA_VISIBILITY_DEFAULT /* */
#include "../src/keyinfo.h"
#include "oidtranstbl.h"
#include "t-common.h"
#ifdef __MINGW32CE__
#define getenv(a) (NULL)
#endif
#define digitp(p) (*(p) >= '0' && *(p) <= '9')
#define fail_if_err(a) do { if(a) { \
fprintf (stderr, "%s:%d: KSBA error: %s\n", \
__FILE__, __LINE__, gpg_strerror(a)); \
exit (1); } \
} while(0)
#define fail_if_err2(f, a) do { if(a) {\
fprintf (stderr, "%s:%d: KSBA error on file `%s': %s\n", \
__FILE__, __LINE__, (f), gpg_strerror(a)); \
exit (1); } \
} while(0)
#define xfree(a) ksba_free (a)
static int verbose;
static int errorcount = 0;
static void
print_names (int indent, ksba_name_t name)
{
int idx;
const char *s;
int indent_all;
if ((indent_all = (indent < 0)))
indent = - indent;
if (!name)
{
fputs ("none\n", stdout);
return;
}
for (idx=0; (s = ksba_name_enum (name, idx)); idx++)
{
char *p = ksba_name_get_uri (name, idx);
printf ("%*s%s\n", idx||indent_all?indent:0, "", p?p:s);
xfree (p);
}
}
/* Return the description for OID; if no description is available
NULL is returned. */
static const char *
get_oid_desc (const char *oid)
{
int i;
if (oid)
for (i=0; oidtranstbl[i].oid; i++)
if (!strcmp (oidtranstbl[i].oid, oid))
return oidtranstbl[i].desc;
return NULL;
}
static void
print_oid_and_desc (const char *oid, int with_lf)
{
const char *s = get_oid_desc (oid);
printf ("%s%s%s%s",
oid, s?" (":"", s?s:"", s?")":"");
if (with_lf)
putchar ('\n');
}
static void
print_oid_list (int indent, char *list)
{
char *lf;
int indent_all, c;
size_t n;
if ((indent_all = (indent < 0)))
indent = - indent;
while (*list)
{
printf ("%*s", indent_all?indent:0, "");
indent_all = 1;
if (!(lf = strchr (list, '\n')))
lf = list + strlen (list);
n = strspn (list, "0123456789.");
c = list[n];
list[n] = 0;
print_oid_and_desc (list, 0);
list[n] = c;
c = *lf;
*lf = 0;
printf (" %s\n", list+n);
*lf = c;
list = *lf? (lf+1):lf;
}
}
static void
list_extensions (ksba_cert_t cert)
{
gpg_error_t err;
const char *oid;
int idx, crit, is_ca, pathlen;
size_t off, len;
unsigned int usage, reason;
char *string, *p;
ksba_name_t name1, name2;
ksba_sexp_t serial;
ksba_sexp_t keyid;
for (idx=0; !(err=ksba_cert_get_extension (cert, idx,
&oid, &crit, &off, &len));idx++)
{
const char *s = get_oid_desc (oid);
printf ("Extn: %s%s%s%s at %d with length %d %s\n",
oid, s?" (":"", s?s:"", s?")":"",
(int)off, (int)len, crit? "(critical)":"");
}
if (err && gpg_err_code (err) != GPG_ERR_EOF )
{
fprintf (stderr,
"%s:%d: enumerating extensions failed: %s\n",
__FILE__, __LINE__, gpg_strerror (err));
errorcount++;
}
/* subjectKeyIdentifier */
err = ksba_cert_get_subj_key_id (cert, NULL, &keyid);
if (!err || gpg_err_code (err) == GPG_ERR_NO_DATA)
{
fputs ("SubjectKeyIdentifier: ", stdout);
if (gpg_err_code (err) == GPG_ERR_NO_DATA)
fputs ("none", stdout);
else
{
print_sexp (keyid);
ksba_free (keyid);
}
putchar ('\n');
}
/* authorityKeyIdentifier */
err = ksba_cert_get_auth_key_id (cert, &keyid, &name1, &serial);
if (!err || gpg_err_code (err) == GPG_ERR_NO_DATA)
{
fputs ("AuthorityKeyIdentifier: ", stdout);
if (gpg_err_code (err) == GPG_ERR_NO_DATA)
fputs ("none\n", stdout);
else
{
if (name1)
{
print_names (24, name1);
ksba_name_release (name1);
fputs (" serial: ", stdout);
print_sexp (serial);
ksba_free (serial);
}
putchar ('\n');
if (keyid)
{
fputs (" keyIdentifier: ", stdout);
print_sexp (keyid);
ksba_free (keyid);
putchar ('\n');
}
}
}
else
{
fprintf (stderr, "%s:%d: ksba_cert_get_auth_key_id: %s\n",
__FILE__, __LINE__, gpg_strerror (err));
errorcount++;
}
err = ksba_cert_is_ca (cert, &is_ca, &pathlen);
if (err)
{
fprintf (stderr, "%s:%d: ksba_cert_is_ca failed: %s\n",
__FILE__, __LINE__, gpg_strerror (err));
errorcount++;
}
else if (is_ca)
printf ("This is a CA certificate with a path length of %d\n", pathlen);
err = ksba_cert_get_key_usage (cert, &usage);
if (gpg_err_code (err) == GPG_ERR_NO_DATA)
printf ("KeyUsage: Not specified\n");
else if (err)
{
fprintf (stderr, "%s:%d: ksba_cert_get_key_usage failed: %s\n",
__FILE__, __LINE__, gpg_strerror (err));
errorcount++;
}
else
{
fputs ("KeyUsage:", stdout);
if ( (usage & KSBA_KEYUSAGE_DIGITAL_SIGNATURE))
fputs (" digitalSignature", stdout);
if ( (usage & KSBA_KEYUSAGE_NON_REPUDIATION))
fputs (" nonRepudiation", stdout);
if ( (usage & KSBA_KEYUSAGE_KEY_ENCIPHERMENT))
fputs (" keyEncipherment", stdout);
if ( (usage & KSBA_KEYUSAGE_DATA_ENCIPHERMENT))
fputs (" dataEncripherment", stdout);
if ( (usage & KSBA_KEYUSAGE_KEY_AGREEMENT))
fputs (" keyAgreement", stdout);
if ( (usage & KSBA_KEYUSAGE_KEY_CERT_SIGN))
fputs (" certSign", stdout);
if ( (usage & KSBA_KEYUSAGE_CRL_SIGN))
fputs (" crlSign", stdout);
if ( (usage & KSBA_KEYUSAGE_ENCIPHER_ONLY))
fputs (" encipherOnly", stdout);
if ( (usage & KSBA_KEYUSAGE_DECIPHER_ONLY))
fputs (" decipherOnly", stdout);
putchar ('\n');
}
err = ksba_cert_get_ext_key_usages (cert, &string);
if (gpg_err_code (err) == GPG_ERR_NO_DATA)
printf ("ExtKeyUsages: none\n");
else if (err)
{
fprintf (stderr, "%s:%d: ksba_cert_ext_key_usages failed: %s\n",
__FILE__, __LINE__, gpg_strerror (err));
errorcount++;
}
else
{
fputs ("ExtKeyUsages: ", stdout);
print_oid_list (14, string);
xfree (string);
}
err = ksba_cert_get_cert_policies (cert, &string);
if (gpg_err_code (err) == GPG_ERR_NO_DATA)
printf ("CertificatePolicies: none\n");
else if (err)
{
fprintf (stderr, "%s:%d: ksba_cert_get_cert_policies failed: %s\n",
__FILE__, __LINE__, gpg_strerror (err));
errorcount++;
}
else
{
/* for display purposes we replace the linefeeds by commas */
for (p=string; *p; p++)
{
if (*p == '\n')
*p = ',';
}
fputs ("CertificatePolicies: ", stdout);
print_oid_list (21, string);
xfree (string);
}
/* CRL distribution point */
for (idx=0; !(err=ksba_cert_get_crl_dist_point (cert, idx,
&name1, &name2,
&reason));idx++)
{
fputs ("CRLDistPoint: ", stdout);
print_names (14, name1);
fputs (" reasons:", stdout);
if ( !reason )
fputs (" none", stdout);
if ( (reason & KSBA_CRLREASON_UNSPECIFIED))
fputs (" unused", stdout);
if ( (reason & KSBA_CRLREASON_KEY_COMPROMISE))
fputs (" keyCompromise", stdout);
if ( (reason & KSBA_CRLREASON_CA_COMPROMISE))
fputs (" caCompromise", stdout);
if ( (reason & KSBA_CRLREASON_AFFILIATION_CHANGED))
fputs (" affiliationChanged", stdout);
if ( (reason & KSBA_CRLREASON_SUPERSEDED))
fputs (" superseded", stdout);
if ( (reason & KSBA_CRLREASON_CESSATION_OF_OPERATION))
fputs (" cessationOfOperation", stdout);
if ( (reason & KSBA_CRLREASON_CERTIFICATE_HOLD))
fputs (" certificateHold", stdout);
putchar ('\n');
fputs (" issuer: ", stdout);
print_names (14, name2);
ksba_name_release (name1);
ksba_name_release (name2);
}
if (err && gpg_err_code (err) != GPG_ERR_EOF)
{
fprintf (stderr, "%s:%d: ksba_cert_get_crl_dist_point failed: %s\n",
__FILE__, __LINE__, gpg_strerror (err));
errorcount++;
}
/* authorityInfoAccess. */
for (idx=0; !(err=ksba_cert_get_authority_info_access (cert, idx,
&string, &name1))
; idx++)
{
fputs ("authorityInfoAccess: ", stdout);
print_oid_and_desc (string, 1);
print_names (-21, name1);
ksba_name_release (name1);
ksba_free (string);
}
if (err && gpg_err_code (err) != GPG_ERR_EOF)
{
fprintf (stderr, "%s:%d: "
"ksba_cert_get_authority_info_access failed: %s\n",
__FILE__, __LINE__, gpg_strerror (err));
errorcount++;
}
/* subjectInfoAccess. */
for (idx=0; !(err=ksba_cert_get_subject_info_access (cert, idx,
&string, &name1))
; idx++)
{
fputs ("subjectInfoAccess: ", stdout);
print_oid_and_desc (string, 1);
print_names (-19, name1);
ksba_name_release (name1);
ksba_free (string);
}
if (err && gpg_err_code (err) != GPG_ERR_EOF)
{
fprintf (stderr, "%s:%d: "
"ksba_cert_get_subject_info_access failed: %s\n",
__FILE__, __LINE__, gpg_strerror (err));
errorcount++;
}
}
static void
one_file (const char *fname)
{
gpg_error_t err;
FILE *fp;
ksba_reader_t r;
ksba_cert_t cert;
char *dn;
ksba_isotime_t t;
int idx;
ksba_sexp_t sexp;
const char *oid, *s;
fp = fopen (fname, "rb");
if (!fp)
{
fprintf (stderr, "%s:%d: can't open `%s': %s\n",
__FILE__, __LINE__, fname, strerror (errno));
exit (1);
}
err = ksba_reader_new (&r);
if (err)
fail_if_err (err);
err = ksba_reader_set_file (r, fp);
fail_if_err (err);
err = ksba_cert_new (&cert);
if (err)
fail_if_err (err);
err = ksba_cert_read_der (cert, r);
fail_if_err2 (fname, err);
printf ("Certificate in `%s':\n", fname);
sexp = ksba_cert_get_serial (cert);
fputs (" serial....: ", stdout);
print_sexp (sexp);
ksba_free (sexp);
putchar ('\n');
for (idx=0;(dn = ksba_cert_get_issuer (cert, idx));idx++)
{
fputs (idx?" aka: ":" issuer....: ", stdout);
print_dn (dn);
ksba_free (dn);
putchar ('\n');
}
for (idx=0;(dn = ksba_cert_get_subject (cert, idx));idx++)
{
fputs (idx?" aka: ":" subject...: ", stdout);
print_dn (dn);
ksba_free (dn);
putchar ('\n');
}
ksba_cert_get_validity (cert, 0, t);
fputs (" notBefore.: ", stdout);
print_time (t);
putchar ('\n');
ksba_cert_get_validity (cert, 1, t);
fputs (" notAfter..: ", stdout);
print_time (t);
putchar ('\n');
oid = ksba_cert_get_digest_algo (cert);
s = get_oid_desc (oid);
printf (" hash algo.: %s%s%s%s\n",
oid?oid:"(null)", s?" (":"",s?s:"",s?")":"");
/* Under Windows the _ksba_keyinfo_from_sexp are not exported. */
#ifndef __WIN32
/* check that the sexp to keyinfo conversion works */
{
ksba_sexp_t public;
public = ksba_cert_get_public_key (cert);
if (!public)
{
fprintf (stderr, "%s:%d: public key not found\n",
__FILE__, __LINE__);
errorcount++;
}
else
{
unsigned char *der;
size_t derlen;
if (verbose)
{
fputs (" pubkey....: ", stdout);
print_sexp (public);
putchar ('\n');
}
err = _ksba_keyinfo_from_sexp (public, &der, &derlen);
if (err)
{
fprintf (stderr, "%s:%d: converting public key failed: %s\n",
__FILE__, __LINE__, gpg_strerror (err));
errorcount++;
}
else
{
ksba_sexp_t tmp;
if (verbose)
{
fputs (" pubkey-DER: ", stdout);
print_hex (der, derlen);
putchar ('\n');
}
err = _ksba_keyinfo_to_sexp (der, derlen, &tmp);
if (err)
{
fprintf (stderr,
"%s:%d: re-converting public key failed: %s\n",
__FILE__, __LINE__, gpg_strerror (err));
errorcount++;
}
else
{
unsigned char *der2;
size_t derlen2;
err = _ksba_keyinfo_from_sexp (tmp, &der2, &derlen2);
if (err)
{
fprintf (stderr, "%s:%d: re-re-converting "
"public key failed: %s\n",
__FILE__, __LINE__, gpg_strerror (err));
errorcount++;
}
else if (derlen != derlen2 || memcmp (der, der2, derlen))
{
fprintf (stderr, "%s:%d: mismatch after "
"re-re-converting public key\n",
__FILE__, __LINE__);
errorcount++;
xfree (der2);
} else {
/* Don't leak memory if everything is ok. */
xfree (der2);
}
xfree (tmp);
}
xfree (der);
}
ksba_free (public);
}
}
#endif
if (verbose)
{
sexp = ksba_cert_get_sig_val (cert);
fputs (" sigval....: ", stdout);
print_sexp (sexp);
ksba_free (sexp);
putchar ('\n');
}
list_extensions (cert);
ksba_cert_release (cert);
err = ksba_cert_new (&cert);
if (err)
fail_if_err (err);
err = ksba_cert_read_der (cert, r);
if (err && gpg_err_code (err) != GPG_ERR_EOF)
{
fprintf (stderr, "%s:%d: expected EOF but got: %s\n",
__FILE__, __LINE__, gpg_strerror (err));
errorcount++;
}
putchar ('\n');
ksba_cert_release (cert);
ksba_reader_release (r);
fclose (fp);
}
int
main (int argc, char **argv)
{
const char *srcdir = getenv ("srcdir");
if (!srcdir)
srcdir = ".";
if (argc)
{
argc--; argv++;
}
if (argc && !strcmp (*argv, "--verbose"))
{
verbose = 1;
argc--; argv++;
}
if (argc)
{
for (; argc; argc--, argv++)
one_file (*argv);
}
else
{
const char *files[] = {
"cert_dfn_pca01.der",
"cert_dfn_pca15.der",
"cert_g10code_test1.der",
NULL
};
int idx;
for (idx=0; files[idx]; idx++)
{
char *fname;
fname = xmalloc (strlen (srcdir) + 1 + strlen (files[idx]) + 1);
strcpy (fname, srcdir);
strcat (fname, "/");
strcat (fname, files[idx]);
one_file (fname);
ksba_free (fname);
}
}
return !!errorcount;
}