1*0a6a1f1dSLionel Sambuc /* $NetBSD: print.c,v 1.1.1.2 2014/04/24 12:45:42 pettai Exp $ */
2ebfedea0SLionel Sambuc
3ebfedea0SLionel Sambuc /*
4ebfedea0SLionel Sambuc * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan
5ebfedea0SLionel Sambuc * (Royal Institute of Technology, Stockholm, Sweden).
6ebfedea0SLionel Sambuc * All rights reserved.
7ebfedea0SLionel Sambuc *
8ebfedea0SLionel Sambuc * Redistribution and use in source and binary forms, with or without
9ebfedea0SLionel Sambuc * modification, are permitted provided that the following conditions
10ebfedea0SLionel Sambuc * are met:
11ebfedea0SLionel Sambuc *
12ebfedea0SLionel Sambuc * 1. Redistributions of source code must retain the above copyright
13ebfedea0SLionel Sambuc * notice, this list of conditions and the following disclaimer.
14ebfedea0SLionel Sambuc *
15ebfedea0SLionel Sambuc * 2. Redistributions in binary form must reproduce the above copyright
16ebfedea0SLionel Sambuc * notice, this list of conditions and the following disclaimer in the
17ebfedea0SLionel Sambuc * documentation and/or other materials provided with the distribution.
18ebfedea0SLionel Sambuc *
19ebfedea0SLionel Sambuc * 3. Neither the name of the Institute nor the names of its contributors
20ebfedea0SLionel Sambuc * may be used to endorse or promote products derived from this software
21ebfedea0SLionel Sambuc * without specific prior written permission.
22ebfedea0SLionel Sambuc *
23ebfedea0SLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24ebfedea0SLionel Sambuc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25ebfedea0SLionel Sambuc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26ebfedea0SLionel Sambuc * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27ebfedea0SLionel Sambuc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28ebfedea0SLionel Sambuc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29ebfedea0SLionel Sambuc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30ebfedea0SLionel Sambuc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31ebfedea0SLionel Sambuc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32ebfedea0SLionel Sambuc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33ebfedea0SLionel Sambuc * SUCH DAMAGE.
34ebfedea0SLionel Sambuc */
35ebfedea0SLionel Sambuc
36ebfedea0SLionel Sambuc #include "hx_locl.h"
37ebfedea0SLionel Sambuc
38ebfedea0SLionel Sambuc /**
39ebfedea0SLionel Sambuc * @page page_print Hx509 printing functions
40ebfedea0SLionel Sambuc *
41ebfedea0SLionel Sambuc * See the library functions here: @ref hx509_print
42ebfedea0SLionel Sambuc */
43ebfedea0SLionel Sambuc
44ebfedea0SLionel Sambuc struct hx509_validate_ctx_data {
45ebfedea0SLionel Sambuc int flags;
46ebfedea0SLionel Sambuc hx509_vprint_func vprint_func;
47ebfedea0SLionel Sambuc void *ctx;
48ebfedea0SLionel Sambuc };
49ebfedea0SLionel Sambuc
50ebfedea0SLionel Sambuc struct cert_status {
51ebfedea0SLionel Sambuc unsigned int selfsigned:1;
52ebfedea0SLionel Sambuc unsigned int isca:1;
53ebfedea0SLionel Sambuc unsigned int isproxy:1;
54ebfedea0SLionel Sambuc unsigned int haveSAN:1;
55ebfedea0SLionel Sambuc unsigned int haveIAN:1;
56ebfedea0SLionel Sambuc unsigned int haveSKI:1;
57ebfedea0SLionel Sambuc unsigned int haveAKI:1;
58ebfedea0SLionel Sambuc unsigned int haveCRLDP:1;
59ebfedea0SLionel Sambuc };
60ebfedea0SLionel Sambuc
61ebfedea0SLionel Sambuc
62ebfedea0SLionel Sambuc /*
63ebfedea0SLionel Sambuc *
64ebfedea0SLionel Sambuc */
65ebfedea0SLionel Sambuc
66ebfedea0SLionel Sambuc static int
Time2string(const Time * T,char ** str)67ebfedea0SLionel Sambuc Time2string(const Time *T, char **str)
68ebfedea0SLionel Sambuc {
69ebfedea0SLionel Sambuc time_t t;
70ebfedea0SLionel Sambuc char *s;
71ebfedea0SLionel Sambuc struct tm *tm;
72ebfedea0SLionel Sambuc
73ebfedea0SLionel Sambuc *str = NULL;
74ebfedea0SLionel Sambuc t = _hx509_Time2time_t(T);
75ebfedea0SLionel Sambuc tm = gmtime (&t);
76ebfedea0SLionel Sambuc s = malloc(30);
77ebfedea0SLionel Sambuc if (s == NULL)
78ebfedea0SLionel Sambuc return ENOMEM;
79ebfedea0SLionel Sambuc strftime(s, 30, "%Y-%m-%d %H:%M:%S", tm);
80ebfedea0SLionel Sambuc *str = s;
81ebfedea0SLionel Sambuc return 0;
82ebfedea0SLionel Sambuc }
83ebfedea0SLionel Sambuc
84ebfedea0SLionel Sambuc /**
85ebfedea0SLionel Sambuc * Helper function to print on stdout for:
86ebfedea0SLionel Sambuc * - hx509_oid_print(),
87ebfedea0SLionel Sambuc * - hx509_bitstring_print(),
88ebfedea0SLionel Sambuc * - hx509_validate_ctx_set_print().
89ebfedea0SLionel Sambuc *
90ebfedea0SLionel Sambuc * @param ctx the context to the print function. If the ctx is NULL,
91ebfedea0SLionel Sambuc * stdout is used.
92ebfedea0SLionel Sambuc * @param fmt the printing format.
93ebfedea0SLionel Sambuc * @param va the argumet list.
94ebfedea0SLionel Sambuc *
95ebfedea0SLionel Sambuc * @ingroup hx509_print
96ebfedea0SLionel Sambuc */
97ebfedea0SLionel Sambuc
98ebfedea0SLionel Sambuc void
hx509_print_stdout(void * ctx,const char * fmt,va_list va)99ebfedea0SLionel Sambuc hx509_print_stdout(void *ctx, const char *fmt, va_list va)
100ebfedea0SLionel Sambuc {
101ebfedea0SLionel Sambuc FILE *f = ctx;
102ebfedea0SLionel Sambuc if (f == NULL)
103ebfedea0SLionel Sambuc f = stdout;
104ebfedea0SLionel Sambuc vfprintf(f, fmt, va);
105ebfedea0SLionel Sambuc }
106ebfedea0SLionel Sambuc
107ebfedea0SLionel Sambuc static void
print_func(hx509_vprint_func func,void * ctx,const char * fmt,...)108ebfedea0SLionel Sambuc print_func(hx509_vprint_func func, void *ctx, const char *fmt, ...)
109ebfedea0SLionel Sambuc {
110ebfedea0SLionel Sambuc va_list va;
111ebfedea0SLionel Sambuc va_start(va, fmt);
112ebfedea0SLionel Sambuc (*func)(ctx, fmt, va);
113ebfedea0SLionel Sambuc va_end(va);
114ebfedea0SLionel Sambuc }
115ebfedea0SLionel Sambuc
116ebfedea0SLionel Sambuc /**
117ebfedea0SLionel Sambuc * Print a oid to a string.
118ebfedea0SLionel Sambuc *
119ebfedea0SLionel Sambuc * @param oid oid to print
120ebfedea0SLionel Sambuc * @param str allocated string, free with hx509_xfree().
121ebfedea0SLionel Sambuc *
122ebfedea0SLionel Sambuc * @return An hx509 error code, see hx509_get_error_string().
123ebfedea0SLionel Sambuc *
124ebfedea0SLionel Sambuc * @ingroup hx509_print
125ebfedea0SLionel Sambuc */
126ebfedea0SLionel Sambuc
127ebfedea0SLionel Sambuc int
hx509_oid_sprint(const heim_oid * oid,char ** str)128ebfedea0SLionel Sambuc hx509_oid_sprint(const heim_oid *oid, char **str)
129ebfedea0SLionel Sambuc {
130ebfedea0SLionel Sambuc return der_print_heim_oid(oid, '.', str);
131ebfedea0SLionel Sambuc }
132ebfedea0SLionel Sambuc
133ebfedea0SLionel Sambuc /**
134ebfedea0SLionel Sambuc * Print a oid using a hx509_vprint_func function. To print to stdout
135ebfedea0SLionel Sambuc * use hx509_print_stdout().
136ebfedea0SLionel Sambuc *
137ebfedea0SLionel Sambuc * @param oid oid to print
138ebfedea0SLionel Sambuc * @param func hx509_vprint_func to print with.
139ebfedea0SLionel Sambuc * @param ctx context variable to hx509_vprint_func function.
140ebfedea0SLionel Sambuc *
141ebfedea0SLionel Sambuc * @ingroup hx509_print
142ebfedea0SLionel Sambuc */
143ebfedea0SLionel Sambuc
144ebfedea0SLionel Sambuc void
hx509_oid_print(const heim_oid * oid,hx509_vprint_func func,void * ctx)145ebfedea0SLionel Sambuc hx509_oid_print(const heim_oid *oid, hx509_vprint_func func, void *ctx)
146ebfedea0SLionel Sambuc {
147ebfedea0SLionel Sambuc char *str;
148ebfedea0SLionel Sambuc hx509_oid_sprint(oid, &str);
149ebfedea0SLionel Sambuc print_func(func, ctx, "%s", str);
150ebfedea0SLionel Sambuc free(str);
151ebfedea0SLionel Sambuc }
152ebfedea0SLionel Sambuc
153ebfedea0SLionel Sambuc /**
154ebfedea0SLionel Sambuc * Print a bitstring using a hx509_vprint_func function. To print to
155ebfedea0SLionel Sambuc * stdout use hx509_print_stdout().
156ebfedea0SLionel Sambuc *
157ebfedea0SLionel Sambuc * @param b bit string to print.
158ebfedea0SLionel Sambuc * @param func hx509_vprint_func to print with.
159ebfedea0SLionel Sambuc * @param ctx context variable to hx509_vprint_func function.
160ebfedea0SLionel Sambuc *
161ebfedea0SLionel Sambuc * @ingroup hx509_print
162ebfedea0SLionel Sambuc */
163ebfedea0SLionel Sambuc
164ebfedea0SLionel Sambuc void
hx509_bitstring_print(const heim_bit_string * b,hx509_vprint_func func,void * ctx)165ebfedea0SLionel Sambuc hx509_bitstring_print(const heim_bit_string *b,
166ebfedea0SLionel Sambuc hx509_vprint_func func, void *ctx)
167ebfedea0SLionel Sambuc {
168*0a6a1f1dSLionel Sambuc size_t i;
169ebfedea0SLionel Sambuc print_func(func, ctx, "\tlength: %d\n\t", b->length);
170ebfedea0SLionel Sambuc for (i = 0; i < (b->length + 7) / 8; i++)
171ebfedea0SLionel Sambuc print_func(func, ctx, "%02x%s%s",
172ebfedea0SLionel Sambuc ((unsigned char *)b->data)[i],
173ebfedea0SLionel Sambuc i < (b->length - 7) / 8
174ebfedea0SLionel Sambuc && (i == 0 || (i % 16) != 15) ? ":" : "",
175ebfedea0SLionel Sambuc i != 0 && (i % 16) == 15 ?
176ebfedea0SLionel Sambuc (i <= ((b->length + 7) / 8 - 2) ? "\n\t" : "\n"):"");
177ebfedea0SLionel Sambuc }
178ebfedea0SLionel Sambuc
179ebfedea0SLionel Sambuc /**
180ebfedea0SLionel Sambuc * Print certificate usage for a certificate to a string.
181ebfedea0SLionel Sambuc *
182ebfedea0SLionel Sambuc * @param context A hx509 context.
183ebfedea0SLionel Sambuc * @param c a certificate print the keyusage for.
184ebfedea0SLionel Sambuc * @param s the return string with the keysage printed in to, free
185ebfedea0SLionel Sambuc * with hx509_xfree().
186ebfedea0SLionel Sambuc *
187ebfedea0SLionel Sambuc * @return An hx509 error code, see hx509_get_error_string().
188ebfedea0SLionel Sambuc *
189ebfedea0SLionel Sambuc * @ingroup hx509_print
190ebfedea0SLionel Sambuc */
191ebfedea0SLionel Sambuc
192ebfedea0SLionel Sambuc int
hx509_cert_keyusage_print(hx509_context context,hx509_cert c,char ** s)193ebfedea0SLionel Sambuc hx509_cert_keyusage_print(hx509_context context, hx509_cert c, char **s)
194ebfedea0SLionel Sambuc {
195ebfedea0SLionel Sambuc KeyUsage ku;
196ebfedea0SLionel Sambuc char buf[256];
197ebfedea0SLionel Sambuc int ret;
198ebfedea0SLionel Sambuc
199ebfedea0SLionel Sambuc *s = NULL;
200ebfedea0SLionel Sambuc
201ebfedea0SLionel Sambuc ret = _hx509_cert_get_keyusage(context, c, &ku);
202ebfedea0SLionel Sambuc if (ret)
203ebfedea0SLionel Sambuc return ret;
204ebfedea0SLionel Sambuc unparse_flags(KeyUsage2int(ku), asn1_KeyUsage_units(), buf, sizeof(buf));
205ebfedea0SLionel Sambuc *s = strdup(buf);
206ebfedea0SLionel Sambuc if (*s == NULL) {
207ebfedea0SLionel Sambuc hx509_set_error_string(context, 0, ENOMEM, "out of memory");
208ebfedea0SLionel Sambuc return ENOMEM;
209ebfedea0SLionel Sambuc }
210ebfedea0SLionel Sambuc
211ebfedea0SLionel Sambuc return 0;
212ebfedea0SLionel Sambuc }
213ebfedea0SLionel Sambuc
214ebfedea0SLionel Sambuc /*
215ebfedea0SLionel Sambuc *
216ebfedea0SLionel Sambuc */
217ebfedea0SLionel Sambuc
218ebfedea0SLionel Sambuc static void
validate_vprint(void * c,const char * fmt,va_list va)219ebfedea0SLionel Sambuc validate_vprint(void *c, const char *fmt, va_list va)
220ebfedea0SLionel Sambuc {
221ebfedea0SLionel Sambuc hx509_validate_ctx ctx = c;
222ebfedea0SLionel Sambuc if (ctx->vprint_func == NULL)
223ebfedea0SLionel Sambuc return;
224ebfedea0SLionel Sambuc (ctx->vprint_func)(ctx->ctx, fmt, va);
225ebfedea0SLionel Sambuc }
226ebfedea0SLionel Sambuc
227ebfedea0SLionel Sambuc static void
validate_print(hx509_validate_ctx ctx,int flags,const char * fmt,...)228ebfedea0SLionel Sambuc validate_print(hx509_validate_ctx ctx, int flags, const char *fmt, ...)
229ebfedea0SLionel Sambuc {
230ebfedea0SLionel Sambuc va_list va;
231ebfedea0SLionel Sambuc if ((ctx->flags & flags) == 0)
232ebfedea0SLionel Sambuc return;
233ebfedea0SLionel Sambuc va_start(va, fmt);
234ebfedea0SLionel Sambuc validate_vprint(ctx, fmt, va);
235ebfedea0SLionel Sambuc va_end(va);
236ebfedea0SLionel Sambuc }
237ebfedea0SLionel Sambuc
238ebfedea0SLionel Sambuc /*
239ebfedea0SLionel Sambuc * Dont Care, SHOULD critical, SHOULD NOT critical, MUST critical,
240ebfedea0SLionel Sambuc * MUST NOT critical
241ebfedea0SLionel Sambuc */
242ebfedea0SLionel Sambuc enum critical_flag { D_C = 0, S_C, S_N_C, M_C, M_N_C };
243ebfedea0SLionel Sambuc
244ebfedea0SLionel Sambuc static int
check_Null(hx509_validate_ctx ctx,struct cert_status * status,enum critical_flag cf,const Extension * e)245ebfedea0SLionel Sambuc check_Null(hx509_validate_ctx ctx,
246ebfedea0SLionel Sambuc struct cert_status *status,
247ebfedea0SLionel Sambuc enum critical_flag cf, const Extension *e)
248ebfedea0SLionel Sambuc {
249ebfedea0SLionel Sambuc switch(cf) {
250ebfedea0SLionel Sambuc case D_C:
251ebfedea0SLionel Sambuc break;
252ebfedea0SLionel Sambuc case S_C:
253ebfedea0SLionel Sambuc if (!e->critical)
254ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
255ebfedea0SLionel Sambuc "\tCritical not set on SHOULD\n");
256ebfedea0SLionel Sambuc break;
257ebfedea0SLionel Sambuc case S_N_C:
258ebfedea0SLionel Sambuc if (e->critical)
259ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
260ebfedea0SLionel Sambuc "\tCritical set on SHOULD NOT\n");
261ebfedea0SLionel Sambuc break;
262ebfedea0SLionel Sambuc case M_C:
263ebfedea0SLionel Sambuc if (!e->critical)
264ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
265ebfedea0SLionel Sambuc "\tCritical not set on MUST\n");
266ebfedea0SLionel Sambuc break;
267ebfedea0SLionel Sambuc case M_N_C:
268ebfedea0SLionel Sambuc if (e->critical)
269ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
270ebfedea0SLionel Sambuc "\tCritical set on MUST NOT\n");
271ebfedea0SLionel Sambuc break;
272ebfedea0SLionel Sambuc default:
273ebfedea0SLionel Sambuc _hx509_abort("internal check_Null state error");
274ebfedea0SLionel Sambuc }
275ebfedea0SLionel Sambuc return 0;
276ebfedea0SLionel Sambuc }
277ebfedea0SLionel Sambuc
278ebfedea0SLionel Sambuc static int
check_subjectKeyIdentifier(hx509_validate_ctx ctx,struct cert_status * status,enum critical_flag cf,const Extension * e)279ebfedea0SLionel Sambuc check_subjectKeyIdentifier(hx509_validate_ctx ctx,
280ebfedea0SLionel Sambuc struct cert_status *status,
281ebfedea0SLionel Sambuc enum critical_flag cf,
282ebfedea0SLionel Sambuc const Extension *e)
283ebfedea0SLionel Sambuc {
284ebfedea0SLionel Sambuc SubjectKeyIdentifier si;
285ebfedea0SLionel Sambuc size_t size;
286ebfedea0SLionel Sambuc int ret;
287ebfedea0SLionel Sambuc
288ebfedea0SLionel Sambuc status->haveSKI = 1;
289ebfedea0SLionel Sambuc check_Null(ctx, status, cf, e);
290ebfedea0SLionel Sambuc
291ebfedea0SLionel Sambuc ret = decode_SubjectKeyIdentifier(e->extnValue.data,
292ebfedea0SLionel Sambuc e->extnValue.length,
293ebfedea0SLionel Sambuc &si, &size);
294ebfedea0SLionel Sambuc if (ret) {
295ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
296ebfedea0SLionel Sambuc "Decoding SubjectKeyIdentifier failed: %d", ret);
297ebfedea0SLionel Sambuc return 1;
298ebfedea0SLionel Sambuc }
299ebfedea0SLionel Sambuc if (size != e->extnValue.length) {
300ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
301ebfedea0SLionel Sambuc "Decoding SKI ahve extra bits on the end");
302ebfedea0SLionel Sambuc return 1;
303ebfedea0SLionel Sambuc }
304ebfedea0SLionel Sambuc if (si.length == 0)
305ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
306ebfedea0SLionel Sambuc "SKI is too short (0 bytes)");
307ebfedea0SLionel Sambuc if (si.length > 20)
308ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
309ebfedea0SLionel Sambuc "SKI is too long");
310ebfedea0SLionel Sambuc
311ebfedea0SLionel Sambuc {
312ebfedea0SLionel Sambuc char *id;
313ebfedea0SLionel Sambuc hex_encode(si.data, si.length, &id);
314ebfedea0SLionel Sambuc if (id) {
315ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
316ebfedea0SLionel Sambuc "\tsubject key id: %s\n", id);
317ebfedea0SLionel Sambuc free(id);
318ebfedea0SLionel Sambuc }
319ebfedea0SLionel Sambuc }
320ebfedea0SLionel Sambuc
321ebfedea0SLionel Sambuc free_SubjectKeyIdentifier(&si);
322ebfedea0SLionel Sambuc
323ebfedea0SLionel Sambuc return 0;
324ebfedea0SLionel Sambuc }
325ebfedea0SLionel Sambuc
326ebfedea0SLionel Sambuc static int
check_authorityKeyIdentifier(hx509_validate_ctx ctx,struct cert_status * status,enum critical_flag cf,const Extension * e)327ebfedea0SLionel Sambuc check_authorityKeyIdentifier(hx509_validate_ctx ctx,
328ebfedea0SLionel Sambuc struct cert_status *status,
329ebfedea0SLionel Sambuc enum critical_flag cf,
330ebfedea0SLionel Sambuc const Extension *e)
331ebfedea0SLionel Sambuc {
332ebfedea0SLionel Sambuc AuthorityKeyIdentifier ai;
333ebfedea0SLionel Sambuc size_t size;
334ebfedea0SLionel Sambuc int ret;
335ebfedea0SLionel Sambuc
336ebfedea0SLionel Sambuc status->haveAKI = 1;
337ebfedea0SLionel Sambuc check_Null(ctx, status, cf, e);
338ebfedea0SLionel Sambuc
339ebfedea0SLionel Sambuc ret = decode_AuthorityKeyIdentifier(e->extnValue.data,
340ebfedea0SLionel Sambuc e->extnValue.length,
341ebfedea0SLionel Sambuc &ai, &size);
342ebfedea0SLionel Sambuc if (ret) {
343ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
344ebfedea0SLionel Sambuc "Decoding AuthorityKeyIdentifier failed: %d", ret);
345ebfedea0SLionel Sambuc return 1;
346ebfedea0SLionel Sambuc }
347ebfedea0SLionel Sambuc if (size != e->extnValue.length) {
348ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
349ebfedea0SLionel Sambuc "Decoding SKI ahve extra bits on the end");
350ebfedea0SLionel Sambuc return 1;
351ebfedea0SLionel Sambuc }
352ebfedea0SLionel Sambuc
353ebfedea0SLionel Sambuc if (ai.keyIdentifier) {
354ebfedea0SLionel Sambuc char *id;
355ebfedea0SLionel Sambuc hex_encode(ai.keyIdentifier->data, ai.keyIdentifier->length, &id);
356ebfedea0SLionel Sambuc if (id) {
357ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
358ebfedea0SLionel Sambuc "\tauthority key id: %s\n", id);
359ebfedea0SLionel Sambuc free(id);
360ebfedea0SLionel Sambuc }
361ebfedea0SLionel Sambuc }
362ebfedea0SLionel Sambuc
363ebfedea0SLionel Sambuc return 0;
364ebfedea0SLionel Sambuc }
365ebfedea0SLionel Sambuc
366ebfedea0SLionel Sambuc static int
check_extKeyUsage(hx509_validate_ctx ctx,struct cert_status * status,enum critical_flag cf,const Extension * e)367ebfedea0SLionel Sambuc check_extKeyUsage(hx509_validate_ctx ctx,
368ebfedea0SLionel Sambuc struct cert_status *status,
369ebfedea0SLionel Sambuc enum critical_flag cf,
370ebfedea0SLionel Sambuc const Extension *e)
371ebfedea0SLionel Sambuc {
372ebfedea0SLionel Sambuc ExtKeyUsage eku;
373ebfedea0SLionel Sambuc size_t size, i;
374ebfedea0SLionel Sambuc int ret;
375ebfedea0SLionel Sambuc
376ebfedea0SLionel Sambuc check_Null(ctx, status, cf, e);
377ebfedea0SLionel Sambuc
378ebfedea0SLionel Sambuc ret = decode_ExtKeyUsage(e->extnValue.data,
379ebfedea0SLionel Sambuc e->extnValue.length,
380ebfedea0SLionel Sambuc &eku, &size);
381ebfedea0SLionel Sambuc if (ret) {
382ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
383ebfedea0SLionel Sambuc "Decoding ExtKeyUsage failed: %d", ret);
384ebfedea0SLionel Sambuc return 1;
385ebfedea0SLionel Sambuc }
386ebfedea0SLionel Sambuc if (size != e->extnValue.length) {
387ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
388ebfedea0SLionel Sambuc "Padding data in EKU");
389ebfedea0SLionel Sambuc free_ExtKeyUsage(&eku);
390ebfedea0SLionel Sambuc return 1;
391ebfedea0SLionel Sambuc }
392ebfedea0SLionel Sambuc if (eku.len == 0) {
393ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
394ebfedea0SLionel Sambuc "ExtKeyUsage length is 0");
395ebfedea0SLionel Sambuc return 1;
396ebfedea0SLionel Sambuc }
397ebfedea0SLionel Sambuc
398ebfedea0SLionel Sambuc for (i = 0; i < eku.len; i++) {
399ebfedea0SLionel Sambuc char *str;
400ebfedea0SLionel Sambuc ret = der_print_heim_oid (&eku.val[i], '.', &str);
401ebfedea0SLionel Sambuc if (ret) {
402ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
403ebfedea0SLionel Sambuc "\tEKU: failed to print oid %d", i);
404ebfedea0SLionel Sambuc free_ExtKeyUsage(&eku);
405ebfedea0SLionel Sambuc return 1;
406ebfedea0SLionel Sambuc }
407ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
408ebfedea0SLionel Sambuc "\teku-%d: %s\n", i, str);;
409ebfedea0SLionel Sambuc free(str);
410ebfedea0SLionel Sambuc }
411ebfedea0SLionel Sambuc
412ebfedea0SLionel Sambuc free_ExtKeyUsage(&eku);
413ebfedea0SLionel Sambuc
414ebfedea0SLionel Sambuc return 0;
415ebfedea0SLionel Sambuc }
416ebfedea0SLionel Sambuc
417ebfedea0SLionel Sambuc static int
check_pkinit_san(hx509_validate_ctx ctx,heim_any * a)418ebfedea0SLionel Sambuc check_pkinit_san(hx509_validate_ctx ctx, heim_any *a)
419ebfedea0SLionel Sambuc {
420ebfedea0SLionel Sambuc KRB5PrincipalName kn;
421ebfedea0SLionel Sambuc unsigned i;
422ebfedea0SLionel Sambuc size_t size;
423ebfedea0SLionel Sambuc int ret;
424ebfedea0SLionel Sambuc
425ebfedea0SLionel Sambuc ret = decode_KRB5PrincipalName(a->data, a->length, &kn, &size);
426ebfedea0SLionel Sambuc if (ret) {
427ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
428ebfedea0SLionel Sambuc "Decoding kerberos name in SAN failed: %d", ret);
429ebfedea0SLionel Sambuc return 1;
430ebfedea0SLionel Sambuc }
431ebfedea0SLionel Sambuc
432ebfedea0SLionel Sambuc if (size != a->length) {
433ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
434ebfedea0SLionel Sambuc "Decoding kerberos name have extra bits on the end");
435ebfedea0SLionel Sambuc return 1;
436ebfedea0SLionel Sambuc }
437ebfedea0SLionel Sambuc
438ebfedea0SLionel Sambuc /* print kerberos principal, add code to quote / within components */
439ebfedea0SLionel Sambuc for (i = 0; i < kn.principalName.name_string.len; i++) {
440ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s",
441ebfedea0SLionel Sambuc kn.principalName.name_string.val[i]);
442ebfedea0SLionel Sambuc if (i + 1 < kn.principalName.name_string.len)
443ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "/");
444ebfedea0SLionel Sambuc }
445ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "@");
446ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s", kn.realm);
447ebfedea0SLionel Sambuc
448ebfedea0SLionel Sambuc free_KRB5PrincipalName(&kn);
449ebfedea0SLionel Sambuc return 0;
450ebfedea0SLionel Sambuc }
451ebfedea0SLionel Sambuc
452ebfedea0SLionel Sambuc static int
check_utf8_string_san(hx509_validate_ctx ctx,heim_any * a)453ebfedea0SLionel Sambuc check_utf8_string_san(hx509_validate_ctx ctx, heim_any *a)
454ebfedea0SLionel Sambuc {
455ebfedea0SLionel Sambuc PKIXXmppAddr jid;
456ebfedea0SLionel Sambuc size_t size;
457ebfedea0SLionel Sambuc int ret;
458ebfedea0SLionel Sambuc
459ebfedea0SLionel Sambuc ret = decode_PKIXXmppAddr(a->data, a->length, &jid, &size);
460ebfedea0SLionel Sambuc if (ret) {
461ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
462ebfedea0SLionel Sambuc "Decoding JID in SAN failed: %d", ret);
463ebfedea0SLionel Sambuc return 1;
464ebfedea0SLionel Sambuc }
465ebfedea0SLionel Sambuc
466ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s", jid);
467ebfedea0SLionel Sambuc free_PKIXXmppAddr(&jid);
468ebfedea0SLionel Sambuc
469ebfedea0SLionel Sambuc return 0;
470ebfedea0SLionel Sambuc }
471ebfedea0SLionel Sambuc
472ebfedea0SLionel Sambuc static int
check_altnull(hx509_validate_ctx ctx,heim_any * a)473ebfedea0SLionel Sambuc check_altnull(hx509_validate_ctx ctx, heim_any *a)
474ebfedea0SLionel Sambuc {
475ebfedea0SLionel Sambuc return 0;
476ebfedea0SLionel Sambuc }
477ebfedea0SLionel Sambuc
478ebfedea0SLionel Sambuc static int
check_CRLDistributionPoints(hx509_validate_ctx ctx,struct cert_status * status,enum critical_flag cf,const Extension * e)479ebfedea0SLionel Sambuc check_CRLDistributionPoints(hx509_validate_ctx ctx,
480ebfedea0SLionel Sambuc struct cert_status *status,
481ebfedea0SLionel Sambuc enum critical_flag cf,
482ebfedea0SLionel Sambuc const Extension *e)
483ebfedea0SLionel Sambuc {
484ebfedea0SLionel Sambuc CRLDistributionPoints dp;
485ebfedea0SLionel Sambuc size_t size;
486*0a6a1f1dSLionel Sambuc int ret;
487*0a6a1f1dSLionel Sambuc size_t i;
488ebfedea0SLionel Sambuc
489ebfedea0SLionel Sambuc check_Null(ctx, status, cf, e);
490ebfedea0SLionel Sambuc
491ebfedea0SLionel Sambuc ret = decode_CRLDistributionPoints(e->extnValue.data,
492ebfedea0SLionel Sambuc e->extnValue.length,
493ebfedea0SLionel Sambuc &dp, &size);
494ebfedea0SLionel Sambuc if (ret) {
495ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
496ebfedea0SLionel Sambuc "Decoding CRL Distribution Points failed: %d\n", ret);
497ebfedea0SLionel Sambuc return 1;
498ebfedea0SLionel Sambuc }
499ebfedea0SLionel Sambuc
500ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "CRL Distribution Points:\n");
501ebfedea0SLionel Sambuc for (i = 0 ; i < dp.len; i++) {
502ebfedea0SLionel Sambuc if (dp.val[i].distributionPoint) {
503ebfedea0SLionel Sambuc DistributionPointName dpname;
504ebfedea0SLionel Sambuc heim_any *data = dp.val[i].distributionPoint;
505*0a6a1f1dSLionel Sambuc size_t j;
506ebfedea0SLionel Sambuc
507ebfedea0SLionel Sambuc ret = decode_DistributionPointName(data->data, data->length,
508ebfedea0SLionel Sambuc &dpname, NULL);
509ebfedea0SLionel Sambuc if (ret) {
510ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
511ebfedea0SLionel Sambuc "Failed to parse CRL Distribution Point Name: %d\n", ret);
512ebfedea0SLionel Sambuc continue;
513ebfedea0SLionel Sambuc }
514ebfedea0SLionel Sambuc
515ebfedea0SLionel Sambuc switch (dpname.element) {
516ebfedea0SLionel Sambuc case choice_DistributionPointName_fullName:
517ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "Fullname:\n");
518ebfedea0SLionel Sambuc
519ebfedea0SLionel Sambuc for (j = 0 ; j < dpname.u.fullName.len; j++) {
520ebfedea0SLionel Sambuc char *s;
521ebfedea0SLionel Sambuc GeneralName *name = &dpname.u.fullName.val[j];
522ebfedea0SLionel Sambuc
523ebfedea0SLionel Sambuc ret = hx509_general_name_unparse(name, &s);
524ebfedea0SLionel Sambuc if (ret == 0 && s != NULL) {
525ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE, " %s\n", s);
526ebfedea0SLionel Sambuc free(s);
527ebfedea0SLionel Sambuc }
528ebfedea0SLionel Sambuc }
529ebfedea0SLionel Sambuc break;
530ebfedea0SLionel Sambuc case choice_DistributionPointName_nameRelativeToCRLIssuer:
531ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
532ebfedea0SLionel Sambuc "Unknown nameRelativeToCRLIssuer");
533ebfedea0SLionel Sambuc break;
534ebfedea0SLionel Sambuc default:
535ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
536ebfedea0SLionel Sambuc "Unknown DistributionPointName");
537ebfedea0SLionel Sambuc break;
538ebfedea0SLionel Sambuc }
539ebfedea0SLionel Sambuc free_DistributionPointName(&dpname);
540ebfedea0SLionel Sambuc }
541ebfedea0SLionel Sambuc }
542ebfedea0SLionel Sambuc free_CRLDistributionPoints(&dp);
543ebfedea0SLionel Sambuc
544ebfedea0SLionel Sambuc status->haveCRLDP = 1;
545ebfedea0SLionel Sambuc
546ebfedea0SLionel Sambuc return 0;
547ebfedea0SLionel Sambuc }
548ebfedea0SLionel Sambuc
549ebfedea0SLionel Sambuc
550ebfedea0SLionel Sambuc struct {
551ebfedea0SLionel Sambuc const char *name;
552ebfedea0SLionel Sambuc const heim_oid *oid;
553ebfedea0SLionel Sambuc int (*func)(hx509_validate_ctx, heim_any *);
554ebfedea0SLionel Sambuc } altname_types[] = {
555ebfedea0SLionel Sambuc { "pk-init", &asn1_oid_id_pkinit_san, check_pkinit_san },
556ebfedea0SLionel Sambuc { "jabber", &asn1_oid_id_pkix_on_xmppAddr, check_utf8_string_san },
557ebfedea0SLionel Sambuc { "dns-srv", &asn1_oid_id_pkix_on_dnsSRV, check_altnull },
558ebfedea0SLionel Sambuc { "card-id", &asn1_oid_id_uspkicommon_card_id, check_altnull },
559ebfedea0SLionel Sambuc { "Microsoft NT-PRINCIPAL-NAME", &asn1_oid_id_pkinit_ms_san, check_utf8_string_san }
560ebfedea0SLionel Sambuc };
561ebfedea0SLionel Sambuc
562ebfedea0SLionel Sambuc static int
check_altName(hx509_validate_ctx ctx,struct cert_status * status,const char * name,enum critical_flag cf,const Extension * e)563ebfedea0SLionel Sambuc check_altName(hx509_validate_ctx ctx,
564ebfedea0SLionel Sambuc struct cert_status *status,
565ebfedea0SLionel Sambuc const char *name,
566ebfedea0SLionel Sambuc enum critical_flag cf,
567ebfedea0SLionel Sambuc const Extension *e)
568ebfedea0SLionel Sambuc {
569ebfedea0SLionel Sambuc GeneralNames gn;
570ebfedea0SLionel Sambuc size_t size;
571*0a6a1f1dSLionel Sambuc int ret;
572*0a6a1f1dSLionel Sambuc size_t i;
573ebfedea0SLionel Sambuc
574ebfedea0SLionel Sambuc check_Null(ctx, status, cf, e);
575ebfedea0SLionel Sambuc
576ebfedea0SLionel Sambuc if (e->extnValue.length == 0) {
577ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
578ebfedea0SLionel Sambuc "%sAltName empty, not allowed", name);
579ebfedea0SLionel Sambuc return 1;
580ebfedea0SLionel Sambuc }
581ebfedea0SLionel Sambuc ret = decode_GeneralNames(e->extnValue.data, e->extnValue.length,
582ebfedea0SLionel Sambuc &gn, &size);
583ebfedea0SLionel Sambuc if (ret) {
584ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
585ebfedea0SLionel Sambuc "\tret = %d while decoding %s GeneralNames\n",
586ebfedea0SLionel Sambuc ret, name);
587ebfedea0SLionel Sambuc return 1;
588ebfedea0SLionel Sambuc }
589ebfedea0SLionel Sambuc if (gn.len == 0) {
590ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
591ebfedea0SLionel Sambuc "%sAltName generalName empty, not allowed\n", name);
592ebfedea0SLionel Sambuc return 1;
593ebfedea0SLionel Sambuc }
594ebfedea0SLionel Sambuc
595ebfedea0SLionel Sambuc for (i = 0; i < gn.len; i++) {
596ebfedea0SLionel Sambuc switch (gn.val[i].element) {
597ebfedea0SLionel Sambuc case choice_GeneralName_otherName: {
598ebfedea0SLionel Sambuc unsigned j;
599ebfedea0SLionel Sambuc
600ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
601ebfedea0SLionel Sambuc "%sAltName otherName ", name);
602ebfedea0SLionel Sambuc
603ebfedea0SLionel Sambuc for (j = 0; j < sizeof(altname_types)/sizeof(altname_types[0]); j++) {
604ebfedea0SLionel Sambuc if (der_heim_oid_cmp(altname_types[j].oid,
605ebfedea0SLionel Sambuc &gn.val[i].u.otherName.type_id) != 0)
606ebfedea0SLionel Sambuc continue;
607ebfedea0SLionel Sambuc
608ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s: ",
609ebfedea0SLionel Sambuc altname_types[j].name);
610ebfedea0SLionel Sambuc (*altname_types[j].func)(ctx, &gn.val[i].u.otherName.value);
611ebfedea0SLionel Sambuc break;
612ebfedea0SLionel Sambuc }
613ebfedea0SLionel Sambuc if (j == sizeof(altname_types)/sizeof(altname_types[0])) {
614ebfedea0SLionel Sambuc hx509_oid_print(&gn.val[i].u.otherName.type_id,
615ebfedea0SLionel Sambuc validate_vprint, ctx);
616ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE, " unknown");
617ebfedea0SLionel Sambuc }
618ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\n");
619ebfedea0SLionel Sambuc break;
620ebfedea0SLionel Sambuc }
621ebfedea0SLionel Sambuc default: {
622ebfedea0SLionel Sambuc char *s;
623ebfedea0SLionel Sambuc ret = hx509_general_name_unparse(&gn.val[i], &s);
624ebfedea0SLionel Sambuc if (ret) {
625ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
626ebfedea0SLionel Sambuc "ret = %d unparsing GeneralName\n", ret);
627ebfedea0SLionel Sambuc return 1;
628ebfedea0SLionel Sambuc }
629ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "%s\n", s);
630ebfedea0SLionel Sambuc free(s);
631ebfedea0SLionel Sambuc break;
632ebfedea0SLionel Sambuc }
633ebfedea0SLionel Sambuc }
634ebfedea0SLionel Sambuc }
635ebfedea0SLionel Sambuc
636ebfedea0SLionel Sambuc free_GeneralNames(&gn);
637ebfedea0SLionel Sambuc
638ebfedea0SLionel Sambuc return 0;
639ebfedea0SLionel Sambuc }
640ebfedea0SLionel Sambuc
641ebfedea0SLionel Sambuc static int
check_subjectAltName(hx509_validate_ctx ctx,struct cert_status * status,enum critical_flag cf,const Extension * e)642ebfedea0SLionel Sambuc check_subjectAltName(hx509_validate_ctx ctx,
643ebfedea0SLionel Sambuc struct cert_status *status,
644ebfedea0SLionel Sambuc enum critical_flag cf,
645ebfedea0SLionel Sambuc const Extension *e)
646ebfedea0SLionel Sambuc {
647ebfedea0SLionel Sambuc status->haveSAN = 1;
648ebfedea0SLionel Sambuc return check_altName(ctx, status, "subject", cf, e);
649ebfedea0SLionel Sambuc }
650ebfedea0SLionel Sambuc
651ebfedea0SLionel Sambuc static int
check_issuerAltName(hx509_validate_ctx ctx,struct cert_status * status,enum critical_flag cf,const Extension * e)652ebfedea0SLionel Sambuc check_issuerAltName(hx509_validate_ctx ctx,
653ebfedea0SLionel Sambuc struct cert_status *status,
654ebfedea0SLionel Sambuc enum critical_flag cf,
655ebfedea0SLionel Sambuc const Extension *e)
656ebfedea0SLionel Sambuc {
657ebfedea0SLionel Sambuc status->haveIAN = 1;
658ebfedea0SLionel Sambuc return check_altName(ctx, status, "issuer", cf, e);
659ebfedea0SLionel Sambuc }
660ebfedea0SLionel Sambuc
661ebfedea0SLionel Sambuc
662ebfedea0SLionel Sambuc static int
check_basicConstraints(hx509_validate_ctx ctx,struct cert_status * status,enum critical_flag cf,const Extension * e)663ebfedea0SLionel Sambuc check_basicConstraints(hx509_validate_ctx ctx,
664ebfedea0SLionel Sambuc struct cert_status *status,
665ebfedea0SLionel Sambuc enum critical_flag cf,
666ebfedea0SLionel Sambuc const Extension *e)
667ebfedea0SLionel Sambuc {
668ebfedea0SLionel Sambuc BasicConstraints b;
669ebfedea0SLionel Sambuc size_t size;
670ebfedea0SLionel Sambuc int ret;
671ebfedea0SLionel Sambuc
672ebfedea0SLionel Sambuc check_Null(ctx, status, cf, e);
673ebfedea0SLionel Sambuc
674ebfedea0SLionel Sambuc ret = decode_BasicConstraints(e->extnValue.data, e->extnValue.length,
675ebfedea0SLionel Sambuc &b, &size);
676ebfedea0SLionel Sambuc if (ret) {
677ebfedea0SLionel Sambuc printf("\tret = %d while decoding BasicConstraints\n", ret);
678ebfedea0SLionel Sambuc return 0;
679ebfedea0SLionel Sambuc }
680ebfedea0SLionel Sambuc if (size != e->extnValue.length)
681ebfedea0SLionel Sambuc printf("\tlength of der data isn't same as extension\n");
682ebfedea0SLionel Sambuc
683ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
684ebfedea0SLionel Sambuc "\tis %sa CA\n", b.cA && *b.cA ? "" : "NOT ");
685ebfedea0SLionel Sambuc if (b.pathLenConstraint)
686ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
687ebfedea0SLionel Sambuc "\tpathLenConstraint: %d\n", *b.pathLenConstraint);
688ebfedea0SLionel Sambuc
689ebfedea0SLionel Sambuc if (b.cA) {
690ebfedea0SLionel Sambuc if (*b.cA) {
691ebfedea0SLionel Sambuc if (!e->critical)
692ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
693ebfedea0SLionel Sambuc "Is a CA and not BasicConstraints CRITICAL\n");
694ebfedea0SLionel Sambuc status->isca = 1;
695ebfedea0SLionel Sambuc }
696ebfedea0SLionel Sambuc else
697ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
698ebfedea0SLionel Sambuc "cA is FALSE, not allowed to be\n");
699ebfedea0SLionel Sambuc }
700ebfedea0SLionel Sambuc free_BasicConstraints(&b);
701ebfedea0SLionel Sambuc
702ebfedea0SLionel Sambuc return 0;
703ebfedea0SLionel Sambuc }
704ebfedea0SLionel Sambuc
705ebfedea0SLionel Sambuc static int
check_proxyCertInfo(hx509_validate_ctx ctx,struct cert_status * status,enum critical_flag cf,const Extension * e)706ebfedea0SLionel Sambuc check_proxyCertInfo(hx509_validate_ctx ctx,
707ebfedea0SLionel Sambuc struct cert_status *status,
708ebfedea0SLionel Sambuc enum critical_flag cf,
709ebfedea0SLionel Sambuc const Extension *e)
710ebfedea0SLionel Sambuc {
711ebfedea0SLionel Sambuc check_Null(ctx, status, cf, e);
712ebfedea0SLionel Sambuc status->isproxy = 1;
713ebfedea0SLionel Sambuc return 0;
714ebfedea0SLionel Sambuc }
715ebfedea0SLionel Sambuc
716ebfedea0SLionel Sambuc static int
check_authorityInfoAccess(hx509_validate_ctx ctx,struct cert_status * status,enum critical_flag cf,const Extension * e)717ebfedea0SLionel Sambuc check_authorityInfoAccess(hx509_validate_ctx ctx,
718ebfedea0SLionel Sambuc struct cert_status *status,
719ebfedea0SLionel Sambuc enum critical_flag cf,
720ebfedea0SLionel Sambuc const Extension *e)
721ebfedea0SLionel Sambuc {
722ebfedea0SLionel Sambuc AuthorityInfoAccessSyntax aia;
723ebfedea0SLionel Sambuc size_t size;
724*0a6a1f1dSLionel Sambuc int ret;
725*0a6a1f1dSLionel Sambuc size_t i;
726ebfedea0SLionel Sambuc
727ebfedea0SLionel Sambuc check_Null(ctx, status, cf, e);
728ebfedea0SLionel Sambuc
729ebfedea0SLionel Sambuc ret = decode_AuthorityInfoAccessSyntax(e->extnValue.data,
730ebfedea0SLionel Sambuc e->extnValue.length,
731ebfedea0SLionel Sambuc &aia, &size);
732ebfedea0SLionel Sambuc if (ret) {
733ebfedea0SLionel Sambuc printf("\tret = %d while decoding AuthorityInfoAccessSyntax\n", ret);
734ebfedea0SLionel Sambuc return 0;
735ebfedea0SLionel Sambuc }
736ebfedea0SLionel Sambuc
737ebfedea0SLionel Sambuc for (i = 0; i < aia.len; i++) {
738ebfedea0SLionel Sambuc char *str;
739ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
740ebfedea0SLionel Sambuc "\ttype: ");
741ebfedea0SLionel Sambuc hx509_oid_print(&aia.val[i].accessMethod, validate_vprint, ctx);
742ebfedea0SLionel Sambuc hx509_general_name_unparse(&aia.val[i].accessLocation, &str);
743ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
744ebfedea0SLionel Sambuc "\n\tdirname: %s\n", str);
745ebfedea0SLionel Sambuc free(str);
746ebfedea0SLionel Sambuc }
747ebfedea0SLionel Sambuc free_AuthorityInfoAccessSyntax(&aia);
748ebfedea0SLionel Sambuc
749ebfedea0SLionel Sambuc return 0;
750ebfedea0SLionel Sambuc }
751ebfedea0SLionel Sambuc
752ebfedea0SLionel Sambuc /*
753ebfedea0SLionel Sambuc *
754ebfedea0SLionel Sambuc */
755ebfedea0SLionel Sambuc
756ebfedea0SLionel Sambuc struct {
757ebfedea0SLionel Sambuc const char *name;
758ebfedea0SLionel Sambuc const heim_oid *oid;
759ebfedea0SLionel Sambuc int (*func)(hx509_validate_ctx ctx,
760ebfedea0SLionel Sambuc struct cert_status *status,
761ebfedea0SLionel Sambuc enum critical_flag cf,
762ebfedea0SLionel Sambuc const Extension *);
763ebfedea0SLionel Sambuc enum critical_flag cf;
764ebfedea0SLionel Sambuc } check_extension[] = {
765ebfedea0SLionel Sambuc #define ext(name, checkname) #name, &asn1_oid_id_x509_ce_##name, check_##checkname
766ebfedea0SLionel Sambuc { ext(subjectDirectoryAttributes, Null), M_N_C },
767ebfedea0SLionel Sambuc { ext(subjectKeyIdentifier, subjectKeyIdentifier), M_N_C },
768ebfedea0SLionel Sambuc { ext(keyUsage, Null), S_C },
769ebfedea0SLionel Sambuc { ext(subjectAltName, subjectAltName), M_N_C },
770ebfedea0SLionel Sambuc { ext(issuerAltName, issuerAltName), S_N_C },
771ebfedea0SLionel Sambuc { ext(basicConstraints, basicConstraints), D_C },
772ebfedea0SLionel Sambuc { ext(cRLNumber, Null), M_N_C },
773ebfedea0SLionel Sambuc { ext(cRLReason, Null), M_N_C },
774ebfedea0SLionel Sambuc { ext(holdInstructionCode, Null), M_N_C },
775ebfedea0SLionel Sambuc { ext(invalidityDate, Null), M_N_C },
776ebfedea0SLionel Sambuc { ext(deltaCRLIndicator, Null), M_C },
777ebfedea0SLionel Sambuc { ext(issuingDistributionPoint, Null), M_C },
778ebfedea0SLionel Sambuc { ext(certificateIssuer, Null), M_C },
779ebfedea0SLionel Sambuc { ext(nameConstraints, Null), M_C },
780ebfedea0SLionel Sambuc { ext(cRLDistributionPoints, CRLDistributionPoints), S_N_C },
781*0a6a1f1dSLionel Sambuc { ext(certificatePolicies, Null), 0 },
782ebfedea0SLionel Sambuc { ext(policyMappings, Null), M_N_C },
783ebfedea0SLionel Sambuc { ext(authorityKeyIdentifier, authorityKeyIdentifier), M_N_C },
784ebfedea0SLionel Sambuc { ext(policyConstraints, Null), D_C },
785ebfedea0SLionel Sambuc { ext(extKeyUsage, extKeyUsage), D_C },
786ebfedea0SLionel Sambuc { ext(freshestCRL, Null), M_N_C },
787ebfedea0SLionel Sambuc { ext(inhibitAnyPolicy, Null), M_C },
788ebfedea0SLionel Sambuc #undef ext
789ebfedea0SLionel Sambuc #define ext(name, checkname) #name, &asn1_oid_id_pkix_pe_##name, check_##checkname
790ebfedea0SLionel Sambuc { ext(proxyCertInfo, proxyCertInfo), M_C },
791ebfedea0SLionel Sambuc { ext(authorityInfoAccess, authorityInfoAccess), M_C },
792ebfedea0SLionel Sambuc #undef ext
793ebfedea0SLionel Sambuc { "US Fed PKI - PIV Interim", &asn1_oid_id_uspkicommon_piv_interim,
794ebfedea0SLionel Sambuc check_Null, D_C },
795ebfedea0SLionel Sambuc { "Netscape cert comment", &asn1_oid_id_netscape_cert_comment,
796ebfedea0SLionel Sambuc check_Null, D_C },
797*0a6a1f1dSLionel Sambuc { NULL, NULL, NULL, 0 }
798ebfedea0SLionel Sambuc };
799ebfedea0SLionel Sambuc
800ebfedea0SLionel Sambuc /**
801ebfedea0SLionel Sambuc * Allocate a hx509 validation/printing context.
802ebfedea0SLionel Sambuc *
803ebfedea0SLionel Sambuc * @param context A hx509 context.
804ebfedea0SLionel Sambuc * @param ctx a new allocated hx509 validation context, free with
805ebfedea0SLionel Sambuc * hx509_validate_ctx_free().
806ebfedea0SLionel Sambuc
807ebfedea0SLionel Sambuc * @return An hx509 error code, see hx509_get_error_string().
808ebfedea0SLionel Sambuc *
809ebfedea0SLionel Sambuc * @ingroup hx509_print
810ebfedea0SLionel Sambuc */
811ebfedea0SLionel Sambuc
812ebfedea0SLionel Sambuc int
hx509_validate_ctx_init(hx509_context context,hx509_validate_ctx * ctx)813ebfedea0SLionel Sambuc hx509_validate_ctx_init(hx509_context context, hx509_validate_ctx *ctx)
814ebfedea0SLionel Sambuc {
815ebfedea0SLionel Sambuc *ctx = malloc(sizeof(**ctx));
816ebfedea0SLionel Sambuc if (*ctx == NULL)
817ebfedea0SLionel Sambuc return ENOMEM;
818ebfedea0SLionel Sambuc memset(*ctx, 0, sizeof(**ctx));
819ebfedea0SLionel Sambuc return 0;
820ebfedea0SLionel Sambuc }
821ebfedea0SLionel Sambuc
822ebfedea0SLionel Sambuc /**
823ebfedea0SLionel Sambuc * Set the printing functions for the validation context.
824ebfedea0SLionel Sambuc *
825ebfedea0SLionel Sambuc * @param ctx a hx509 valication context.
826ebfedea0SLionel Sambuc * @param func the printing function to usea.
827ebfedea0SLionel Sambuc * @param c the context variable to the printing function.
828ebfedea0SLionel Sambuc *
829ebfedea0SLionel Sambuc * @return An hx509 error code, see hx509_get_error_string().
830ebfedea0SLionel Sambuc *
831ebfedea0SLionel Sambuc * @ingroup hx509_print
832ebfedea0SLionel Sambuc */
833ebfedea0SLionel Sambuc
834ebfedea0SLionel Sambuc void
hx509_validate_ctx_set_print(hx509_validate_ctx ctx,hx509_vprint_func func,void * c)835ebfedea0SLionel Sambuc hx509_validate_ctx_set_print(hx509_validate_ctx ctx,
836ebfedea0SLionel Sambuc hx509_vprint_func func,
837ebfedea0SLionel Sambuc void *c)
838ebfedea0SLionel Sambuc {
839ebfedea0SLionel Sambuc ctx->vprint_func = func;
840ebfedea0SLionel Sambuc ctx->ctx = c;
841ebfedea0SLionel Sambuc }
842ebfedea0SLionel Sambuc
843ebfedea0SLionel Sambuc /**
844ebfedea0SLionel Sambuc * Add flags to control the behaivor of the hx509_validate_cert()
845ebfedea0SLionel Sambuc * function.
846ebfedea0SLionel Sambuc *
847ebfedea0SLionel Sambuc * @param ctx A hx509 validation context.
848ebfedea0SLionel Sambuc * @param flags flags to add to the validation context.
849ebfedea0SLionel Sambuc *
850ebfedea0SLionel Sambuc * @return An hx509 error code, see hx509_get_error_string().
851ebfedea0SLionel Sambuc *
852ebfedea0SLionel Sambuc * @ingroup hx509_print
853ebfedea0SLionel Sambuc */
854ebfedea0SLionel Sambuc
855ebfedea0SLionel Sambuc void
hx509_validate_ctx_add_flags(hx509_validate_ctx ctx,int flags)856ebfedea0SLionel Sambuc hx509_validate_ctx_add_flags(hx509_validate_ctx ctx, int flags)
857ebfedea0SLionel Sambuc {
858ebfedea0SLionel Sambuc ctx->flags |= flags;
859ebfedea0SLionel Sambuc }
860ebfedea0SLionel Sambuc
861ebfedea0SLionel Sambuc /**
862ebfedea0SLionel Sambuc * Free an hx509 validate context.
863ebfedea0SLionel Sambuc *
864ebfedea0SLionel Sambuc * @param ctx the hx509 validate context to free.
865ebfedea0SLionel Sambuc *
866ebfedea0SLionel Sambuc * @ingroup hx509_print
867ebfedea0SLionel Sambuc */
868ebfedea0SLionel Sambuc
869ebfedea0SLionel Sambuc void
hx509_validate_ctx_free(hx509_validate_ctx ctx)870ebfedea0SLionel Sambuc hx509_validate_ctx_free(hx509_validate_ctx ctx)
871ebfedea0SLionel Sambuc {
872ebfedea0SLionel Sambuc free(ctx);
873ebfedea0SLionel Sambuc }
874ebfedea0SLionel Sambuc
875ebfedea0SLionel Sambuc /**
876ebfedea0SLionel Sambuc * Validate/Print the status of the certificate.
877ebfedea0SLionel Sambuc *
878ebfedea0SLionel Sambuc * @param context A hx509 context.
879ebfedea0SLionel Sambuc * @param ctx A hx509 validation context.
880ebfedea0SLionel Sambuc * @param cert the cerificate to validate/print.
881ebfedea0SLionel Sambuc
882ebfedea0SLionel Sambuc * @return An hx509 error code, see hx509_get_error_string().
883ebfedea0SLionel Sambuc *
884ebfedea0SLionel Sambuc * @ingroup hx509_print
885ebfedea0SLionel Sambuc */
886ebfedea0SLionel Sambuc
887ebfedea0SLionel Sambuc int
hx509_validate_cert(hx509_context context,hx509_validate_ctx ctx,hx509_cert cert)888ebfedea0SLionel Sambuc hx509_validate_cert(hx509_context context,
889ebfedea0SLionel Sambuc hx509_validate_ctx ctx,
890ebfedea0SLionel Sambuc hx509_cert cert)
891ebfedea0SLionel Sambuc {
892ebfedea0SLionel Sambuc Certificate *c = _hx509_get_cert(cert);
893ebfedea0SLionel Sambuc TBSCertificate *t = &c->tbsCertificate;
894ebfedea0SLionel Sambuc hx509_name issuer, subject;
895ebfedea0SLionel Sambuc char *str;
896ebfedea0SLionel Sambuc struct cert_status status;
897ebfedea0SLionel Sambuc int ret;
898ebfedea0SLionel Sambuc
899ebfedea0SLionel Sambuc memset(&status, 0, sizeof(status));
900ebfedea0SLionel Sambuc
901ebfedea0SLionel Sambuc if (_hx509_cert_get_version(c) != 3)
902ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
903ebfedea0SLionel Sambuc "Not version 3 certificate\n");
904ebfedea0SLionel Sambuc
905ebfedea0SLionel Sambuc if ((t->version == NULL || *t->version < 2) && t->extensions)
906ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
907ebfedea0SLionel Sambuc "Not version 3 certificate with extensions\n");
908ebfedea0SLionel Sambuc
909ebfedea0SLionel Sambuc if (_hx509_cert_get_version(c) >= 3 && t->extensions == NULL)
910ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
911ebfedea0SLionel Sambuc "Version 3 certificate without extensions\n");
912ebfedea0SLionel Sambuc
913ebfedea0SLionel Sambuc ret = hx509_cert_get_subject(cert, &subject);
914ebfedea0SLionel Sambuc if (ret) abort();
915ebfedea0SLionel Sambuc hx509_name_to_string(subject, &str);
916ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
917ebfedea0SLionel Sambuc "subject name: %s\n", str);
918ebfedea0SLionel Sambuc free(str);
919ebfedea0SLionel Sambuc
920ebfedea0SLionel Sambuc ret = hx509_cert_get_issuer(cert, &issuer);
921ebfedea0SLionel Sambuc if (ret) abort();
922ebfedea0SLionel Sambuc hx509_name_to_string(issuer, &str);
923ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
924ebfedea0SLionel Sambuc "issuer name: %s\n", str);
925ebfedea0SLionel Sambuc free(str);
926ebfedea0SLionel Sambuc
927ebfedea0SLionel Sambuc if (hx509_name_cmp(subject, issuer) == 0) {
928ebfedea0SLionel Sambuc status.selfsigned = 1;
929ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
930ebfedea0SLionel Sambuc "\tis a self-signed certificate\n");
931ebfedea0SLionel Sambuc }
932ebfedea0SLionel Sambuc
933ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
934ebfedea0SLionel Sambuc "Validity:\n");
935ebfedea0SLionel Sambuc
936ebfedea0SLionel Sambuc Time2string(&t->validity.notBefore, &str);
937ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\tnotBefore %s\n", str);
938ebfedea0SLionel Sambuc free(str);
939ebfedea0SLionel Sambuc Time2string(&t->validity.notAfter, &str);
940ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "\tnotAfter %s\n", str);
941ebfedea0SLionel Sambuc free(str);
942ebfedea0SLionel Sambuc
943ebfedea0SLionel Sambuc if (t->extensions) {
944*0a6a1f1dSLionel Sambuc size_t i, j;
945ebfedea0SLionel Sambuc
946ebfedea0SLionel Sambuc if (t->extensions->len == 0) {
947ebfedea0SLionel Sambuc validate_print(ctx,
948ebfedea0SLionel Sambuc HX509_VALIDATE_F_VALIDATE|HX509_VALIDATE_F_VERBOSE,
949ebfedea0SLionel Sambuc "The empty extensions list is not "
950ebfedea0SLionel Sambuc "allowed by PKIX\n");
951ebfedea0SLionel Sambuc }
952ebfedea0SLionel Sambuc
953ebfedea0SLionel Sambuc for (i = 0; i < t->extensions->len; i++) {
954ebfedea0SLionel Sambuc
955ebfedea0SLionel Sambuc for (j = 0; check_extension[j].name; j++)
956ebfedea0SLionel Sambuc if (der_heim_oid_cmp(check_extension[j].oid,
957ebfedea0SLionel Sambuc &t->extensions->val[i].extnID) == 0)
958ebfedea0SLionel Sambuc break;
959ebfedea0SLionel Sambuc if (check_extension[j].name == NULL) {
960ebfedea0SLionel Sambuc int flags = HX509_VALIDATE_F_VERBOSE;
961ebfedea0SLionel Sambuc if (t->extensions->val[i].critical)
962ebfedea0SLionel Sambuc flags |= HX509_VALIDATE_F_VALIDATE;
963ebfedea0SLionel Sambuc validate_print(ctx, flags, "don't know what ");
964ebfedea0SLionel Sambuc if (t->extensions->val[i].critical)
965ebfedea0SLionel Sambuc validate_print(ctx, flags, "and is CRITICAL ");
966ebfedea0SLionel Sambuc if (ctx->flags & flags)
967ebfedea0SLionel Sambuc hx509_oid_print(&t->extensions->val[i].extnID,
968ebfedea0SLionel Sambuc validate_vprint, ctx);
969ebfedea0SLionel Sambuc validate_print(ctx, flags, " is\n");
970ebfedea0SLionel Sambuc continue;
971ebfedea0SLionel Sambuc }
972ebfedea0SLionel Sambuc validate_print(ctx,
973ebfedea0SLionel Sambuc HX509_VALIDATE_F_VALIDATE|HX509_VALIDATE_F_VERBOSE,
974ebfedea0SLionel Sambuc "checking extention: %s\n",
975ebfedea0SLionel Sambuc check_extension[j].name);
976ebfedea0SLionel Sambuc (*check_extension[j].func)(ctx,
977ebfedea0SLionel Sambuc &status,
978ebfedea0SLionel Sambuc check_extension[j].cf,
979ebfedea0SLionel Sambuc &t->extensions->val[i]);
980ebfedea0SLionel Sambuc }
981ebfedea0SLionel Sambuc } else
982ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE, "no extentions\n");
983ebfedea0SLionel Sambuc
984ebfedea0SLionel Sambuc if (status.isca) {
985ebfedea0SLionel Sambuc if (!status.haveSKI)
986ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
987ebfedea0SLionel Sambuc "CA certificate have no SubjectKeyIdentifier\n");
988ebfedea0SLionel Sambuc
989ebfedea0SLionel Sambuc } else {
990ebfedea0SLionel Sambuc if (!status.haveAKI)
991ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
992ebfedea0SLionel Sambuc "Is not CA and doesn't have "
993ebfedea0SLionel Sambuc "AuthorityKeyIdentifier\n");
994ebfedea0SLionel Sambuc }
995ebfedea0SLionel Sambuc
996ebfedea0SLionel Sambuc
997ebfedea0SLionel Sambuc if (!status.haveSKI)
998ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
999ebfedea0SLionel Sambuc "Doesn't have SubjectKeyIdentifier\n");
1000ebfedea0SLionel Sambuc
1001ebfedea0SLionel Sambuc if (status.isproxy && status.isca)
1002ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
1003ebfedea0SLionel Sambuc "Proxy and CA at the same time!\n");
1004ebfedea0SLionel Sambuc
1005ebfedea0SLionel Sambuc if (status.isproxy) {
1006ebfedea0SLionel Sambuc if (status.haveSAN)
1007ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
1008ebfedea0SLionel Sambuc "Proxy and have SAN\n");
1009ebfedea0SLionel Sambuc if (status.haveIAN)
1010ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
1011ebfedea0SLionel Sambuc "Proxy and have IAN\n");
1012ebfedea0SLionel Sambuc }
1013ebfedea0SLionel Sambuc
1014ebfedea0SLionel Sambuc if (hx509_name_is_null_p(subject) && !status.haveSAN)
1015ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
1016ebfedea0SLionel Sambuc "NULL subject DN and doesn't have a SAN\n");
1017ebfedea0SLionel Sambuc
1018ebfedea0SLionel Sambuc if (!status.selfsigned && !status.haveCRLDP)
1019ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
1020ebfedea0SLionel Sambuc "Not a CA nor PROXY and doesn't have"
1021ebfedea0SLionel Sambuc "CRL Dist Point\n");
1022ebfedea0SLionel Sambuc
1023ebfedea0SLionel Sambuc if (status.selfsigned) {
1024ebfedea0SLionel Sambuc ret = _hx509_verify_signature_bitstring(context,
1025ebfedea0SLionel Sambuc cert,
1026ebfedea0SLionel Sambuc &c->signatureAlgorithm,
1027ebfedea0SLionel Sambuc &c->tbsCertificate._save,
1028ebfedea0SLionel Sambuc &c->signatureValue);
1029ebfedea0SLionel Sambuc if (ret == 0)
1030ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VERBOSE,
1031ebfedea0SLionel Sambuc "Self-signed certificate was self-signed\n");
1032ebfedea0SLionel Sambuc else
1033ebfedea0SLionel Sambuc validate_print(ctx, HX509_VALIDATE_F_VALIDATE,
1034ebfedea0SLionel Sambuc "Self-signed certificate NOT really self-signed!\n");
1035ebfedea0SLionel Sambuc }
1036ebfedea0SLionel Sambuc
1037ebfedea0SLionel Sambuc hx509_name_free(&subject);
1038ebfedea0SLionel Sambuc hx509_name_free(&issuer);
1039ebfedea0SLionel Sambuc
1040ebfedea0SLionel Sambuc return 0;
1041ebfedea0SLionel Sambuc }
1042