1178825Sdfr/*
2233294Sstas * Copyright (c) 2004 - 2007 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9178825Sdfr *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
20178825Sdfr *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34178825Sdfr#include "hx_locl.h"
35178825Sdfr
36178825Sdfr/**
37178825Sdfr * @page page_print Hx509 printing functions
38178825Sdfr *
39178825Sdfr * See the library functions here: @ref hx509_print
40178825Sdfr */
41178825Sdfr
42178825Sdfrstruct hx509_validate_ctx_data {
43178825Sdfr    int flags;
44178825Sdfr    hx509_vprint_func vprint_func;
45178825Sdfr    void *ctx;
46178825Sdfr};
47178825Sdfr
48178825Sdfrstruct cert_status {
49178825Sdfr    unsigned int selfsigned:1;
50178825Sdfr    unsigned int isca:1;
51178825Sdfr    unsigned int isproxy:1;
52178825Sdfr    unsigned int haveSAN:1;
53178825Sdfr    unsigned int haveIAN:1;
54178825Sdfr    unsigned int haveSKI:1;
55178825Sdfr    unsigned int haveAKI:1;
56178825Sdfr    unsigned int haveCRLDP:1;
57178825Sdfr};
58178825Sdfr
59178825Sdfr
60178825Sdfr/*
61178825Sdfr *
62178825Sdfr */
63178825Sdfr
64178825Sdfrstatic int
65178825SdfrTime2string(const Time *T, char **str)
66178825Sdfr{
67178825Sdfr    time_t t;
68178825Sdfr    char *s;
69178825Sdfr    struct tm *tm;
70178825Sdfr
71178825Sdfr    *str = NULL;
72178825Sdfr    t = _hx509_Time2time_t(T);
73178825Sdfr    tm = gmtime (&t);
74178825Sdfr    s = malloc(30);
75178825Sdfr    if (s == NULL)
76178825Sdfr	return ENOMEM;
77178825Sdfr    strftime(s, 30, "%Y-%m-%d %H:%M:%S", tm);
78178825Sdfr    *str = s;
79178825Sdfr    return 0;
80178825Sdfr}
81178825Sdfr
82178825Sdfr/**
83178825Sdfr * Helper function to print on stdout for:
84178825Sdfr * - hx509_oid_print(),
85178825Sdfr * - hx509_bitstring_print(),
86178825Sdfr * - hx509_validate_ctx_set_print().
87178825Sdfr *
88178825Sdfr * @param ctx the context to the print function. If the ctx is NULL,
89178825Sdfr * stdout is used.
90178825Sdfr * @param fmt the printing format.
91178825Sdfr * @param va the argumet list.
92178825Sdfr *
93178825Sdfr * @ingroup hx509_print
94178825Sdfr */
95178825Sdfr
96178825Sdfrvoid
97178825Sdfrhx509_print_stdout(void *ctx, const char *fmt, va_list va)
98178825Sdfr{
99178825Sdfr    FILE *f = ctx;
100178825Sdfr    if (f == NULL)
101178825Sdfr	f = stdout;
102178825Sdfr    vfprintf(f, fmt, va);
103178825Sdfr}
104178825Sdfr
105178825Sdfrstatic void
106178825Sdfrprint_func(hx509_vprint_func func, void *ctx, const char *fmt, ...)
107178825Sdfr{
108178825Sdfr    va_list va;
109178825Sdfr    va_start(va, fmt);
110178825Sdfr    (*func)(ctx, fmt, va);
111178825Sdfr    va_end(va);
112178825Sdfr}
113178825Sdfr
114178825Sdfr/**
115178825Sdfr * Print a oid to a string.
116233294Sstas *
117178825Sdfr * @param oid oid to print
118178825Sdfr * @param str allocated string, free with hx509_xfree().
119178825Sdfr *
120178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
121178825Sdfr *
122178825Sdfr * @ingroup hx509_print
123178825Sdfr */
124178825Sdfr
125178825Sdfrint
126178825Sdfrhx509_oid_sprint(const heim_oid *oid, char **str)
127178825Sdfr{
128178825Sdfr    return der_print_heim_oid(oid, '.', str);
129178825Sdfr}
130178825Sdfr
131178825Sdfr/**
132178825Sdfr * Print a oid using a hx509_vprint_func function. To print to stdout
133178825Sdfr * use hx509_print_stdout().
134233294Sstas *
135178825Sdfr * @param oid oid to print
136178825Sdfr * @param func hx509_vprint_func to print with.
137178825Sdfr * @param ctx context variable to hx509_vprint_func function.
138178825Sdfr *
139178825Sdfr * @ingroup hx509_print
140178825Sdfr */
141178825Sdfr
142178825Sdfrvoid
143178825Sdfrhx509_oid_print(const heim_oid *oid, hx509_vprint_func func, void *ctx)
144178825Sdfr{
145178825Sdfr    char *str;
146178825Sdfr    hx509_oid_sprint(oid, &str);
147178825Sdfr    print_func(func, ctx, "%s", str);
148178825Sdfr    free(str);
149178825Sdfr}
150178825Sdfr
151178825Sdfr/**
152178825Sdfr * Print a bitstring using a hx509_vprint_func function. To print to
153178825Sdfr * stdout use hx509_print_stdout().
154233294Sstas *
155178825Sdfr * @param b bit string to print.
156178825Sdfr * @param func hx509_vprint_func to print with.
157178825Sdfr * @param ctx context variable to hx509_vprint_func function.
158178825Sdfr *
159178825Sdfr * @ingroup hx509_print
160178825Sdfr */
161178825Sdfr
162178825Sdfrvoid
163178825Sdfrhx509_bitstring_print(const heim_bit_string *b,
164178825Sdfr		      hx509_vprint_func func, void *ctx)
165178825Sdfr{
166233294Sstas    size_t i;
167178825Sdfr    print_func(func, ctx, "\tlength: %d\n\t", b->length);
168178825Sdfr    for (i = 0; i < (b->length + 7) / 8; i++)
169178825Sdfr	print_func(func, ctx, "%02x%s%s",
170233294Sstas		   ((unsigned char *)b->data)[i],
171178825Sdfr		   i < (b->length - 7) / 8
172178825Sdfr		   && (i == 0 || (i % 16) != 15) ? ":" : "",
173178825Sdfr		   i != 0 && (i % 16) == 15 ?
174178825Sdfr		   (i <= ((b->length + 7) / 8 - 2) ? "\n\t" : "\n"):"");
175178825Sdfr}
176178825Sdfr
177178825Sdfr/**
178178825Sdfr * Print certificate usage for a certificate to a string.
179233294Sstas *
180178825Sdfr * @param context A hx509 context.
181178825Sdfr * @param c a certificate print the keyusage for.
182178825Sdfr * @param s the return string with the keysage printed in to, free
183178825Sdfr * with hx509_xfree().
184178825Sdfr *
185178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
186178825Sdfr *
187178825Sdfr * @ingroup hx509_print
188178825Sdfr */
189178825Sdfr
190178825Sdfrint
191178825Sdfrhx509_cert_keyusage_print(hx509_context context, hx509_cert c, char **s)
192178825Sdfr{
193178825Sdfr    KeyUsage ku;
194178825Sdfr    char buf[256];
195178825Sdfr    int ret;
196178825Sdfr
197178825Sdfr    *s = NULL;
198178825Sdfr
199178825Sdfr    ret = _hx509_cert_get_keyusage(context, c, &ku);
200178825Sdfr    if (ret)
201178825Sdfr	return ret;
202178825Sdfr    unparse_flags(KeyUsage2int(ku), asn1_KeyUsage_units(), buf, sizeof(buf));
203178825Sdfr    *s = strdup(buf);
204178825Sdfr    if (*s == NULL) {
205178825Sdfr	hx509_set_error_string(context, 0, ENOMEM, "out of memory");
206178825Sdfr	return ENOMEM;
207178825Sdfr    }
208178825Sdfr
209178825Sdfr    return 0;
210178825Sdfr}
211178825Sdfr
212178825Sdfr/*
213178825Sdfr *
214178825Sdfr */
215178825Sdfr
216178825Sdfrstatic void
217178825Sdfrvalidate_vprint(void *c, const char *fmt, va_list va)
218178825Sdfr{
219178825Sdfr    hx509_validate_ctx ctx = c;
220178825Sdfr    if (ctx->vprint_func == NULL)
221178825Sdfr	return;
222178825Sdfr    (ctx->vprint_func)(ctx->ctx, fmt, va);
223178825Sdfr}
224178825Sdfr
225178825Sdfrstatic void
226178825Sdfrvalidate_print(hx509_validate_ctx ctx, int flags, const char *fmt, ...)
227178825Sdfr{
228178825Sdfr    va_list va;
229178825Sdfr    if ((ctx->flags & flags) == 0)
230178825Sdfr	return;
231178825Sdfr    va_start(va, fmt);
232178825Sdfr    validate_vprint(ctx, fmt, va);
233178825Sdfr    va_end(va);
234178825Sdfr}
235178825Sdfr
236233294Sstas/*
237178825Sdfr * Dont Care, SHOULD critical, SHOULD NOT critical, MUST critical,
238178825Sdfr * MUST NOT critical
239178825Sdfr */
240178825Sdfrenum critical_flag { D_C = 0, S_C, S_N_C, M_C, M_N_C };
241178825Sdfr
242178825Sdfrstatic int
243178825Sdfrcheck_Null(hx509_validate_ctx ctx,
244178825Sdfr	   struct cert_status *status,
245178825Sdfr	   enum critical_flag cf, const Extension *e)
246178825Sdfr{
247178825Sdfr    switch(cf) {
248178825Sdfr    case D_C:
249178825Sdfr	break;
250178825Sdfr    case S_C:
251178825Sdfr	if (!e->critical)
252178825Sdfr	    validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
253178825Sdfr			   "\tCritical not set on SHOULD\n");
254178825Sdfr	break;
255178825Sdfr    case S_N_C:
256178825Sdfr	if (e->critical)
257178825Sdfr	    validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
258178825Sdfr			   "\tCritical set on SHOULD NOT\n");
259178825Sdfr	break;
260178825Sdfr    case M_C:
261178825Sdfr	if (!e->critical)
262178825Sdfr	    validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
263178825Sdfr			   "\tCritical not set on MUST\n");
264178825Sdfr	break;
265178825Sdfr    case M_N_C:
266178825Sdfr	if (e->critical)
267178825Sdfr	    validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
268178825Sdfr			   "\tCritical set on MUST NOT\n");
269178825Sdfr	break;
270178825Sdfr    default:
271178825Sdfr	_hx509_abort("internal check_Null state error");
272178825Sdfr    }
273178825Sdfr    return 0;
274178825Sdfr}
275178825Sdfr
276178825Sdfrstatic int
277233294Sstascheck_subjectKeyIdentifier(hx509_validate_ctx ctx,
278178825Sdfr			   struct cert_status *status,
279178825Sdfr			   enum critical_flag cf,
280178825Sdfr			   const Extension *e)
281178825Sdfr{
282178825Sdfr    SubjectKeyIdentifier si;
283178825Sdfr    size_t size;
284178825Sdfr    int ret;
285178825Sdfr
286178825Sdfr    status->haveSKI = 1;
287178825Sdfr    check_Null(ctx, status, cf, e);
288178825Sdfr
289233294Sstas    ret = decode_SubjectKeyIdentifier(e->extnValue.data,
290178825Sdfr				      e->extnValue.length,
291178825Sdfr				      &si, &size);
292178825Sdfr    if (ret) {
293178825Sdfr	validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
294178825Sdfr		       "Decoding SubjectKeyIdentifier failed: %d", ret);
295178825Sdfr	return 1;
296178825Sdfr    }
297178825Sdfr    if (size != e->extnValue.length) {
298178825Sdfr	validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
299178825Sdfr		       "Decoding SKI ahve extra bits on the end");
300178825Sdfr	return 1;
301178825Sdfr    }
302178825Sdfr    if (si.length == 0)
303178825Sdfr	validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
304178825Sdfr		       "SKI is too short (0 bytes)");
305178825Sdfr    if (si.length > 20)
306178825Sdfr	validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
307178825Sdfr		       "SKI is too long");
308178825Sdfr
309178825Sdfr    {
310178825Sdfr	char *id;
311178825Sdfr	hex_encode(si.data, si.length, &id);
312178825Sdfr	if (id) {
313178825Sdfr	    validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
314178825Sdfr			   "\tsubject key id: %s\n", id);
315178825Sdfr	    free(id);
316178825Sdfr	}
317178825Sdfr    }
318178825Sdfr
319178825Sdfr    free_SubjectKeyIdentifier(&si);
320178825Sdfr
321178825Sdfr    return 0;
322178825Sdfr}
323178825Sdfr
324178825Sdfrstatic int
325233294Sstascheck_authorityKeyIdentifier(hx509_validate_ctx ctx,
326178825Sdfr			     struct cert_status *status,
327178825Sdfr			     enum critical_flag cf,
328178825Sdfr			     const Extension *e)
329178825Sdfr{
330178825Sdfr    AuthorityKeyIdentifier ai;
331178825Sdfr    size_t size;
332178825Sdfr    int ret;
333178825Sdfr
334178825Sdfr    status->haveAKI = 1;
335178825Sdfr    check_Null(ctx, status, cf, e);
336178825Sdfr
337233294Sstas    ret = decode_AuthorityKeyIdentifier(e->extnValue.data,
338178825Sdfr					e->extnValue.length,
339178825Sdfr					&ai, &size);
340178825Sdfr    if (ret) {
341178825Sdfr	validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
342178825Sdfr		       "Decoding AuthorityKeyIdentifier failed: %d", ret);
343178825Sdfr	return 1;
344178825Sdfr    }
345178825Sdfr    if (size != e->extnValue.length) {
346178825Sdfr	validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
347178825Sdfr		       "Decoding SKI ahve extra bits on the end");
348178825Sdfr	return 1;
349178825Sdfr    }
350178825Sdfr
351178825Sdfr    if (ai.keyIdentifier) {
352178825Sdfr	char *id;
353178825Sdfr	hex_encode(ai.keyIdentifier->data, ai.keyIdentifier->length, &id);
354178825Sdfr	if (id) {
355178825Sdfr	    validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
356178825Sdfr			   "\tauthority key id: %s\n", id);
357178825Sdfr	    free(id);
358178825Sdfr	}
359178825Sdfr    }
360178825Sdfr
361178825Sdfr    return 0;
362178825Sdfr}
363178825Sdfr
364233294Sstasstatic int
365233294Sstascheck_extKeyUsage(hx509_validate_ctx ctx,
366233294Sstas		  struct cert_status *status,
367233294Sstas		  enum critical_flag cf,
368233294Sstas		  const Extension *e)
369233294Sstas{
370233294Sstas    ExtKeyUsage eku;
371233294Sstas    size_t size, i;
372233294Sstas    int ret;
373178825Sdfr
374233294Sstas    check_Null(ctx, status, cf, e);
375233294Sstas
376233294Sstas    ret = decode_ExtKeyUsage(e->extnValue.data,
377233294Sstas			     e->extnValue.length,
378233294Sstas			     &eku, &size);
379233294Sstas    if (ret) {
380233294Sstas	validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
381233294Sstas		       "Decoding ExtKeyUsage failed: %d", ret);
382233294Sstas	return 1;
383233294Sstas    }
384233294Sstas    if (size != e->extnValue.length) {
385233294Sstas	validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
386233294Sstas		       "Padding data in EKU");
387233294Sstas	free_ExtKeyUsage(&eku);
388233294Sstas	return 1;
389233294Sstas    }
390233294Sstas    if (eku.len == 0) {
391233294Sstas	validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
392233294Sstas		       "ExtKeyUsage length is 0");
393233294Sstas	return 1;
394233294Sstas    }
395233294Sstas
396233294Sstas    for (i = 0; i < eku.len; i++) {
397233294Sstas	char *str;
398233294Sstas	ret = der_print_heim_oid (&eku.val[i], '.', &str);
399233294Sstas	if (ret) {
400233294Sstas	    validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
401233294Sstas			   "\tEKU: failed to print oid %d", i);
402233294Sstas	    free_ExtKeyUsage(&eku);
403233294Sstas	    return 1;
404233294Sstas	}
405233294Sstas	validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
406233294Sstas		       "\teku-%d: %s\n", i, str);;
407233294Sstas	free(str);
408233294Sstas    }
409233294Sstas
410233294Sstas    free_ExtKeyUsage(&eku);
411233294Sstas
412233294Sstas    return 0;
413233294Sstas}
414233294Sstas
415178825Sdfrstatic int
416178825Sdfrcheck_pkinit_san(hx509_validate_ctx ctx, heim_any *a)
417178825Sdfr{
418178825Sdfr    KRB5PrincipalName kn;
419178825Sdfr    unsigned i;
420178825Sdfr    size_t size;
421178825Sdfr    int ret;
422178825Sdfr
423178825Sdfr    ret = decode_KRB5PrincipalName(a->data, a->length, &kn, &size);
424178825Sdfr    if (ret) {
425178825Sdfr	validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
426178825Sdfr		       "Decoding kerberos name in SAN failed: %d", ret);
427178825Sdfr	return 1;
428178825Sdfr    }
429178825Sdfr
430178825Sdfr    if (size != a->length) {
431178825Sdfr	validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
432178825Sdfr		       "Decoding kerberos name have extra bits on the end");
433178825Sdfr	return 1;
434178825Sdfr    }
435178825Sdfr
436178825Sdfr    /* print kerberos principal, add code to quote / within components */
437178825Sdfr    for (i = 0; i < kn.principalName.name_string.len; i++) {
438233294Sstas	validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s",
439178825Sdfr		       kn.principalName.name_string.val[i]);
440178825Sdfr	if (i + 1 < kn.principalName.name_string.len)
441178825Sdfr	    validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "/");
442178825Sdfr    }
443178825Sdfr    validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "@");
444178825Sdfr    validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s", kn.realm);
445178825Sdfr
446178825Sdfr    free_KRB5PrincipalName(&kn);
447178825Sdfr    return 0;
448178825Sdfr}
449178825Sdfr
450178825Sdfrstatic int
451178825Sdfrcheck_utf8_string_san(hx509_validate_ctx ctx, heim_any *a)
452178825Sdfr{
453178825Sdfr    PKIXXmppAddr jid;
454178825Sdfr    size_t size;
455178825Sdfr    int ret;
456178825Sdfr
457178825Sdfr    ret = decode_PKIXXmppAddr(a->data, a->length, &jid, &size);
458178825Sdfr    if (ret) {
459178825Sdfr	validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
460178825Sdfr		       "Decoding JID in SAN failed: %d", ret);
461178825Sdfr	return 1;
462178825Sdfr    }
463178825Sdfr
464178825Sdfr    validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s", jid);
465178825Sdfr    free_PKIXXmppAddr(&jid);
466178825Sdfr
467178825Sdfr    return 0;
468178825Sdfr}
469178825Sdfr
470178825Sdfrstatic int
471178825Sdfrcheck_altnull(hx509_validate_ctx ctx, heim_any *a)
472178825Sdfr{
473178825Sdfr    return 0;
474178825Sdfr}
475178825Sdfr
476178825Sdfrstatic int
477233294Sstascheck_CRLDistributionPoints(hx509_validate_ctx ctx,
478178825Sdfr			   struct cert_status *status,
479178825Sdfr			   enum critical_flag cf,
480178825Sdfr			   const Extension *e)
481178825Sdfr{
482178825Sdfr    CRLDistributionPoints dp;
483178825Sdfr    size_t size;
484233294Sstas    int ret;
485233294Sstas    size_t i;
486178825Sdfr
487178825Sdfr    check_Null(ctx, status, cf, e);
488178825Sdfr
489233294Sstas    ret = decode_CRLDistributionPoints(e->extnValue.data,
490178825Sdfr				       e->extnValue.length,
491178825Sdfr				       &dp, &size);
492178825Sdfr    if (ret) {
493178825Sdfr	validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
494178825Sdfr		       "Decoding CRL Distribution Points failed: %d\n", ret);
495178825Sdfr	return 1;
496178825Sdfr    }
497178825Sdfr
498178825Sdfr    validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "CRL Distribution Points:\n");
499178825Sdfr    for (i = 0 ; i < dp.len; i++) {
500178825Sdfr	if (dp.val[i].distributionPoint) {
501178825Sdfr	    DistributionPointName dpname;
502178825Sdfr	    heim_any *data = dp.val[i].distributionPoint;
503233294Sstas	    size_t j;
504233294Sstas
505178825Sdfr	    ret = decode_DistributionPointName(data->data, data->length,
506178825Sdfr					       &dpname, NULL);
507178825Sdfr	    if (ret) {
508233294Sstas		validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
509178825Sdfr			       "Failed to parse CRL Distribution Point Name: %d\n", ret);
510178825Sdfr		continue;
511178825Sdfr	    }
512178825Sdfr
513178825Sdfr	    switch (dpname.element) {
514178825Sdfr	    case choice_DistributionPointName_fullName:
515178825Sdfr		validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "Fullname:\n");
516233294Sstas
517178825Sdfr		for (j = 0 ; j < dpname.u.fullName.len; j++) {
518178825Sdfr		    char *s;
519178825Sdfr		    GeneralName *name = &dpname.u.fullName.val[j];
520178825Sdfr
521178825Sdfr		    ret = hx509_general_name_unparse(name, &s);
522178825Sdfr		    if (ret == 0 && s != NULL) {
523178825Sdfr			validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "   %s\n", s);
524178825Sdfr			free(s);
525178825Sdfr		    }
526178825Sdfr		}
527178825Sdfr		break;
528178825Sdfr	    case choice_DistributionPointName_nameRelativeToCRLIssuer:
529178825Sdfr		validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
530178825Sdfr			       "Unknown nameRelativeToCRLIssuer");
531178825Sdfr		break;
532178825Sdfr	    default:
533178825Sdfr		validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
534178825Sdfr			       "Unknown DistributionPointName");
535178825Sdfr		break;
536178825Sdfr	    }
537178825Sdfr	    free_DistributionPointName(&dpname);
538178825Sdfr	}
539178825Sdfr    }
540178825Sdfr    free_CRLDistributionPoints(&dp);
541178825Sdfr
542178825Sdfr    status->haveCRLDP = 1;
543178825Sdfr
544178825Sdfr    return 0;
545178825Sdfr}
546178825Sdfr
547178825Sdfr
548178825Sdfrstruct {
549178825Sdfr    const char *name;
550233294Sstas    const heim_oid *oid;
551178825Sdfr    int (*func)(hx509_validate_ctx, heim_any *);
552233294Sstas} altname_types[] = {
553233294Sstas    { "pk-init", &asn1_oid_id_pkinit_san, check_pkinit_san },
554233294Sstas    { "jabber", &asn1_oid_id_pkix_on_xmppAddr, check_utf8_string_san },
555233294Sstas    { "dns-srv", &asn1_oid_id_pkix_on_dnsSRV, check_altnull },
556233294Sstas    { "card-id", &asn1_oid_id_uspkicommon_card_id, check_altnull },
557233294Sstas    { "Microsoft NT-PRINCIPAL-NAME", &asn1_oid_id_pkinit_ms_san, check_utf8_string_san }
558178825Sdfr};
559178825Sdfr
560178825Sdfrstatic int
561178825Sdfrcheck_altName(hx509_validate_ctx ctx,
562178825Sdfr	      struct cert_status *status,
563178825Sdfr	      const char *name,
564178825Sdfr	      enum critical_flag cf,
565178825Sdfr	      const Extension *e)
566178825Sdfr{
567178825Sdfr    GeneralNames gn;
568178825Sdfr    size_t size;
569233294Sstas    int ret;
570233294Sstas    size_t i;
571178825Sdfr
572178825Sdfr    check_Null(ctx, status, cf, e);
573178825Sdfr
574178825Sdfr    if (e->extnValue.length == 0) {
575178825Sdfr	validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
576178825Sdfr		       "%sAltName empty, not allowed", name);
577178825Sdfr	return 1;
578178825Sdfr    }
579178825Sdfr    ret = decode_GeneralNames(e->extnValue.data, e->extnValue.length,
580178825Sdfr			      &gn, &size);
581178825Sdfr    if (ret) {
582178825Sdfr	validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
583233294Sstas		       "\tret = %d while decoding %s GeneralNames\n",
584178825Sdfr		       ret, name);
585178825Sdfr	return 1;
586178825Sdfr    }
587178825Sdfr    if (gn.len == 0) {
588178825Sdfr	validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
589178825Sdfr		       "%sAltName generalName empty, not allowed\n", name);
590178825Sdfr	return 1;
591178825Sdfr    }
592178825Sdfr
593178825Sdfr    for (i = 0; i < gn.len; i++) {
594178825Sdfr	switch (gn.val[i].element) {
595178825Sdfr	case choice_GeneralName_otherName: {
596178825Sdfr	    unsigned j;
597178825Sdfr
598178825Sdfr	    validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
599178825Sdfr			   "%sAltName otherName ", name);
600178825Sdfr
601233294Sstas	    for (j = 0; j < sizeof(altname_types)/sizeof(altname_types[0]); j++) {
602233294Sstas		if (der_heim_oid_cmp(altname_types[j].oid,
603178825Sdfr				     &gn.val[i].u.otherName.type_id) != 0)
604178825Sdfr		    continue;
605233294Sstas
606233294Sstas		validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s: ",
607233294Sstas			       altname_types[j].name);
608233294Sstas		(*altname_types[j].func)(ctx, &gn.val[i].u.otherName.value);
609178825Sdfr		break;
610178825Sdfr	    }
611233294Sstas	    if (j == sizeof(altname_types)/sizeof(altname_types[0])) {
612178825Sdfr		hx509_oid_print(&gn.val[i].u.otherName.type_id,
613178825Sdfr				validate_vprint, ctx);
614178825Sdfr		validate_print(ctx, HX509_VALIDATE_F_VERBOSE, " unknown");
615178825Sdfr	    }
616178825Sdfr	    validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\n");
617178825Sdfr	    break;
618178825Sdfr	}
619178825Sdfr	default: {
620178825Sdfr	    char *s;
621178825Sdfr	    ret = hx509_general_name_unparse(&gn.val[i], &s);
622178825Sdfr	    if (ret) {
623178825Sdfr		validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
624178825Sdfr			       "ret = %d unparsing GeneralName\n", ret);
625178825Sdfr		return 1;
626178825Sdfr	    }
627178825Sdfr	    validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s\n", s);
628178825Sdfr	    free(s);
629178825Sdfr	    break;
630178825Sdfr	}
631178825Sdfr	}
632178825Sdfr    }
633178825Sdfr
634178825Sdfr    free_GeneralNames(&gn);
635178825Sdfr
636178825Sdfr    return 0;
637178825Sdfr}
638178825Sdfr
639178825Sdfrstatic int
640178825Sdfrcheck_subjectAltName(hx509_validate_ctx ctx,
641178825Sdfr		     struct cert_status *status,
642178825Sdfr		     enum critical_flag cf,
643178825Sdfr		     const Extension *e)
644178825Sdfr{
645178825Sdfr    status->haveSAN = 1;
646178825Sdfr    return check_altName(ctx, status, "subject", cf, e);
647178825Sdfr}
648178825Sdfr
649178825Sdfrstatic int
650178825Sdfrcheck_issuerAltName(hx509_validate_ctx ctx,
651178825Sdfr		    struct cert_status *status,
652178825Sdfr		     enum critical_flag cf,
653178825Sdfr		     const Extension *e)
654178825Sdfr{
655178825Sdfr    status->haveIAN = 1;
656178825Sdfr    return check_altName(ctx, status, "issuer", cf, e);
657178825Sdfr}
658178825Sdfr
659178825Sdfr
660178825Sdfrstatic int
661233294Sstascheck_basicConstraints(hx509_validate_ctx ctx,
662178825Sdfr		       struct cert_status *status,
663233294Sstas		       enum critical_flag cf,
664178825Sdfr		       const Extension *e)
665178825Sdfr{
666178825Sdfr    BasicConstraints b;
667178825Sdfr    size_t size;
668178825Sdfr    int ret;
669178825Sdfr
670178825Sdfr    check_Null(ctx, status, cf, e);
671233294Sstas
672178825Sdfr    ret = decode_BasicConstraints(e->extnValue.data, e->extnValue.length,
673178825Sdfr				  &b, &size);
674178825Sdfr    if (ret) {
675178825Sdfr	printf("\tret = %d while decoding BasicConstraints\n", ret);
676178825Sdfr	return 0;
677178825Sdfr    }
678178825Sdfr    if (size != e->extnValue.length)
679178825Sdfr	printf("\tlength of der data isn't same as extension\n");
680178825Sdfr
681178825Sdfr    validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
682178825Sdfr		   "\tis %sa CA\n", b.cA && *b.cA ? "" : "NOT ");
683178825Sdfr    if (b.pathLenConstraint)
684178825Sdfr	validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
685178825Sdfr		       "\tpathLenConstraint: %d\n", *b.pathLenConstraint);
686178825Sdfr
687178825Sdfr    if (b.cA) {
688178825Sdfr	if (*b.cA) {
689178825Sdfr	    if (!e->critical)
690178825Sdfr		validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
691178825Sdfr			       "Is a CA and not BasicConstraints CRITICAL\n");
692178825Sdfr	    status->isca = 1;
693178825Sdfr	}
694178825Sdfr	else
695178825Sdfr	    validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
696178825Sdfr			   "cA is FALSE, not allowed to be\n");
697178825Sdfr    }
698178825Sdfr    free_BasicConstraints(&b);
699178825Sdfr
700178825Sdfr    return 0;
701178825Sdfr}
702178825Sdfr
703178825Sdfrstatic int
704233294Sstascheck_proxyCertInfo(hx509_validate_ctx ctx,
705178825Sdfr		    struct cert_status *status,
706233294Sstas		    enum critical_flag cf,
707178825Sdfr		    const Extension *e)
708178825Sdfr{
709178825Sdfr    check_Null(ctx, status, cf, e);
710178825Sdfr    status->isproxy = 1;
711178825Sdfr    return 0;
712178825Sdfr}
713178825Sdfr
714178825Sdfrstatic int
715233294Sstascheck_authorityInfoAccess(hx509_validate_ctx ctx,
716178825Sdfr			  struct cert_status *status,
717233294Sstas			  enum critical_flag cf,
718178825Sdfr			  const Extension *e)
719178825Sdfr{
720178825Sdfr    AuthorityInfoAccessSyntax aia;
721178825Sdfr    size_t size;
722233294Sstas    int ret;
723233294Sstas    size_t i;
724178825Sdfr
725178825Sdfr    check_Null(ctx, status, cf, e);
726178825Sdfr
727233294Sstas    ret = decode_AuthorityInfoAccessSyntax(e->extnValue.data,
728178825Sdfr					   e->extnValue.length,
729178825Sdfr					   &aia, &size);
730178825Sdfr    if (ret) {
731178825Sdfr	printf("\tret = %d while decoding AuthorityInfoAccessSyntax\n", ret);
732178825Sdfr	return 0;
733178825Sdfr    }
734178825Sdfr
735178825Sdfr    for (i = 0; i < aia.len; i++) {
736178825Sdfr	char *str;
737178825Sdfr	validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
738178825Sdfr		       "\ttype: ");
739178825Sdfr	hx509_oid_print(&aia.val[i].accessMethod, validate_vprint, ctx);
740178825Sdfr	hx509_general_name_unparse(&aia.val[i].accessLocation, &str);
741178825Sdfr	validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
742178825Sdfr		       "\n\tdirname: %s\n", str);
743178825Sdfr	free(str);
744178825Sdfr    }
745178825Sdfr    free_AuthorityInfoAccessSyntax(&aia);
746178825Sdfr
747178825Sdfr    return 0;
748178825Sdfr}
749178825Sdfr
750178825Sdfr/*
751178825Sdfr *
752178825Sdfr */
753178825Sdfr
754178825Sdfrstruct {
755178825Sdfr    const char *name;
756233294Sstas    const heim_oid *oid;
757233294Sstas    int (*func)(hx509_validate_ctx ctx,
758178825Sdfr		struct cert_status *status,
759233294Sstas		enum critical_flag cf,
760178825Sdfr		const Extension *);
761178825Sdfr    enum critical_flag cf;
762178825Sdfr} check_extension[] = {
763233294Sstas#define ext(name, checkname) #name, &asn1_oid_id_x509_ce_##name, check_##checkname
764178825Sdfr    { ext(subjectDirectoryAttributes, Null), M_N_C },
765178825Sdfr    { ext(subjectKeyIdentifier, subjectKeyIdentifier), M_N_C },
766178825Sdfr    { ext(keyUsage, Null), S_C },
767178825Sdfr    { ext(subjectAltName, subjectAltName), M_N_C },
768178825Sdfr    { ext(issuerAltName, issuerAltName), S_N_C },
769178825Sdfr    { ext(basicConstraints, basicConstraints), D_C },
770178825Sdfr    { ext(cRLNumber, Null), M_N_C },
771178825Sdfr    { ext(cRLReason, Null), M_N_C },
772178825Sdfr    { ext(holdInstructionCode, Null), M_N_C },
773178825Sdfr    { ext(invalidityDate, Null), M_N_C },
774178825Sdfr    { ext(deltaCRLIndicator, Null), M_C },
775178825Sdfr    { ext(issuingDistributionPoint, Null), M_C },
776178825Sdfr    { ext(certificateIssuer, Null), M_C },
777178825Sdfr    { ext(nameConstraints, Null), M_C },
778178825Sdfr    { ext(cRLDistributionPoints, CRLDistributionPoints), S_N_C },
779233294Sstas    { ext(certificatePolicies, Null), 0 },
780178825Sdfr    { ext(policyMappings, Null), M_N_C },
781178825Sdfr    { ext(authorityKeyIdentifier, authorityKeyIdentifier), M_N_C },
782178825Sdfr    { ext(policyConstraints, Null), D_C },
783233294Sstas    { ext(extKeyUsage, extKeyUsage), D_C },
784178825Sdfr    { ext(freshestCRL, Null), M_N_C },
785178825Sdfr    { ext(inhibitAnyPolicy, Null), M_C },
786178825Sdfr#undef ext
787233294Sstas#define ext(name, checkname) #name, &asn1_oid_id_pkix_pe_##name, check_##checkname
788178825Sdfr    { ext(proxyCertInfo, proxyCertInfo), M_C },
789178825Sdfr    { ext(authorityInfoAccess, authorityInfoAccess), M_C },
790178825Sdfr#undef ext
791233294Sstas    { "US Fed PKI - PIV Interim", &asn1_oid_id_uspkicommon_piv_interim,
792178825Sdfr      check_Null, D_C },
793233294Sstas    { "Netscape cert comment", &asn1_oid_id_netscape_cert_comment,
794178825Sdfr      check_Null, D_C },
795233294Sstas    { NULL, NULL, NULL, 0 }
796178825Sdfr};
797178825Sdfr
798178825Sdfr/**
799178825Sdfr * Allocate a hx509 validation/printing context.
800233294Sstas *
801178825Sdfr * @param context A hx509 context.
802178825Sdfr * @param ctx a new allocated hx509 validation context, free with
803178825Sdfr * hx509_validate_ctx_free().
804178825Sdfr
805178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
806178825Sdfr *
807178825Sdfr * @ingroup hx509_print
808178825Sdfr */
809178825Sdfr
810178825Sdfrint
811178825Sdfrhx509_validate_ctx_init(hx509_context context, hx509_validate_ctx *ctx)
812178825Sdfr{
813178825Sdfr    *ctx = malloc(sizeof(**ctx));
814178825Sdfr    if (*ctx == NULL)
815178825Sdfr	return ENOMEM;
816178825Sdfr    memset(*ctx, 0, sizeof(**ctx));
817178825Sdfr    return 0;
818178825Sdfr}
819178825Sdfr
820178825Sdfr/**
821178825Sdfr * Set the printing functions for the validation context.
822233294Sstas *
823178825Sdfr * @param ctx a hx509 valication context.
824178825Sdfr * @param func the printing function to usea.
825178825Sdfr * @param c the context variable to the printing function.
826178825Sdfr *
827178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
828178825Sdfr *
829178825Sdfr * @ingroup hx509_print
830178825Sdfr */
831178825Sdfr
832178825Sdfrvoid
833233294Sstashx509_validate_ctx_set_print(hx509_validate_ctx ctx,
834178825Sdfr			     hx509_vprint_func func,
835178825Sdfr			     void *c)
836178825Sdfr{
837178825Sdfr    ctx->vprint_func = func;
838178825Sdfr    ctx->ctx = c;
839178825Sdfr}
840178825Sdfr
841178825Sdfr/**
842178825Sdfr * Add flags to control the behaivor of the hx509_validate_cert()
843178825Sdfr * function.
844233294Sstas *
845178825Sdfr * @param ctx A hx509 validation context.
846178825Sdfr * @param flags flags to add to the validation context.
847178825Sdfr *
848178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
849178825Sdfr *
850178825Sdfr * @ingroup hx509_print
851178825Sdfr */
852178825Sdfr
853178825Sdfrvoid
854178825Sdfrhx509_validate_ctx_add_flags(hx509_validate_ctx ctx, int flags)
855178825Sdfr{
856178825Sdfr    ctx->flags |= flags;
857178825Sdfr}
858178825Sdfr
859178825Sdfr/**
860178825Sdfr * Free an hx509 validate context.
861233294Sstas *
862178825Sdfr * @param ctx the hx509 validate context to free.
863178825Sdfr *
864178825Sdfr * @ingroup hx509_print
865178825Sdfr */
866178825Sdfr
867178825Sdfrvoid
868178825Sdfrhx509_validate_ctx_free(hx509_validate_ctx ctx)
869178825Sdfr{
870178825Sdfr    free(ctx);
871178825Sdfr}
872178825Sdfr
873178825Sdfr/**
874178825Sdfr * Validate/Print the status of the certificate.
875233294Sstas *
876178825Sdfr * @param context A hx509 context.
877178825Sdfr * @param ctx A hx509 validation context.
878178825Sdfr * @param cert the cerificate to validate/print.
879178825Sdfr
880178825Sdfr * @return An hx509 error code, see hx509_get_error_string().
881178825Sdfr *
882178825Sdfr * @ingroup hx509_print
883178825Sdfr */
884178825Sdfr
885178825Sdfrint
886178825Sdfrhx509_validate_cert(hx509_context context,
887178825Sdfr		    hx509_validate_ctx ctx,
888178825Sdfr		    hx509_cert cert)
889178825Sdfr{
890178825Sdfr    Certificate *c = _hx509_get_cert(cert);
891178825Sdfr    TBSCertificate *t = &c->tbsCertificate;
892178825Sdfr    hx509_name issuer, subject;
893178825Sdfr    char *str;
894178825Sdfr    struct cert_status status;
895178825Sdfr    int ret;
896178825Sdfr
897178825Sdfr    memset(&status, 0, sizeof(status));
898178825Sdfr
899178825Sdfr    if (_hx509_cert_get_version(c) != 3)
900178825Sdfr	validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
901178825Sdfr		       "Not version 3 certificate\n");
902233294Sstas
903178825Sdfr    if ((t->version == NULL || *t->version < 2) && t->extensions)
904178825Sdfr	validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
905178825Sdfr		       "Not version 3 certificate with extensions\n");
906233294Sstas
907178825Sdfr    if (_hx509_cert_get_version(c) >= 3 && t->extensions == NULL)
908178825Sdfr	validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
909178825Sdfr		       "Version 3 certificate without extensions\n");
910178825Sdfr
911178825Sdfr    ret = hx509_cert_get_subject(cert, &subject);
912178825Sdfr    if (ret) abort();
913178825Sdfr    hx509_name_to_string(subject, &str);
914178825Sdfr    validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
915178825Sdfr		   "subject name: %s\n", str);
916178825Sdfr    free(str);
917178825Sdfr
918178825Sdfr    ret = hx509_cert_get_issuer(cert, &issuer);
919178825Sdfr    if (ret) abort();
920178825Sdfr    hx509_name_to_string(issuer, &str);
921178825Sdfr    validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
922178825Sdfr		   "issuer name: %s\n", str);
923178825Sdfr    free(str);
924178825Sdfr
925178825Sdfr    if (hx509_name_cmp(subject, issuer) == 0) {
926178825Sdfr	status.selfsigned = 1;
927178825Sdfr	validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
928178825Sdfr		       "\tis a self-signed certificate\n");
929178825Sdfr    }
930178825Sdfr
931178825Sdfr    validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
932178825Sdfr		   "Validity:\n");
933178825Sdfr
934178825Sdfr    Time2string(&t->validity.notBefore, &str);
935178825Sdfr    validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\tnotBefore %s\n", str);
936178825Sdfr    free(str);
937178825Sdfr    Time2string(&t->validity.notAfter, &str);
938178825Sdfr    validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\tnotAfter  %s\n", str);
939178825Sdfr    free(str);
940178825Sdfr
941178825Sdfr    if (t->extensions) {
942233294Sstas	size_t i, j;
943178825Sdfr
944178825Sdfr	if (t->extensions->len == 0) {
945178825Sdfr	    validate_print(ctx,
946178825Sdfr			   HX509_VALIDATE_F_VALIDATE|HX509_VALIDATE_F_VERBOSE,
947178825Sdfr			   "The empty extensions list is not "
948178825Sdfr			   "allowed by PKIX\n");
949178825Sdfr	}
950178825Sdfr
951178825Sdfr	for (i = 0; i < t->extensions->len; i++) {
952178825Sdfr
953178825Sdfr	    for (j = 0; check_extension[j].name; j++)
954233294Sstas		if (der_heim_oid_cmp(check_extension[j].oid,
955178825Sdfr				     &t->extensions->val[i].extnID) == 0)
956178825Sdfr		    break;
957178825Sdfr	    if (check_extension[j].name == NULL) {
958178825Sdfr		int flags = HX509_VALIDATE_F_VERBOSE;
959178825Sdfr		if (t->extensions->val[i].critical)
960178825Sdfr		    flags |= HX509_VALIDATE_F_VALIDATE;
961178825Sdfr		validate_print(ctx, flags, "don't know what ");
962178825Sdfr		if (t->extensions->val[i].critical)
963178825Sdfr		    validate_print(ctx, flags, "and is CRITICAL ");
964178825Sdfr		if (ctx->flags & flags)
965233294Sstas		    hx509_oid_print(&t->extensions->val[i].extnID,
966178825Sdfr				    validate_vprint, ctx);
967178825Sdfr		validate_print(ctx, flags, " is\n");
968178825Sdfr		continue;
969178825Sdfr	    }
970178825Sdfr	    validate_print(ctx,
971178825Sdfr			   HX509_VALIDATE_F_VALIDATE|HX509_VALIDATE_F_VERBOSE,
972178825Sdfr			   "checking extention: %s\n",
973178825Sdfr			   check_extension[j].name);
974178825Sdfr	    (*check_extension[j].func)(ctx,
975178825Sdfr				       &status,
976178825Sdfr				       check_extension[j].cf,
977178825Sdfr				       &t->extensions->val[i]);
978178825Sdfr	}
979178825Sdfr    } else
980178825Sdfr	validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "no extentions\n");
981233294Sstas
982178825Sdfr    if (status.isca) {
983178825Sdfr	if (!status.haveSKI)
984233294Sstas	    validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
985178825Sdfr			   "CA certificate have no SubjectKeyIdentifier\n");
986178825Sdfr
987178825Sdfr    } else {
988178825Sdfr	if (!status.haveAKI)
989233294Sstas	    validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
990178825Sdfr			   "Is not CA and doesn't have "
991178825Sdfr			   "AuthorityKeyIdentifier\n");
992178825Sdfr    }
993178825Sdfr
994233294Sstas
995178825Sdfr    if (!status.haveSKI)
996233294Sstas	validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
997178825Sdfr		       "Doesn't have SubjectKeyIdentifier\n");
998178825Sdfr
999178825Sdfr    if (status.isproxy && status.isca)
1000233294Sstas	validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
1001178825Sdfr		       "Proxy and CA at the same time!\n");
1002178825Sdfr
1003178825Sdfr    if (status.isproxy) {
1004178825Sdfr	if (status.haveSAN)
1005233294Sstas	    validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
1006178825Sdfr			   "Proxy and have SAN\n");
1007178825Sdfr	if (status.haveIAN)
1008233294Sstas	    validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
1009178825Sdfr			   "Proxy and have IAN\n");
1010178825Sdfr    }
1011178825Sdfr
1012178825Sdfr    if (hx509_name_is_null_p(subject) && !status.haveSAN)
1013233294Sstas	validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
1014178825Sdfr		       "NULL subject DN and doesn't have a SAN\n");
1015178825Sdfr
1016178825Sdfr    if (!status.selfsigned && !status.haveCRLDP)
1017233294Sstas	validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
1018178825Sdfr		       "Not a CA nor PROXY and doesn't have"
1019178825Sdfr		       "CRL Dist Point\n");
1020178825Sdfr
1021178825Sdfr    if (status.selfsigned) {
1022178825Sdfr	ret = _hx509_verify_signature_bitstring(context,
1023233294Sstas						cert,
1024178825Sdfr						&c->signatureAlgorithm,
1025178825Sdfr						&c->tbsCertificate._save,
1026178825Sdfr						&c->signatureValue);
1027178825Sdfr	if (ret == 0)
1028233294Sstas	    validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
1029178825Sdfr			   "Self-signed certificate was self-signed\n");
1030178825Sdfr	else
1031233294Sstas	    validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
1032178825Sdfr			   "Self-signed certificate NOT really self-signed!\n");
1033178825Sdfr    }
1034178825Sdfr
1035178825Sdfr    hx509_name_free(&subject);
1036178825Sdfr    hx509_name_free(&issuer);
1037178825Sdfr
1038178825Sdfr    return 0;
1039178825Sdfr}
1040