Bug Summary

File:src/sbin/isakmpd/x509.c
Warning:line 699, column 2
Value stored to 'size' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name x509.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sbin/isakmpd/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/sbin/isakmpd -I . -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/sbin/isakmpd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/sbin/isakmpd/x509.c
1/* $OpenBSD: x509.c,v 1.124 2021/11/19 23:15:59 tb Exp $ */
2/* $EOM: x509.c,v 1.54 2001/01/16 18:42:16 ho Exp $ */
3
4/*
5 * Copyright (c) 1998, 1999 Niels Provos. All rights reserved.
6 * Copyright (c) 1999, 2000, 2001 Niklas Hallqvist. All rights reserved.
7 * Copyright (c) 1999, 2000, 2001 Angelos D. Keromytis. All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/*
31 * This code was written under funding by Ericsson Radio Systems.
32 */
33
34#include <sys/types.h>
35#include <sys/stat.h>
36#include <dirent.h>
37#include <errno(*__errno()).h>
38#include <fcntl.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <unistd.h>
43#include <limits.h>
44
45#include <regex.h>
46#include <keynote.h>
47
48#include "cert.h"
49#include "conf.h"
50#include "exchange.h"
51#include "hash.h"
52#include "ike_auth.h"
53#include "ipsec.h"
54#include "log.h"
55#include "dh.h"
56#include "monitor.h"
57#include "policy.h"
58#include "sa.h"
59#include "util.h"
60#include "x509.h"
61
62static u_int16_t x509_hash(u_int8_t *, size_t);
63static void x509_hash_init(void);
64static X509 *x509_hash_find(u_int8_t *, size_t);
65static int x509_hash_enter(X509 *);
66
67/*
68 * X509_STOREs do not support subjectAltNames, so we have to build
69 * our own hash table.
70 */
71
72/*
73 * XXX Actually this store is not really useful, we never use it as we have
74 * our own hash table. It also gets collisions if we have several certificates
75 * only differing in subjectAltName.
76 */
77static X509_STORE *x509_certs = 0;
78static X509_STORE *x509_cas = 0;
79
80static int n_x509_cas = 0;
81
82/* Initial number of bits used as hash. */
83#define INITIAL_BUCKET_BITS6 6
84
85struct x509_hash {
86 LIST_ENTRY(x509_hash)struct { struct x509_hash *le_next; struct x509_hash **le_prev
; }
link;
87
88 X509 *cert;
89};
90
91static LIST_HEAD(x509_list, x509_hash)struct x509_list { struct x509_hash *lh_first; } *x509_tab = 0;
92
93/* Works both as a maximum index and a mask. */
94static int bucket_mask;
95
96/*
97 * Given an X509 certificate, create a KeyNote assertion where
98 * Issuer/Subject -> Authorizer/Licensees.
99 * XXX RSA-specific.
100 */
101int
102x509_generate_kn(int id, X509 *cert)
103{
104 static const char fmt[] = "Authorizer: \"rsa-hex:%s\"\nLicensees: \"rsa-hex:%s"
105 "\"\nConditions: %s >= \"%s\" && %s <= \"%s\";\n";
106 char *ikey = NULL((void*)0), *skey = NULL((void*)0), *buf = NULL((void*)0);
107 char isname[256], subname[256];
108 static const char fmt2[] = "Authorizer: \"DN:%s\"\nLicensees: \"DN:%s\"\n"
109 "Conditions: %s >= \"%s\" && %s <= \"%s\";\n";
110 X509_NAME *issuer, *subject;
111 struct keynote_deckey dc;
112 X509_STORE_CTX *csc = NULL((void*)0);
113 X509_OBJECT *obj = NULL((void*)0);
114 X509 *icert;
115 RSA *key = NULL((void*)0);
116 time_t tt;
117 char before[15], after[15], *timecomp, *timecomp2;
118 ASN1_TIME *tm;
119 int i;
120
121 LOG_DBG((LOG_POLICY, 90,log_debug (LOG_POLICY, 90, "x509_generate_kn: generating KeyNote policy for certificate %p"
, cert)
122 "x509_generate_kn: generating KeyNote policy for certificate %p",log_debug (LOG_POLICY, 90, "x509_generate_kn: generating KeyNote policy for certificate %p"
, cert)
123 cert))log_debug (LOG_POLICY, 90, "x509_generate_kn: generating KeyNote policy for certificate %p"
, cert)
;
124
125 issuer = X509_get_issuer_name(cert);
126 subject = X509_get_subject_name(cert);
127
128 /* Missing or self-signed, ignore cert but don't report failure. */
129 if (!issuer || !subject || !X509_NAME_cmp(issuer, subject))
130 return 1;
131
132 if (!x509_cert_get_key(cert, &key)) {
133 LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: failed to get public key from cert"
)
134 "x509_generate_kn: failed to get public key from cert"))log_debug (LOG_POLICY, 30, "x509_generate_kn: failed to get public key from cert"
)
;
135 return 0;
136 }
137 dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA6;
138 dc.dec_key = key;
139 ikey = kn_encode_key(&dc, INTERNAL_ENC_PKCS11, ENCODING_HEX1,
140 KEYNOTE_PUBLIC_KEY0);
141 if (keynote_errno == ERROR_MEMORY-1) {
142 log_print("x509_generate_kn: failed to get memory for "
143 "public key");
144 LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get "log_debug (LOG_POLICY, 30, "x509_generate_kn: cannot get " "subject key"
)
145 "subject key"))log_debug (LOG_POLICY, 30, "x509_generate_kn: cannot get " "subject key"
)
;
146 goto fail;
147 }
148 if (!ikey) {
149 LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get "log_debug (LOG_POLICY, 30, "x509_generate_kn: cannot get " "subject key"
)
150 "subject key"))log_debug (LOG_POLICY, 30, "x509_generate_kn: cannot get " "subject key"
)
;
151 goto fail;
152 }
153
154 RSA_free(key);
155 key = NULL((void*)0);
156
157 csc = X509_STORE_CTX_new();
158 if (csc == NULL((void*)0)) {
159 log_print("x509_generate_kn: failed to get memory for "
160 "certificate store");
161 goto fail;
162 }
163 obj = X509_OBJECT_new();
164 if (obj == NULL((void*)0)) {
165 log_print("x509_generate_kn: failed to get memory for "
166 "certificate object");
167 goto fail;
168 }
169
170 /* Now find issuer's certificate so we can get the public key. */
171 X509_STORE_CTX_init(csc, x509_cas, cert, NULL((void*)0));
172 if (X509_STORE_get_by_subjectX509_STORE_CTX_get_by_subject(csc, X509_LU_X509, issuer, obj) !=
173 X509_LU_X509) {
174 X509_STORE_CTX_cleanup(csc);
175 X509_STORE_CTX_init(csc, x509_certs, cert, NULL((void*)0));
176 if (X509_STORE_get_by_subjectX509_STORE_CTX_get_by_subject(csc, X509_LU_X509, issuer, obj)
177 != X509_LU_X509) {
178 X509_STORE_CTX_cleanup(csc);
179 LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: no certificate found for "
"issuer")
180 "x509_generate_kn: no certificate found for "log_debug (LOG_POLICY, 30, "x509_generate_kn: no certificate found for "
"issuer")
181 "issuer"))log_debug (LOG_POLICY, 30, "x509_generate_kn: no certificate found for "
"issuer")
;
182 goto fail;
183 }
184 }
185 X509_STORE_CTX_free(csc);
186 csc = NULL((void*)0);
187
188 icert = X509_OBJECT_get0_X509(obj);
189 if (icert == NULL((void*)0)) {
190 LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: "log_debug (LOG_POLICY, 30, "x509_generate_kn: " "missing certificates, cannot construct X509 chain"
)
191 "missing certificates, cannot construct X509 chain"))log_debug (LOG_POLICY, 30, "x509_generate_kn: " "missing certificates, cannot construct X509 chain"
)
;
192 goto fail;
193 }
194 if (!x509_cert_get_key(icert, &key)) {
195 LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: failed to get public key from cert"
)
196 "x509_generate_kn: failed to get public key from cert"))log_debug (LOG_POLICY, 30, "x509_generate_kn: failed to get public key from cert"
)
;
197 goto fail;
198 }
199 X509_OBJECT_free(obj);
200 obj = NULL((void*)0);
201
202 dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA6;
203 dc.dec_key = key;
204 skey = kn_encode_key(&dc, INTERNAL_ENC_PKCS11, ENCODING_HEX1,
205 KEYNOTE_PUBLIC_KEY0);
206 if (keynote_errno == ERROR_MEMORY-1) {
207 log_error("x509_generate_kn: failed to get memory for public "
208 "key");
209 LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get issuer "log_debug (LOG_POLICY, 30, "x509_generate_kn: cannot get issuer "
"key")
210 "key"))log_debug (LOG_POLICY, 30, "x509_generate_kn: cannot get issuer "
"key")
;
211 goto fail;
212 }
213 if (!skey) {
214 LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get issuer "log_debug (LOG_POLICY, 30, "x509_generate_kn: cannot get issuer "
"key")
215 "key"))log_debug (LOG_POLICY, 30, "x509_generate_kn: cannot get issuer "
"key")
;
216 goto fail;
217 }
218
219 RSA_free(key);
220 key = NULL((void*)0);
221
222 if (((tm = X509_get_notBeforeX509_getm_notBefore(cert)) == NULL((void*)0)) ||
223 (tm->type != V_ASN1_UTCTIME23 &&
224 tm->type != V_ASN1_GENERALIZEDTIME24)) {
225 tt = time(0);
226 strftime(before, 14, "%Y%m%d%H%M%S", localtime(&tt));
227 timecomp = "LocalTimeOfDay";
228 } else {
229 if (tm->data[tm->length - 1] == 'Z') {
230 timecomp = "GMTTimeOfDay";
231 i = tm->length - 2;
232 } else {
233 timecomp = "LocalTimeOfDay";
234 i = tm->length - 1;
235 }
236
237 for (; i >= 0; i--) {
238 if (tm->data[i] < '0' || tm->data[i] > '9') {
239 LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid data in "
"NotValidBefore time field")
240 "x509_generate_kn: invalid data in "log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid data in "
"NotValidBefore time field")
241 "NotValidBefore time field"))log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid data in "
"NotValidBefore time field")
;
242 goto fail;
243 }
244 }
245
246 if (tm->type == V_ASN1_UTCTIME23) {
247 if ((tm->length < 10) || (tm->length > 13)) {
248 LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length "
"of NotValidBefore time field (%d)", tm->length)
249 "x509_generate_kn: invalid length "log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length "
"of NotValidBefore time field (%d)", tm->length)
250 "of NotValidBefore time field (%d)",log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length "
"of NotValidBefore time field (%d)", tm->length)
251 tm->length))log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length "
"of NotValidBefore time field (%d)", tm->length)
;
252 goto fail;
253 }
254 /* Validity checks. */
255 if ((tm->data[2] != '0' && tm->data[2] != '1') ||
256 (tm->data[2] == '0' && tm->data[3] == '0') ||
257 (tm->data[2] == '1' && tm->data[3] > '2') ||
258 (tm->data[4] > '3') ||
259 (tm->data[4] == '0' && tm->data[5] == '0') ||
260 (tm->data[4] == '3' && tm->data[5] > '1') ||
261 (tm->data[6] > '2') ||
262 (tm->data[6] == '2' && tm->data[7] > '3') ||
263 (tm->data[8] > '5')) {
264 LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid value in "
"NotValidBefore time field")
265 "x509_generate_kn: invalid value in "log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid value in "
"NotValidBefore time field")
266 "NotValidBefore time field"))log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid value in "
"NotValidBefore time field")
;
267 goto fail;
268 }
269 /* Stupid UTC tricks. */
270 if (tm->data[0] < '5')
271 snprintf(before, sizeof before, "20%s",
272 tm->data);
273 else
274 snprintf(before, sizeof before, "19%s",
275 tm->data);
276 } else { /* V_ASN1_GENERICTIME */
277 if ((tm->length < 12) || (tm->length > 15)) {
278 LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length of "
"NotValidBefore time field (%d)", tm->length)
279 "x509_generate_kn: invalid length of "log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length of "
"NotValidBefore time field (%d)", tm->length)
280 "NotValidBefore time field (%d)",log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length of "
"NotValidBefore time field (%d)", tm->length)
281 tm->length))log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length of "
"NotValidBefore time field (%d)", tm->length)
;
282 goto fail;
283 }
284 /* Validity checks. */
285 if ((tm->data[4] != '0' && tm->data[4] != '1') ||
286 (tm->data[4] == '0' && tm->data[5] == '0') ||
287 (tm->data[4] == '1' && tm->data[5] > '2') ||
288 (tm->data[6] > '3') ||
289 (tm->data[6] == '0' && tm->data[7] == '0') ||
290 (tm->data[6] == '3' && tm->data[7] > '1') ||
291 (tm->data[8] > '2') ||
292 (tm->data[8] == '2' && tm->data[9] > '3') ||
293 (tm->data[10] > '5')) {
294 LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid value in "
"NotValidBefore time field")
295 "x509_generate_kn: invalid value in "log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid value in "
"NotValidBefore time field")
296 "NotValidBefore time field"))log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid value in "
"NotValidBefore time field")
;
297 goto fail;
298 }
299 snprintf(before, sizeof before, "%s", tm->data);
300 }
301
302 /* Fix missing seconds. */
303 if (tm->length < 12) {
304 before[12] = '0';
305 before[13] = '0';
306 }
307 /* This will overwrite trailing 'Z'. */
308 before[14] = '\0';
309 }
310
311 tm = X509_get_notAfterX509_getm_notAfter(cert);
312 if (tm == NULL((void*)0) ||
313 (tm->type != V_ASN1_UTCTIME23 &&
314 tm->type != V_ASN1_GENERALIZEDTIME24)) {
315 tt = time(0);
316 strftime(after, 14, "%Y%m%d%H%M%S", localtime(&tt));
317 timecomp2 = "LocalTimeOfDay";
318 } else {
319 if (tm->data[tm->length - 1] == 'Z') {
320 timecomp2 = "GMTTimeOfDay";
321 i = tm->length - 2;
322 } else {
323 timecomp2 = "LocalTimeOfDay";
324 i = tm->length - 1;
325 }
326
327 for (; i >= 0; i--) {
328 if (tm->data[i] < '0' || tm->data[i] > '9') {
329 LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid data in "
"NotValidAfter time field")
330 "x509_generate_kn: invalid data in "log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid data in "
"NotValidAfter time field")
331 "NotValidAfter time field"))log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid data in "
"NotValidAfter time field")
;
332 goto fail;
333 }
334 }
335
336 if (tm->type == V_ASN1_UTCTIME23) {
337 if ((tm->length < 10) || (tm->length > 13)) {
338 LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length of "
"NotValidAfter time field (%d)", tm->length)
339 "x509_generate_kn: invalid length of "log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length of "
"NotValidAfter time field (%d)", tm->length)
340 "NotValidAfter time field (%d)",log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length of "
"NotValidAfter time field (%d)", tm->length)
341 tm->length))log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length of "
"NotValidAfter time field (%d)", tm->length)
;
342 goto fail;
343 }
344 /* Validity checks. */
345 if ((tm->data[2] != '0' && tm->data[2] != '1') ||
346 (tm->data[2] == '0' && tm->data[3] == '0') ||
347 (tm->data[2] == '1' && tm->data[3] > '2') ||
348 (tm->data[4] > '3') ||
349 (tm->data[4] == '0' && tm->data[5] == '0') ||
350 (tm->data[4] == '3' && tm->data[5] > '1') ||
351 (tm->data[6] > '2') ||
352 (tm->data[6] == '2' && tm->data[7] > '3') ||
353 (tm->data[8] > '5')) {
354 LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid value in "
"NotValidAfter time field")
355 "x509_generate_kn: invalid value in "log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid value in "
"NotValidAfter time field")
356 "NotValidAfter time field"))log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid value in "
"NotValidAfter time field")
;
357 goto fail;
358 }
359 /* Stupid UTC tricks. */
360 if (tm->data[0] < '5')
361 snprintf(after, sizeof after, "20%s",
362 tm->data);
363 else
364 snprintf(after, sizeof after, "19%s",
365 tm->data);
366 } else { /* V_ASN1_GENERICTIME */
367 if ((tm->length < 12) || (tm->length > 15)) {
368 LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length of "
"NotValidAfter time field (%d)", tm->length)
369 "x509_generate_kn: invalid length of "log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length of "
"NotValidAfter time field (%d)", tm->length)
370 "NotValidAfter time field (%d)",log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length of "
"NotValidAfter time field (%d)", tm->length)
371 tm->length))log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid length of "
"NotValidAfter time field (%d)", tm->length)
;
372 goto fail;
373 }
374 /* Validity checks. */
375 if ((tm->data[4] != '0' && tm->data[4] != '1') ||
376 (tm->data[4] == '0' && tm->data[5] == '0') ||
377 (tm->data[4] == '1' && tm->data[5] > '2') ||
378 (tm->data[6] > '3') ||
379 (tm->data[6] == '0' && tm->data[7] == '0') ||
380 (tm->data[6] == '3' && tm->data[7] > '1') ||
381 (tm->data[8] > '2') ||
382 (tm->data[8] == '2' && tm->data[9] > '3') ||
383 (tm->data[10] > '5')) {
384 LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid value in "
"NotValidAfter time field")
385 "x509_generate_kn: invalid value in "log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid value in "
"NotValidAfter time field")
386 "NotValidAfter time field"))log_debug (LOG_POLICY, 30, "x509_generate_kn: invalid value in "
"NotValidAfter time field")
;
387 goto fail;
388 }
389 snprintf(after, sizeof after, "%s", tm->data);
390 }
391
392 /* Fix missing seconds. */
393 if (tm->length < 12) {
394 after[12] = '0';
395 after[13] = '0';
396 }
397 after[14] = '\0'; /* This will overwrite trailing 'Z' */
398 }
399
400 if (asprintf(&buf, fmt, skey, ikey, timecomp, before, timecomp2,
401 after) == -1) {
402 log_error("x509_generate_kn: "
403 "failed to allocate memory for KeyNote credential");
404 goto fail;
405 }
406
407 free(ikey);
408 ikey = NULL((void*)0);
409 free(skey);
410 skey = NULL((void*)0);
411
412 if (kn_add_assertion(id, buf, strlen(buf), ASSERT_FLAG_LOCAL0x0001) == -1) {
413 LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: failed to add new KeyNote credential"
)
414 "x509_generate_kn: failed to add new KeyNote credential"))log_debug (LOG_POLICY, 30, "x509_generate_kn: failed to add new KeyNote credential"
)
;
415 goto fail;
416 }
417 /* We could print the assertion here, but log_print() truncates... */
418 LOG_DBG((LOG_POLICY, 60, "x509_generate_kn: added credential"))log_debug (LOG_POLICY, 60, "x509_generate_kn: added credential"
)
;
419
420 free(buf);
421 buf = NULL((void*)0);
422
423 if (!X509_NAME_oneline(issuer, isname, 256)) {
424 LOG_DBG((LOG_POLICY, 50,log_debug (LOG_POLICY, 50, "x509_generate_kn: " "X509_NAME_oneline (issuer, ...) failed"
)
425 "x509_generate_kn: "log_debug (LOG_POLICY, 50, "x509_generate_kn: " "X509_NAME_oneline (issuer, ...) failed"
)
426 "X509_NAME_oneline (issuer, ...) failed"))log_debug (LOG_POLICY, 50, "x509_generate_kn: " "X509_NAME_oneline (issuer, ...) failed"
)
;
427 goto fail;
428 }
429 if (!X509_NAME_oneline(subject, subname, 256)) {
430 LOG_DBG((LOG_POLICY, 50,log_debug (LOG_POLICY, 50, "x509_generate_kn: " "X509_NAME_oneline (subject, ...) failed"
)
431 "x509_generate_kn: "log_debug (LOG_POLICY, 50, "x509_generate_kn: " "X509_NAME_oneline (subject, ...) failed"
)
432 "X509_NAME_oneline (subject, ...) failed"))log_debug (LOG_POLICY, 50, "x509_generate_kn: " "X509_NAME_oneline (subject, ...) failed"
)
;
433 goto fail;
434 }
435 if (asprintf(&buf, fmt2, isname, subname, timecomp, before,
436 timecomp2, after) == -1) {
437 log_error("x509_generate_kn: malloc failed");
438 return 0;
439 }
440
441 if (kn_add_assertion(id, buf, strlen(buf), ASSERT_FLAG_LOCAL0x0001) == -1) {
442 LOG_DBG((LOG_POLICY, 30,log_debug (LOG_POLICY, 30, "x509_generate_kn: failed to add new KeyNote credential"
)
443 "x509_generate_kn: failed to add new KeyNote credential"))log_debug (LOG_POLICY, 30, "x509_generate_kn: failed to add new KeyNote credential"
)
;
444 goto fail;
445 }
446 LOG_DBG((LOG_POLICY, 80, "x509_generate_kn: added credential:\n%s",log_debug (LOG_POLICY, 80, "x509_generate_kn: added credential:\n%s"
, buf)
447 buf))log_debug (LOG_POLICY, 80, "x509_generate_kn: added credential:\n%s"
, buf)
;
448
449 free(buf);
450 return 1;
451
452fail:
453 X509_STORE_CTX_free(csc);
454 X509_OBJECT_free(obj);
455 free(buf);
456 free(skey);
457 free(ikey);
458 if (key)
459 RSA_free(key);
460
461 return 0;
462}
463
464static u_int16_t
465x509_hash(u_int8_t *id, size_t len)
466{
467 u_int16_t bucket = 0;
468 size_t i;
469
470 /* XXX We might resize if we are crossing a certain threshold. */
471 for (i = 4; i < (len & ~1); i += 2) {
472 /* Doing it this way avoids alignment problems. */
473 bucket ^= (id[i] + 1) * (id[i + 1] + 257);
474 }
475 /* Hash in the last character of odd length IDs too. */
476 if (i < len)
477 bucket ^= (id[i] + 1) * (id[i] + 257);
478
479 bucket &= bucket_mask;
480 return bucket;
481}
482
483static void
484x509_hash_init(void)
485{
486 struct x509_hash *certh;
487 int i;
488
489 bucket_mask = (1 << INITIAL_BUCKET_BITS6) - 1;
490
491 /* If reinitializing, free existing entries. */
492 if (x509_tab) {
493 for (i = 0; i <= bucket_mask; i++)
494 for (certh = LIST_FIRST(&x509_tab[i])((&x509_tab[i])->lh_first); certh;
495 certh = LIST_FIRST(&x509_tab[i])((&x509_tab[i])->lh_first)) {
496 LIST_REMOVE(certh, link)do { if ((certh)->link.le_next != ((void*)0)) (certh)->
link.le_next->link.le_prev = (certh)->link.le_prev; *(certh
)->link.le_prev = (certh)->link.le_next; ; ; } while (0
)
;
497 free(certh);
498 }
499 free(x509_tab);
500 }
501 x509_tab = calloc(bucket_mask + 1, sizeof(struct x509_list));
502 if (!x509_tab)
503 log_fatal("x509_hash_init: malloc (%lu) failed",
504 (bucket_mask + 1) *
505 (unsigned long)sizeof(struct x509_list));
506 for (i = 0; i <= bucket_mask; i++) {
507 LIST_INIT(&x509_tab[i])do { ((&x509_tab[i])->lh_first) = ((void*)0); } while (
0)
;
508 }
509}
510
511/* Lookup a certificate by an ID blob. */
512static X509 *
513x509_hash_find(u_int8_t *id, size_t len)
514{
515 struct x509_hash *cert;
516 u_int8_t **cid;
517 u_int32_t *clen;
518 int n, i, id_found;
519
520 for (cert = LIST_FIRST(&x509_tab[x509_hash(id, len)])((&x509_tab[x509_hash(id, len)])->lh_first); cert;
521 cert = LIST_NEXT(cert, link)((cert)->link.le_next)) {
522 if (!x509_cert_get_subjects(cert->cert, &n, &cid, &clen))
523 continue;
524
525 id_found = 0;
526 for (i = 0; i < n; i++) {
527 LOG_DBG_BUF((LOG_CRYPTO, 70, "cert_cmp", id, len))log_debug_buf (LOG_CRYPTO, 70, "cert_cmp", id, len);
528 LOG_DBG_BUF((LOG_CRYPTO, 70, "cert_cmp", cid[i],log_debug_buf (LOG_CRYPTO, 70, "cert_cmp", cid[i], clen[i])
529 clen[i]))log_debug_buf (LOG_CRYPTO, 70, "cert_cmp", cid[i], clen[i]);
530 /*
531 * XXX This identity predicate needs to be
532 * understood.
533 */
534 if (clen[i] == len && id[0] == cid[i][0] &&
535 memcmp(id + 4, cid[i] + 4, len - 4) == 0) {
536 id_found++;
537 break;
538 }
539 }
540 cert_free_subjects(n, cid, clen);
541 if (!id_found)
542 continue;
543
544 LOG_DBG((LOG_CRYPTO, 70, "x509_hash_find: return X509 %p",log_debug (LOG_CRYPTO, 70, "x509_hash_find: return X509 %p", cert
->cert)
545 cert->cert))log_debug (LOG_CRYPTO, 70, "x509_hash_find: return X509 %p", cert
->cert)
;
546 return cert->cert;
547 }
548
549 LOG_DBG((LOG_CRYPTO, 70,log_debug (LOG_CRYPTO, 70, "x509_hash_find: no certificate matched query"
)
550 "x509_hash_find: no certificate matched query"))log_debug (LOG_CRYPTO, 70, "x509_hash_find: no certificate matched query"
)
;
551 return 0;
552}
553
554static int
555x509_hash_enter(X509 *cert)
556{
557 u_int16_t bucket = 0;
558 u_int8_t **id;
559 u_int32_t *len;
560 struct x509_hash *certh;
561 int n, i;
562
563 if (!x509_cert_get_subjects(cert, &n, &id, &len)) {
564 log_print("x509_hash_enter: cannot retrieve subjects");
565 return 0;
566 }
567 for (i = 0; i < n; i++) {
568 certh = calloc(1, sizeof *certh);
569 if (!certh) {
570 cert_free_subjects(n, id, len);
571 log_error("x509_hash_enter: calloc (1, %lu) failed",
572 (unsigned long)sizeof *certh);
573 return 0;
574 }
575 certh->cert = cert;
576
577 bucket = x509_hash(id[i], len[i]);
578
579 LIST_INSERT_HEAD(&x509_tab[bucket], certh, link)do { if (((certh)->link.le_next = (&x509_tab[bucket])->
lh_first) != ((void*)0)) (&x509_tab[bucket])->lh_first
->link.le_prev = &(certh)->link.le_next; (&x509_tab
[bucket])->lh_first = (certh); (certh)->link.le_prev = &
(&x509_tab[bucket])->lh_first; } while (0)
;
580 LOG_DBG((LOG_CRYPTO, 70,log_debug (LOG_CRYPTO, 70, "x509_hash_enter: cert %p added to bucket %d"
, cert, bucket)
581 "x509_hash_enter: cert %p added to bucket %d",log_debug (LOG_CRYPTO, 70, "x509_hash_enter: cert %p added to bucket %d"
, cert, bucket)
582 cert, bucket))log_debug (LOG_CRYPTO, 70, "x509_hash_enter: cert %p added to bucket %d"
, cert, bucket)
;
583 }
584 cert_free_subjects(n, id, len);
585
586 return 1;
587}
588
589/* X509 Certificate Handling functions. */
590
591int
592x509_read_from_dir(X509_STORE *ctx, char *name, int hash, int *pcount)
593{
594 FILE *certfp;
595 X509 *cert;
596 struct stat sb;
597 char fullname[PATH_MAX1024];
598 char file[PATH_MAX1024];
599 int fd;
600
601 if (strlen(name) >= sizeof fullname - 1) {
602 log_print("x509_read_from_dir: directory name too long");
603 return 0;
604 }
605 LOG_DBG((LOG_CRYPTO, 40, "x509_read_from_dir: reading certs from %s",log_debug (LOG_CRYPTO, 40, "x509_read_from_dir: reading certs from %s"
, name)
606 name))log_debug (LOG_CRYPTO, 40, "x509_read_from_dir: reading certs from %s"
, name)
;
607
608 if (monitor_req_readdir(name) == -1) {
609 LOG_DBG((LOG_CRYPTO, 10,log_debug (LOG_CRYPTO, 10, "x509_read_from_dir: opendir (\"%s\") failed: %s"
, name, strerror((*__errno())))
610 "x509_read_from_dir: opendir (\"%s\") failed: %s",log_debug (LOG_CRYPTO, 10, "x509_read_from_dir: opendir (\"%s\") failed: %s"
, name, strerror((*__errno())))
611 name, strerror(errno)))log_debug (LOG_CRYPTO, 10, "x509_read_from_dir: opendir (\"%s\") failed: %s"
, name, strerror((*__errno())))
;
612 return 0;
613 }
614
615 while ((fd = monitor_readdir(file, sizeof file)) != -1) {
616 LOG_DBG((LOG_CRYPTO, 60,log_debug (LOG_CRYPTO, 60, "x509_read_from_dir: reading certificate %s"
, file)
617 "x509_read_from_dir: reading certificate %s",log_debug (LOG_CRYPTO, 60, "x509_read_from_dir: reading certificate %s"
, file)
618 file))log_debug (LOG_CRYPTO, 60, "x509_read_from_dir: reading certificate %s"
, file)
;
619
620 if (fstat(fd, &sb) == -1) {
621 log_error("x509_read_from_dir: fstat failed");
622 close(fd);
623 continue;
624 }
625
626 if (!S_ISREG(sb.st_mode)((sb.st_mode & 0170000) == 0100000)) {
627 close(fd);
628 continue;
629 }
630
631 if ((certfp = fdopen(fd, "r")) == NULL((void*)0)) {
632 log_error("x509_read_from_dir: fdopen failed");
633 close(fd);
634 continue;
635 }
636
637#if SSLEAY_VERSION_NUMBER0x20000000L >= 0x00904100L
638 cert = PEM_read_X509(certfp, NULL((void*)0), NULL((void*)0), NULL((void*)0));
639#else
640 cert = PEM_read_X509(certfp, NULL((void*)0), NULL((void*)0));
641#endif
642 fclose(certfp);
643
644 if (cert == NULL((void*)0)) {
645 log_print("x509_read_from_dir: PEM_read_X509 "
646 "failed for %s", file);
647 continue;
648 }
649
650 if (pcount != NULL((void*)0))
651 (*pcount)++;
652
653 if (!X509_STORE_add_cert(ctx, cert)) {
654 /*
655 * This is actually expected if we have several
656 * certificates only differing in subjectAltName,
657 * which is not an something that is strange.
658 * Consider multi-homed machines.
659 */
660 LOG_DBG((LOG_CRYPTO, 50,log_debug (LOG_CRYPTO, 50, "x509_read_from_dir: X509_STORE_add_cert failed "
"for %s", file)
661 "x509_read_from_dir: X509_STORE_add_cert failed "log_debug (LOG_CRYPTO, 50, "x509_read_from_dir: X509_STORE_add_cert failed "
"for %s", file)
662 "for %s", file))log_debug (LOG_CRYPTO, 50, "x509_read_from_dir: X509_STORE_add_cert failed "
"for %s", file)
;
663 }
664 if (hash)
665 if (!x509_hash_enter(cert))
666 log_print("x509_read_from_dir: "
667 "x509_hash_enter (%s) failed",
668 file);
669 }
670
671 return 1;
672}
673
674/* XXX share code with x509_read_from_dir() ? */
675int
676x509_read_crls_from_dir(X509_STORE *ctx, char *name)
677{
678 FILE *crlfp;
679 X509_CRL *crl;
680 struct stat sb;
681 char fullname[PATH_MAX1024];
682 char file[PATH_MAX1024];
683 int fd, off, size;
684
685 if (strlen(name) >= sizeof fullname - 1) {
686 log_print("x509_read_crls_from_dir: directory name too long");
687 return 0;
688 }
689 LOG_DBG((LOG_CRYPTO, 40, "x509_read_crls_from_dir: reading CRLs "log_debug (LOG_CRYPTO, 40, "x509_read_crls_from_dir: reading CRLs "
"from %s", name)
690 "from %s", name))log_debug (LOG_CRYPTO, 40, "x509_read_crls_from_dir: reading CRLs "
"from %s", name)
;
691
692 if (monitor_req_readdir(name) == -1) {
693 LOG_DBG((LOG_CRYPTO, 10, "x509_read_crls_from_dir: opendir "log_debug (LOG_CRYPTO, 10, "x509_read_crls_from_dir: opendir "
"(\"%s\") failed: %s", name, strerror((*__errno())))
694 "(\"%s\") failed: %s", name, strerror(errno)))log_debug (LOG_CRYPTO, 10, "x509_read_crls_from_dir: opendir "
"(\"%s\") failed: %s", name, strerror((*__errno())))
;
695 return 0;
696 }
697 strlcpy(fullname, name, sizeof fullname);
698 off = strlen(fullname);
699 size = sizeof fullname - off;
Value stored to 'size' is never read
700
701 while ((fd = monitor_readdir(file, sizeof file)) != -1) {
702 LOG_DBG((LOG_CRYPTO, 60, "x509_read_crls_from_dir: reading "log_debug (LOG_CRYPTO, 60, "x509_read_crls_from_dir: reading "
"CRL %s", file)
703 "CRL %s", file))log_debug (LOG_CRYPTO, 60, "x509_read_crls_from_dir: reading "
"CRL %s", file)
;
704
705 if (fstat(fd, &sb) == -1) {
706 log_error("x509_read_crls_from_dir: fstat failed");
707 close(fd);
708 continue;
709 }
710
711 if (!S_ISREG(sb.st_mode)((sb.st_mode & 0170000) == 0100000)) {
712 close(fd);
713 continue;
714 }
715
716 if ((crlfp = fdopen(fd, "r")) == NULL((void*)0)) {
717 log_error("x509_read_crls_from_dir: fdopen failed");
718 close(fd);
719 continue;
720 }
721
722 crl = PEM_read_X509_CRL(crlfp, NULL((void*)0), NULL((void*)0), NULL((void*)0));
723
724 fclose(crlfp);
725
726 if (crl == NULL((void*)0)) {
727 log_print("x509_read_crls_from_dir: "
728 "PEM_read_X509_CRL failed for %s",
729 file);
730 continue;
731 }
732 if (!X509_STORE_add_crl(ctx, crl)) {
733 LOG_DBG((LOG_CRYPTO, 50, "x509_read_crls_from_dir: "log_debug (LOG_CRYPTO, 50, "x509_read_crls_from_dir: " "X509_STORE_add_crl failed for %s"
, file)
734 "X509_STORE_add_crl failed for %s", file))log_debug (LOG_CRYPTO, 50, "x509_read_crls_from_dir: " "X509_STORE_add_crl failed for %s"
, file)
;
735 continue;
736 }
737 /*
738 * XXX This is to make x509_cert_validate set this (and
739 * XXX another) flag when validating certificates. Currently,
740 * XXX OpenSSL defaults to reject an otherwise valid
741 * XXX certificate (chain) if these flags are set but there
742 * XXX are no CRLs to check. The current workaround is to only
743 * XXX set the flags if we actually loaded some CRL data.
744 */
745 X509_STORE_set_flags(ctx, X509_V_FLAG_CRL_CHECK0x4);
746 }
747
748 return 1;
749}
750
751/* Initialize our databases and load our own certificates. */
752int
753x509_cert_init(void)
754{
755 char *dirname;
756
757 x509_hash_init();
758
759 /* Process CA certificates we will trust. */
760 dirname = conf_get_str("X509-certificates", "CA-directory");
761 if (!dirname) {
762 log_print("x509_cert_init: no CA-directory");
763 return 0;
764 }
765 /* Free if already initialized. */
766 if (x509_cas)
767 X509_STORE_free(x509_cas);
768
769 x509_cas = X509_STORE_new();
770 if (!x509_cas) {
771 log_print("x509_cert_init: creating new X509_STORE failed");
772 return 0;
773 }
774 if (!x509_read_from_dir(x509_cas, dirname, 0, &n_x509_cas)) {
775 log_print("x509_cert_init: x509_read_from_dir failed");
776 return 0;
777 }
778 /* Process client certificates we will accept. */
779 dirname = conf_get_str("X509-certificates", "Cert-directory");
780 if (!dirname) {
781 log_print("x509_cert_init: no Cert-directory");
782 return 0;
783 }
784 /* Free if already initialized. */
785 if (x509_certs)
786 X509_STORE_free(x509_certs);
787
788 x509_certs = X509_STORE_new();
789 if (!x509_certs) {
790 log_print("x509_cert_init: creating new X509_STORE failed");
791 return 0;
792 }
793 if (!x509_read_from_dir(x509_certs, dirname, 1, NULL((void*)0))) {
794 log_print("x509_cert_init: x509_read_from_dir failed");
795 return 0;
796 }
797 return 1;
798}
799
800int
801x509_crl_init(void)
802{
803 /*
804 * XXX I'm not sure if the method to use CRLs in certificate validation
805 * is valid for OpenSSL versions prior to 0.9.7. For now, simply do not
806 * support it.
807 */
808 char *dirname;
809 dirname = conf_get_str("X509-certificates", "CRL-directory");
810 if (!dirname) {
811 log_print("x509_crl_init: no CRL-directory");
812 return 0;
813 }
814 if (!x509_read_crls_from_dir(x509_cas, dirname)) {
815 LOG_DBG((LOG_MISC, 10,log_debug (LOG_MISC, 10, "x509_crl_init: x509_read_crls_from_dir failed"
)
816 "x509_crl_init: x509_read_crls_from_dir failed"))log_debug (LOG_MISC, 10, "x509_crl_init: x509_read_crls_from_dir failed"
)
;
817 return 0;
818 }
819
820 return 1;
821}
822
823void *
824x509_cert_get(u_int8_t *asn, u_int32_t len)
825{
826 return x509_from_asn(asn, len);
827}
828
829int
830x509_cert_validate(void *scert)
831{
832 X509_STORE_CTX *csc;
833 X509_NAME *issuer, *subject;
834 X509 *cert = (X509 *) scert;
835 EVP_PKEY *key;
836 int res, err, flags;
837
838 /*
839 * Validate the peer certificate by checking with the CA certificates
840 * we trust.
841 */
842 csc = X509_STORE_CTX_new();
843 if (csc == NULL((void*)0)) {
844 log_print("x509_cert_validate: failed to get memory for "
845 "certificate store");
846 return 0;
847 }
848 X509_STORE_CTX_init(csc, x509_cas, cert, NULL((void*)0));
849 /* XXX See comment in x509_read_crls_from_dir. */
850 flags = X509_VERIFY_PARAM_get_flags(X509_STORE_get0_param(x509_cas));
851 if (flags & X509_V_FLAG_CRL_CHECK0x4) {
852 X509_STORE_CTX_set_flags(csc, X509_V_FLAG_CRL_CHECK0x4);
853 X509_STORE_CTX_set_flags(csc, X509_V_FLAG_CRL_CHECK_ALL0x8);
854 }
855 res = X509_verify_cert(csc);
856 err = X509_STORE_CTX_get_error(csc);
857 X509_STORE_CTX_free(csc);
858
859 /*
860 * Return if validation succeeded or self-signed certs are not
861 * accepted.
862 *
863 * XXX X509_verify_cert seems to return -1 if the validation should be
864 * retried somehow. We take this as an error and give up.
865 */
866 if (res > 0)
867 return 1;
868 else if (res < 0 ||
869 (res == 0 && err != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT18)) {
870 if (err)
871 log_print("x509_cert_validate: %.100s",
872 X509_verify_cert_error_string(err));
873 return 0;
874 } else if (!conf_get_str("X509-certificates", "Accept-self-signed")) {
875 if (err)
876 log_print("x509_cert_validate: %.100s",
877 X509_verify_cert_error_string(err));
878 return 0;
879 }
880 issuer = X509_get_issuer_name(cert);
881 subject = X509_get_subject_name(cert);
882
883 if (!issuer || !subject || X509_NAME_cmp(issuer, subject))
884 return 0;
885
886 key = X509_get_pubkey(cert);
887 if (!key) {
888 log_print("x509_cert_validate: could not get public key from "
889 "self-signed cert");
890 return 0;
891 }
892 if (X509_verify(cert, key) == -1) {
893 log_print("x509_cert_validate: self-signed cert is bad");
894 return 0;
895 }
896 return 1;
897}
898
899int
900x509_cert_insert(int id, void *scert)
901{
902 X509 *cert;
903 int res;
904
905 cert = X509_dup((X509 *)scert);
906 if (!cert) {
907 log_print("x509_cert_insert: X509_dup failed");
908 return 0;
909 }
910 if (x509_generate_kn(id, cert) == 0) {
911 LOG_DBG((LOG_POLICY, 50,log_debug (LOG_POLICY, 50, "x509_cert_insert: x509_generate_kn failed"
)
912 "x509_cert_insert: x509_generate_kn failed"))log_debug (LOG_POLICY, 50, "x509_cert_insert: x509_generate_kn failed"
)
;
913 X509_free(cert);
914 return 0;
915 }
916
917 res = x509_hash_enter(cert);
918 if (!res)
919 X509_free(cert);
920
921 return res;
922}
923
924static struct x509_hash *
925x509_hash_lookup(X509 *cert)
926{
927 struct x509_hash *certh;
928 int i;
929
930 for (i = 0; i <= bucket_mask; i++)
931 for (certh = LIST_FIRST(&x509_tab[i])((&x509_tab[i])->lh_first); certh;
932 certh = LIST_NEXT(certh, link)((certh)->link.le_next))
933 if (certh->cert == cert)
934 return certh;
935 return 0;
936}
937
938void
939x509_cert_free(void *cert)
940{
941 struct x509_hash *certh = x509_hash_lookup((X509 *) cert);
942
943 if (certh)
944 LIST_REMOVE(certh, link)do { if ((certh)->link.le_next != ((void*)0)) (certh)->
link.le_next->link.le_prev = (certh)->link.le_prev; *(certh
)->link.le_prev = (certh)->link.le_next; ; ; } while (0
)
;
945 X509_free((X509 *) cert);
946}
947
948/* Validate the BER Encoding of a RDNSequence in the CERT_REQ payload. */
949int
950x509_certreq_validate(u_int8_t *asn, u_int32_t len)
951{
952 int res = 1;
953#if 0
954 struct norm_type name = SEQOF("issuer", RDNSequence);
955
956 if (!asn_template_clone(&name, 1) ||
957 (asn = asn_decode_sequence(asn, len, &name)) == 0) {
958 log_print("x509_certreq_validate: can not decode 'acceptable "
959 "CA' info");
960 res = 0;
961 }
962 asn_free(&name);
963#endif
964
965 /* XXX - not supported directly in SSL - later. */
966
967 return res;
968}
969
970/* Decode the BER Encoding of a RDNSequence in the CERT_REQ payload. */
971int
972x509_certreq_decode(void **pdata, u_int8_t *asn, u_int32_t len)
973{
974#if 0
975 /* XXX This needs to be done later. */
976 struct norm_type aca = SEQOF("aca", RDNSequence);
977 struct norm_type *tmp;
978 struct x509_aca naca, *ret;
979
980 if (!asn_template_clone(&aca, 1) ||
981 (asn = asn_decode_sequence(asn, len, &aca)) == 0) {
982 log_print("x509_certreq_decode: can not decode 'acceptable "
983 "CA' info");
984 goto fail;
985 }
986 bzero(&naca, sizeof(naca));
987
988 tmp = asn_decompose("aca.RelativeDistinguishedName."
989 "AttributeValueAssertion", &aca);
990 if (!tmp)
991 goto fail;
992 x509_get_attribval(tmp, &naca.name1);
993
994 tmp = asn_decompose("aca.RelativeDistinguishedName[1]"
995 ".AttributeValueAssertion", &aca);
996 if (tmp)
997 x509_get_attribval(tmp, &naca.name2);
998
999 asn_free(&aca);
1000
1001 ret = malloc(sizeof(struct x509_aca));
1002 if (ret)
1003 memcpy(ret, &naca, sizeof(struct x509_aca));
1004 else {
1005 log_error("x509_certreq_decode: malloc (%lu) failed",
1006 (unsigned long) sizeof(struct x509_aca));
1007 x509_free_aca(&aca);
1008 }
1009
1010 return ret;
1011
1012fail:
1013 asn_free(&aca);
1014#endif
1015 return 1;
1016}
1017
1018void
1019x509_free_aca(void *blob)
1020{
1021 struct x509_aca *aca = blob;
1022
1023 if (aca != NULL((void*)0)) {
1024 free(aca->name1.type);
1025 free(aca->name1.val);
1026
1027 free(aca->name2.type);
1028 free(aca->name2.val);
1029 }
1030}
1031
1032X509 *
1033x509_from_asn(u_char *asn, u_int len)
1034{
1035 BIO *certh;
1036 X509 *scert = 0;
1037
1038 certh = BIO_new(BIO_s_mem());
1039 if (!certh) {
1040 log_error("x509_from_asn: BIO_new (BIO_s_mem ()) failed");
1041 return 0;
1042 }
1043 if (BIO_write(certh, asn, len) == -1) {
1044 log_error("x509_from_asn: BIO_write failed\n");
1045 goto end;
1046 }
1047 scert = d2i_X509_bio(certh, NULL((void*)0));
1048 if (!scert) {
1049 log_print("x509_from_asn: d2i_X509_bio failed\n");
1050 goto end;
1051 }
1052end:
1053 BIO_free(certh);
1054 return scert;
1055}
1056
1057/*
1058 * Obtain a certificate from an acceptable CA.
1059 * XXX We don't check if the certificate we find is from an accepted CA.
1060 */
1061int
1062x509_cert_obtain(u_int8_t *id, size_t id_len, void *data, u_int8_t **cert,
1063 u_int32_t *certlen)
1064{
1065 struct x509_aca *aca = data;
1066 X509 *scert;
1067
1068 if (aca)
1069 LOG_DBG((LOG_CRYPTO, 60, "x509_cert_obtain: "log_debug (LOG_CRYPTO, 60, "x509_cert_obtain: " "acceptable certificate authorities here"
)
1070 "acceptable certificate authorities here"))log_debug (LOG_CRYPTO, 60, "x509_cert_obtain: " "acceptable certificate authorities here"
)
;
1071
1072 /* We need our ID to find a certificate. */
1073 if (!id) {
1074 log_print("x509_cert_obtain: ID is missing");
1075 return 0;
1076 }
1077 scert = x509_hash_find(id, id_len);
1078 if (!scert)
1079 return 0;
1080
1081 x509_serialize(scert, cert, certlen);
1082 if (!*cert)
1083 return 0;
1084 return 1;
1085}
1086
1087/* Returns a pointer to the subjectAltName information of X509 certificate. */
1088int
1089x509_cert_subjectaltname(X509 *scert, u_int8_t **altname, u_int32_t *len)
1090{
1091 X509_EXTENSION *subjectaltname;
1092 ASN1_OCTET_STRING *sanasn1data;
1093 u_int8_t *sandata;
1094 int extpos, santype, sanlen;
1095
1096 extpos = X509_get_ext_by_NID(scert, NID_subject_alt_name85, -1);
1097 if (extpos == -1) {
1098 log_print("x509_cert_subjectaltname: "
1099 "certificate does not contain subjectAltName");
1100 return 0;
1101 }
1102 subjectaltname = X509_get_ext(scert, extpos);
1103 sanasn1data = X509_EXTENSION_get_data(subjectaltname);
1104
1105 if (!subjectaltname || !sanasn1data || !sanasn1data->data ||
1106 sanasn1data->length < 4) {
1107 log_print("x509_cert_subjectaltname: invalid "
1108 "subjectaltname extension");
1109 return 0;
1110 }
1111 /* SSL does not handle unknown ASN stuff well, do it by hand. */
1112 sandata = sanasn1data->data;
1113 santype = sandata[2] & 0x3f;
1114 sanlen = sandata[3];
1115 sandata += 4;
1116
1117 /*
1118 * The test here used to be !=, but some certificates can include
1119 * extra stuff in subjectAltName, so we will just take the first
1120 * salen bytes, and not worry about what follows.
1121 */
1122 if (sanlen + 4 > sanasn1data->length) {
1123 log_print("x509_cert_subjectaltname: subjectaltname invalid "
1124 "length");
1125 return 0;
1126 }
1127 *len = sanlen;
1128 *altname = sandata;
1129 return santype;
1130}
1131
1132int
1133x509_cert_get_subjects(void *scert, int *cnt, u_int8_t ***id,
1134 u_int32_t **id_len)
1135{
1136 X509 *cert = scert;
1137 X509_NAME *subject;
1138 int type;
1139 u_int8_t *altname;
1140 u_int32_t altlen;
1141 u_int8_t *buf = 0;
1142 unsigned char *ubuf;
1143 int i;
1144
1145 *id = 0;
1146 *id_len = 0;
1147
1148 /*
1149 * XXX There can be a collection of subjectAltNames, but for now I
1150 * only return the subjectName and a single subjectAltName, if
1151 * present.
1152 */
1153 type = x509_cert_subjectaltname(cert, &altname, &altlen);
1154 if (!type) {
1155 *cnt = 1;
1156 altlen = 0;
1157 } else
1158 *cnt = 2;
1159
1160 *id = calloc(*cnt, sizeof **id);
1161 if (!*id) {
1162 log_print("x509_cert_get_subject: malloc (%lu) failed",
1163 *cnt * (unsigned long)sizeof **id);
1164 *cnt = 0;
1165 goto fail;
1166 }
1167 *id_len = calloc(*cnt, sizeof **id_len);
1168 if (!*id_len) {
1169 log_print("x509_cert_get_subject: malloc (%lu) failed",
1170 *cnt * (unsigned long)sizeof **id_len);
1171 goto fail;
1172 }
1173 /* Stash the subjectName into the first slot. */
1174 subject = X509_get_subject_name(cert);
1175 if (!subject)
1176 goto fail;
1177
1178 (*id_len)[0] =
1179 ISAKMP_ID_DATA_OFF8 + i2d_X509_NAME(subject, NULL((void*)0)) -
1180 ISAKMP_GEN_SZ4;
1181 (*id)[0] = malloc((*id_len)[0]);
1182 if (!(*id)[0]) {
1183 log_print("x509_cert_get_subject: malloc (%d) failed",
1184 (*id_len)[0]);
1185 goto fail;
1186 }
1187 SET_ISAKMP_ID_TYPE((*id)[0] - ISAKMP_GEN_SZ, IPSEC_ID_DER_ASN1_DN)field_set_num (isakmp_id_fld + 0, (*id)[0] - 4, 9);
1188 ubuf = (*id)[0] + ISAKMP_ID_DATA_OFF8 - ISAKMP_GEN_SZ4;
1189 i2d_X509_NAME(subject, &ubuf);
1190
1191 if (altlen) {
1192 /* Stash the subjectAltName into the second slot. */
1193 buf = malloc(altlen + ISAKMP_ID_DATA_OFF8);
1194 if (!buf) {
1195 log_print("x509_cert_get_subject: malloc (%d) failed",
1196 altlen + ISAKMP_ID_DATA_OFF8);
1197 goto fail;
1198 }
1199 switch (type) {
1200 case X509v3_DNS_NAME2:
1201 SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_FQDN)field_set_num (isakmp_id_fld + 0, buf, 2);
1202 break;
1203
1204 case X509v3_RFC_NAME1:
1205 SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_USER_FQDN)field_set_num (isakmp_id_fld + 0, buf, 3);
1206 break;
1207
1208 case X509v3_IP_ADDR7:
1209 /*
1210 * XXX I dislike the numeric constants, but I don't
1211 * know what we should use otherwise.
1212 */
1213 switch (altlen) {
1214 case 4:
1215 SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_IPV4_ADDR)field_set_num (isakmp_id_fld + 0, buf, 1);
1216 break;
1217
1218 case 16:
1219 SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_IPV6_ADDR)field_set_num (isakmp_id_fld + 0, buf, 5);
1220 break;
1221
1222 default:
1223 log_print("x509_cert_get_subject: invalid "
1224 "subjectAltName IPaddress length %d ",
1225 altlen);
1226 goto fail;
1227 }
1228 break;
1229 }
1230
1231 SET_IPSEC_ID_PROTO(buf + ISAKMP_ID_DOI_DATA_OFF, 0)field_set_num (ipsec_id_fld + 0, buf + 5, 0);
1232 SET_IPSEC_ID_PORT(buf + ISAKMP_ID_DOI_DATA_OFF, 0)field_set_num (ipsec_id_fld + 1, buf + 5, 0);
1233 memcpy(buf + ISAKMP_ID_DATA_OFF8, altname, altlen);
1234
1235 (*id_len)[1] = ISAKMP_ID_DATA_OFF8 + altlen - ISAKMP_GEN_SZ4;
1236 (*id)[1] = malloc((*id_len)[1]);
1237 if (!(*id)[1]) {
1238 log_print("x509_cert_get_subject: malloc (%d) failed",
1239 (*id_len)[1]);
1240 goto fail;
1241 }
1242 memcpy((*id)[1], buf + ISAKMP_GEN_SZ4, (*id_len)[1]);
1243
1244 free(buf);
1245 buf = 0;
1246 }
1247 return 1;
1248
1249fail:
1250 for (i = 0; i < *cnt; i++)
1251 free((*id)[i]);
1252 free(*id);
1253 free(*id_len);
1254 free(buf);
1255 return 0;
1256}
1257
1258int
1259x509_cert_get_key(void *scert, void *keyp)
1260{
1261 X509 *cert = scert;
1262 EVP_PKEY *key;
1263
1264 key = X509_get_pubkey(cert);
1265
1266 /* Check if we got the right key type. */
1267 if (EVP_PKEY_id(key) != EVP_PKEY_RSA6) {
1268 log_print("x509_cert_get_key: public key is not a RSA key");
1269 X509_free(cert);
1270 return 0;
1271 }
1272 *(RSA **)keyp = RSAPublicKey_dup(EVP_PKEY_get0_RSA(key));
1273
1274 return *(RSA **)keyp == NULL((void*)0) ? 0 : 1;
1275}
1276
1277void *
1278x509_cert_dup(void *scert)
1279{
1280 return X509_dup(scert);
1281}
1282
1283void
1284x509_serialize(void *scert, u_int8_t **data, u_int32_t *datalen)
1285{
1286 u_int8_t *p;
1287
1288 *datalen = i2d_X509((X509 *)scert, NULL((void*)0));
1289 *data = p = malloc(*datalen);
1290 if (!p) {
1291 log_error("x509_serialize: malloc (%d) failed", *datalen);
1292 return;
1293 }
1294 *datalen = i2d_X509((X509 *)scert, &p);
1295}
1296
1297/* From cert to printable */
1298char *
1299x509_printable(void *cert)
1300{
1301 char *s;
1302 u_int8_t *data;
1303 u_int32_t datalen;
1304
1305 x509_serialize(cert, &data, &datalen);
1306 if (!data)
1307 return 0;
1308
1309 s = raw2hex(data, datalen);
1310 free(data);
1311 return s;
1312}
1313
1314/* From printable to cert */
1315void *
1316x509_from_printable(char *cert)
1317{
1318 u_int8_t *buf;
1319 int plen, ret;
1320 void *foo;
1321
1322 plen = (strlen(cert) + 1) / 2;
1323 buf = malloc(plen);
1324 if (!buf) {
1325 log_error("x509_from_printable: malloc (%d) failed", plen);
1326 return 0;
1327 }
1328 ret = hex2raw(cert, buf, plen);
1329 if (ret == -1) {
1330 free(buf);
1331 log_print("x509_from_printable: badly formatted cert");
1332 return 0;
1333 }
1334 foo = x509_cert_get(buf, plen);
1335 free(buf);
1336 if (!foo)
1337 log_print("x509_from_printable: "
1338 "could not retrieve certificate");
1339 return foo;
1340}
1341
1342char *
1343x509_DN_string(u_int8_t *asn1, size_t sz)
1344{
1345 X509_NAME *name;
1346 const u_int8_t *p = asn1;
1347 char buf[256]; /* XXX Just a guess at a maximum length. */
1348 long len = sz;
1349
1350 name = d2i_X509_NAME(NULL((void*)0), &p, len);
1351 if (!name) {
1352 log_print("x509_DN_string: d2i_X509_NAME failed");
1353 return 0;
1354 }
1355 if (!X509_NAME_oneline(name, buf, sizeof buf - 1)) {
1356 log_print("x509_DN_string: X509_NAME_oneline failed");
1357 X509_NAME_free(name);
1358 return 0;
1359 }
1360 X509_NAME_free(name);
1361 buf[sizeof buf - 1] = '\0';
1362 return strdup(buf);
1363}
1364
1365/* Number of CAs we trust (to decide whether we can send CERT_REQ) */
1366int
1367x509_ca_count(void)
1368{
1369 return n_x509_cas;
1370}