GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* $OpenBSD: apps.c,v 1.44 2017/08/12 21:04:33 jsing Exp $ */ |
||
2 |
/* |
||
3 |
* Copyright (c) 2014 Joel Sing <jsing@openbsd.org> |
||
4 |
* |
||
5 |
* Permission to use, copy, modify, and distribute this software for any |
||
6 |
* purpose with or without fee is hereby granted, provided that the above |
||
7 |
* copyright notice and this permission notice appear in all copies. |
||
8 |
* |
||
9 |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||
10 |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||
11 |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
||
12 |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||
13 |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||
14 |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
||
15 |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||
16 |
*/ |
||
17 |
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
||
18 |
* All rights reserved. |
||
19 |
* |
||
20 |
* This package is an SSL implementation written |
||
21 |
* by Eric Young (eay@cryptsoft.com). |
||
22 |
* The implementation was written so as to conform with Netscapes SSL. |
||
23 |
* |
||
24 |
* This library is free for commercial and non-commercial use as long as |
||
25 |
* the following conditions are aheared to. The following conditions |
||
26 |
* apply to all code found in this distribution, be it the RC4, RSA, |
||
27 |
* lhash, DES, etc., code; not just the SSL code. The SSL documentation |
||
28 |
* included with this distribution is covered by the same copyright terms |
||
29 |
* except that the holder is Tim Hudson (tjh@cryptsoft.com). |
||
30 |
* |
||
31 |
* Copyright remains Eric Young's, and as such any Copyright notices in |
||
32 |
* the code are not to be removed. |
||
33 |
* If this package is used in a product, Eric Young should be given attribution |
||
34 |
* as the author of the parts of the library used. |
||
35 |
* This can be in the form of a textual message at program startup or |
||
36 |
* in documentation (online or textual) provided with the package. |
||
37 |
* |
||
38 |
* Redistribution and use in source and binary forms, with or without |
||
39 |
* modification, are permitted provided that the following conditions |
||
40 |
* are met: |
||
41 |
* 1. Redistributions of source code must retain the copyright |
||
42 |
* notice, this list of conditions and the following disclaimer. |
||
43 |
* 2. Redistributions in binary form must reproduce the above copyright |
||
44 |
* notice, this list of conditions and the following disclaimer in the |
||
45 |
* documentation and/or other materials provided with the distribution. |
||
46 |
* 3. All advertising materials mentioning features or use of this software |
||
47 |
* must display the following acknowledgement: |
||
48 |
* "This product includes cryptographic software written by |
||
49 |
* Eric Young (eay@cryptsoft.com)" |
||
50 |
* The word 'cryptographic' can be left out if the rouines from the library |
||
51 |
* being used are not cryptographic related :-). |
||
52 |
* 4. If you include any Windows specific code (or a derivative thereof) from |
||
53 |
* the apps directory (application code) you must include an acknowledgement: |
||
54 |
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" |
||
55 |
* |
||
56 |
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND |
||
57 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||
58 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||
59 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
||
60 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||
61 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||
62 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||
63 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||
64 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||
65 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||
66 |
* SUCH DAMAGE. |
||
67 |
* |
||
68 |
* The licence and distribution terms for any publically available version or |
||
69 |
* derivative of this code cannot be changed. i.e. this code cannot simply be |
||
70 |
* copied and put under another distribution licence |
||
71 |
* [including the GNU Public Licence.] |
||
72 |
*/ |
||
73 |
/* ==================================================================== |
||
74 |
* Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. |
||
75 |
* |
||
76 |
* Redistribution and use in source and binary forms, with or without |
||
77 |
* modification, are permitted provided that the following conditions |
||
78 |
* are met: |
||
79 |
* |
||
80 |
* 1. Redistributions of source code must retain the above copyright |
||
81 |
* notice, this list of conditions and the following disclaimer. |
||
82 |
* |
||
83 |
* 2. Redistributions in binary form must reproduce the above copyright |
||
84 |
* notice, this list of conditions and the following disclaimer in |
||
85 |
* the documentation and/or other materials provided with the |
||
86 |
* distribution. |
||
87 |
* |
||
88 |
* 3. All advertising materials mentioning features or use of this |
||
89 |
* software must display the following acknowledgment: |
||
90 |
* "This product includes software developed by the OpenSSL Project |
||
91 |
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)" |
||
92 |
* |
||
93 |
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to |
||
94 |
* endorse or promote products derived from this software without |
||
95 |
* prior written permission. For written permission, please contact |
||
96 |
* openssl-core@openssl.org. |
||
97 |
* |
||
98 |
* 5. Products derived from this software may not be called "OpenSSL" |
||
99 |
* nor may "OpenSSL" appear in their names without prior written |
||
100 |
* permission of the OpenSSL Project. |
||
101 |
* |
||
102 |
* 6. Redistributions of any form whatsoever must retain the following |
||
103 |
* acknowledgment: |
||
104 |
* "This product includes software developed by the OpenSSL Project |
||
105 |
* for use in the OpenSSL Toolkit (http://www.openssl.org/)" |
||
106 |
* |
||
107 |
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY |
||
108 |
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||
109 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||
110 |
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR |
||
111 |
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||
112 |
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||
113 |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||
114 |
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||
115 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||
116 |
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||
117 |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
||
118 |
* OF THE POSSIBILITY OF SUCH DAMAGE. |
||
119 |
* ==================================================================== |
||
120 |
* |
||
121 |
* This product includes cryptographic software written by Eric Young |
||
122 |
* (eay@cryptsoft.com). This product includes software written by Tim |
||
123 |
* Hudson (tjh@cryptsoft.com). |
||
124 |
* |
||
125 |
*/ |
||
126 |
|||
127 |
#include <sys/types.h> |
||
128 |
#include <sys/stat.h> |
||
129 |
|||
130 |
#include <ctype.h> |
||
131 |
#include <errno.h> |
||
132 |
#include <stdio.h> |
||
133 |
#include <stdlib.h> |
||
134 |
#include <limits.h> |
||
135 |
#include <string.h> |
||
136 |
#include <unistd.h> |
||
137 |
|||
138 |
#include "apps.h" |
||
139 |
|||
140 |
#include <openssl/bn.h> |
||
141 |
#include <openssl/err.h> |
||
142 |
#include <openssl/pem.h> |
||
143 |
#include <openssl/pkcs12.h> |
||
144 |
#include <openssl/safestack.h> |
||
145 |
#include <openssl/x509.h> |
||
146 |
#include <openssl/x509v3.h> |
||
147 |
|||
148 |
#include <openssl/rsa.h> |
||
149 |
|||
150 |
typedef struct { |
||
151 |
const char *name; |
||
152 |
unsigned long flag; |
||
153 |
unsigned long mask; |
||
154 |
} NAME_EX_TBL; |
||
155 |
|||
156 |
UI_METHOD *ui_method = NULL; |
||
157 |
|||
158 |
static int set_table_opts(unsigned long *flags, const char *arg, |
||
159 |
const NAME_EX_TBL *in_tbl); |
||
160 |
static int set_multi_opts(unsigned long *flags, const char *arg, |
||
161 |
const NAME_EX_TBL *in_tbl); |
||
162 |
|||
163 |
#if !defined(OPENSSL_NO_RC4) && !defined(OPENSSL_NO_RSA) |
||
164 |
/* Looks like this stuff is worth moving into separate function */ |
||
165 |
static EVP_PKEY *load_netscape_key(BIO *err, BIO *key, const char *file, |
||
166 |
const char *key_descrip, int format); |
||
167 |
#endif |
||
168 |
|||
169 |
int |
||
170 |
str2fmt(char *s) |
||
171 |
{ |
||
172 |
✗✓ | 48 |
if (s == NULL) |
173 |
return FORMAT_UNDEF; |
||
174 |
✓✓✗✓ |
32 |
if ((*s == 'D') || (*s == 'd')) |
175 |
16 |
return (FORMAT_ASN1); |
|
176 |
✓✗✗✓ |
16 |
else if ((*s == 'T') || (*s == 't')) |
177 |
return (FORMAT_TEXT); |
||
178 |
✓✗✗✓ |
16 |
else if ((*s == 'N') || (*s == 'n')) |
179 |
return (FORMAT_NETSCAPE); |
||
180 |
✓✗✗✓ |
16 |
else if ((*s == 'S') || (*s == 's')) |
181 |
return (FORMAT_SMIME); |
||
182 |
✓✗✗✓ |
16 |
else if ((*s == 'M') || (*s == 'm')) |
183 |
return (FORMAT_MSBLOB); |
||
184 |
✓✗✗✓ |
16 |
else if ((*s == '1') || |
185 |
✓✗✓✗ |
16 |
(strcmp(s, "PKCS12") == 0) || (strcmp(s, "pkcs12") == 0) || |
186 |
✓✗ | 16 |
(strcmp(s, "P12") == 0) || (strcmp(s, "p12") == 0)) |
187 |
return (FORMAT_PKCS12); |
||
188 |
✗✓✗✗ |
8 |
else if ((*s == 'P') || (*s == 'p')) { |
189 |
✓✗✗✓ |
16 |
if (s[1] == 'V' || s[1] == 'v') |
190 |
return FORMAT_PVK; |
||
191 |
else |
||
192 |
8 |
return (FORMAT_PEM); |
|
193 |
} else |
||
194 |
return (FORMAT_UNDEF); |
||
195 |
24 |
} |
|
196 |
|||
197 |
void |
||
198 |
program_name(char *in, char *out, int size) |
||
199 |
{ |
||
200 |
char *p; |
||
201 |
|||
202 |
16862 |
p = strrchr(in, '/'); |
|
203 |
✓✓ | 8431 |
if (p != NULL) |
204 |
5432 |
p++; |
|
205 |
else |
||
206 |
p = in; |
||
207 |
8431 |
strlcpy(out, p, size); |
|
208 |
8431 |
} |
|
209 |
|||
210 |
int |
||
211 |
chopup_args(ARGS *arg, char *buf, int *argc, char **argv[]) |
||
212 |
{ |
||
213 |
int num, i; |
||
214 |
char *p; |
||
215 |
|||
216 |
32 |
*argc = 0; |
|
217 |
16 |
*argv = NULL; |
|
218 |
|||
219 |
i = 0; |
||
220 |
✓✓ | 16 |
if (arg->count == 0) { |
221 |
8 |
arg->count = 20; |
|
222 |
8 |
arg->data = reallocarray(NULL, arg->count, sizeof(char *)); |
|
223 |
✗✓ | 8 |
if (arg->data == NULL) |
224 |
return 0; |
||
225 |
} |
||
226 |
✓✓ | 672 |
for (i = 0; i < arg->count; i++) |
227 |
320 |
arg->data[i] = NULL; |
|
228 |
|||
229 |
num = 0; |
||
230 |
p = buf; |
||
231 |
32 |
for (;;) { |
|
232 |
/* first scan over white space */ |
||
233 |
✓✓ | 32 |
if (!*p) |
234 |
break; |
||
235 |
✓✗✓✗ ✓✗✗✓ |
80 |
while (*p && ((*p == ' ') || (*p == '\t') || (*p == '\n'))) |
236 |
p++; |
||
237 |
✓✗ | 16 |
if (!*p) |
238 |
break; |
||
239 |
|||
240 |
/* The start of something good :-) */ |
||
241 |
✗✓ | 16 |
if (num >= arg->count) { |
242 |
char **tmp_p; |
||
243 |
int tlen = arg->count + 20; |
||
244 |
tmp_p = reallocarray(arg->data, tlen, sizeof(char *)); |
||
245 |
if (tmp_p == NULL) |
||
246 |
return 0; |
||
247 |
arg->data = tmp_p; |
||
248 |
arg->count = tlen; |
||
249 |
/* initialize newly allocated data */ |
||
250 |
for (i = num; i < arg->count; i++) |
||
251 |
arg->data[i] = NULL; |
||
252 |
} |
||
253 |
16 |
arg->data[num++] = p; |
|
254 |
|||
255 |
/* now look for the end of this */ |
||
256 |
✓✗✗✓ |
32 |
if ((*p == '\'') || (*p == '\"')) { /* scan for closing |
257 |
* quote */ |
||
258 |
i = *(p++); |
||
259 |
arg->data[num - 1]++; /* jump over quote */ |
||
260 |
while (*p && (*p != i)) |
||
261 |
p++; |
||
262 |
*p = '\0'; |
||
263 |
} else { |
||
264 |
✓✗✓✗ ✓✓ |
304 |
while (*p && ((*p != ' ') && |
265 |
✓✗ | 160 |
(*p != '\t') && (*p != '\n'))) |
266 |
64 |
p++; |
|
267 |
|||
268 |
✗✓ | 16 |
if (*p == '\0') |
269 |
p--; |
||
270 |
else |
||
271 |
16 |
*p = '\0'; |
|
272 |
} |
||
273 |
16 |
p++; |
|
274 |
} |
||
275 |
16 |
*argc = num; |
|
276 |
16 |
*argv = arg->data; |
|
277 |
16 |
return (1); |
|
278 |
16 |
} |
|
279 |
|||
280 |
int |
||
281 |
dump_cert_text(BIO *out, X509 *x) |
||
282 |
{ |
||
283 |
char *p; |
||
284 |
|||
285 |
48 |
p = X509_NAME_oneline(X509_get_subject_name(x), NULL, 0); |
|
286 |
24 |
BIO_puts(out, "subject="); |
|
287 |
24 |
BIO_puts(out, p); |
|
288 |
24 |
free(p); |
|
289 |
|||
290 |
24 |
p = X509_NAME_oneline(X509_get_issuer_name(x), NULL, 0); |
|
291 |
24 |
BIO_puts(out, "\nissuer="); |
|
292 |
24 |
BIO_puts(out, p); |
|
293 |
24 |
BIO_puts(out, "\n"); |
|
294 |
24 |
free(p); |
|
295 |
|||
296 |
24 |
return 0; |
|
297 |
} |
||
298 |
|||
299 |
int |
||
300 |
ui_open(UI *ui) |
||
301 |
{ |
||
302 |
return UI_method_get_opener(UI_OpenSSL()) (ui); |
||
303 |
} |
||
304 |
|||
305 |
int |
||
306 |
ui_read(UI *ui, UI_STRING *uis) |
||
307 |
{ |
||
308 |
const char *password; |
||
309 |
int string_type; |
||
310 |
|||
311 |
if (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD && |
||
312 |
UI_get0_user_data(ui)) { |
||
313 |
string_type = UI_get_string_type(uis); |
||
314 |
if (string_type == UIT_PROMPT || string_type == UIT_VERIFY) { |
||
315 |
password = |
||
316 |
((PW_CB_DATA *)UI_get0_user_data(ui))->password; |
||
317 |
if (password && password[0] != '\0') { |
||
318 |
UI_set_result(ui, uis, password); |
||
319 |
return 1; |
||
320 |
} |
||
321 |
} |
||
322 |
} |
||
323 |
return UI_method_get_reader(UI_OpenSSL()) (ui, uis); |
||
324 |
} |
||
325 |
|||
326 |
int |
||
327 |
ui_write(UI *ui, UI_STRING *uis) |
||
328 |
{ |
||
329 |
const char *password; |
||
330 |
int string_type; |
||
331 |
|||
332 |
if (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD && |
||
333 |
UI_get0_user_data(ui)) { |
||
334 |
string_type = UI_get_string_type(uis); |
||
335 |
if (string_type == UIT_PROMPT || string_type == UIT_VERIFY) { |
||
336 |
password = |
||
337 |
((PW_CB_DATA *)UI_get0_user_data(ui))->password; |
||
338 |
if (password && password[0] != '\0') |
||
339 |
return 1; |
||
340 |
} |
||
341 |
} |
||
342 |
return UI_method_get_writer(UI_OpenSSL()) (ui, uis); |
||
343 |
} |
||
344 |
|||
345 |
int |
||
346 |
ui_close(UI *ui) |
||
347 |
{ |
||
348 |
return UI_method_get_closer(UI_OpenSSL()) (ui); |
||
349 |
} |
||
350 |
|||
351 |
int |
||
352 |
password_callback(char *buf, int bufsiz, int verify, void *arg) |
||
353 |
{ |
||
354 |
240 |
PW_CB_DATA *cb_tmp = arg; |
|
355 |
UI *ui = NULL; |
||
356 |
int res = 0; |
||
357 |
const char *prompt_info = NULL; |
||
358 |
const char *password = NULL; |
||
359 |
PW_CB_DATA *cb_data = (PW_CB_DATA *) cb_tmp; |
||
360 |
|||
361 |
✓✗ | 120 |
if (cb_data) { |
362 |
✓✗ | 120 |
if (cb_data->password) |
363 |
120 |
password = cb_data->password; |
|
364 |
✓✗ | 120 |
if (cb_data->prompt_info) |
365 |
120 |
prompt_info = cb_data->prompt_info; |
|
366 |
} |
||
367 |
✓✗ | 120 |
if (password) { |
368 |
120 |
res = strlen(password); |
|
369 |
✗✓ | 120 |
if (res > bufsiz) |
370 |
res = bufsiz; |
||
371 |
120 |
memcpy(buf, password, res); |
|
372 |
120 |
return res; |
|
373 |
} |
||
374 |
ui = UI_new_method(ui_method); |
||
375 |
if (ui) { |
||
376 |
int ok = 0; |
||
377 |
char *buff = NULL; |
||
378 |
int ui_flags = 0; |
||
379 |
char *prompt = NULL; |
||
380 |
|||
381 |
prompt = UI_construct_prompt(ui, "pass phrase", prompt_info); |
||
382 |
|||
383 |
ui_flags |= UI_INPUT_FLAG_DEFAULT_PWD; |
||
384 |
UI_ctrl(ui, UI_CTRL_PRINT_ERRORS, 1, 0, 0); |
||
385 |
|||
386 |
if (ok >= 0) |
||
387 |
ok = UI_add_input_string(ui, prompt, ui_flags, buf, |
||
388 |
PW_MIN_LENGTH, bufsiz - 1); |
||
389 |
if (ok >= 0 && verify) { |
||
390 |
buff = malloc(bufsiz); |
||
391 |
ok = UI_add_verify_string(ui, prompt, ui_flags, buff, |
||
392 |
PW_MIN_LENGTH, bufsiz - 1, buf); |
||
393 |
} |
||
394 |
if (ok >= 0) |
||
395 |
do { |
||
396 |
ok = UI_process(ui); |
||
397 |
} while (ok < 0 && |
||
398 |
UI_ctrl(ui, UI_CTRL_IS_REDOABLE, 0, 0, 0)); |
||
399 |
|||
400 |
freezero(buff, (unsigned int) bufsiz); |
||
401 |
if (ok >= 0) |
||
402 |
res = strlen(buf); |
||
403 |
if (ok == -1) { |
||
404 |
BIO_printf(bio_err, "User interface error\n"); |
||
405 |
ERR_print_errors(bio_err); |
||
406 |
explicit_bzero(buf, (unsigned int) bufsiz); |
||
407 |
res = 0; |
||
408 |
} |
||
409 |
if (ok == -2) { |
||
410 |
BIO_printf(bio_err, "aborted!\n"); |
||
411 |
explicit_bzero(buf, (unsigned int) bufsiz); |
||
412 |
res = 0; |
||
413 |
} |
||
414 |
UI_free(ui); |
||
415 |
free(prompt); |
||
416 |
} |
||
417 |
return res; |
||
418 |
120 |
} |
|
419 |
|||
420 |
static char *app_get_pass(BIO *err, char *arg, int keepbio); |
||
421 |
|||
422 |
int |
||
423 |
app_passwd(BIO *err, char *arg1, char *arg2, char **pass1, char **pass2) |
||
424 |
{ |
||
425 |
int same; |
||
426 |
|||
427 |
✓✓✓✓ |
4862 |
if (!arg2 || !arg1 || strcmp(arg1, arg2)) |
428 |
2403 |
same = 0; |
|
429 |
else |
||
430 |
same = 1; |
||
431 |
✓✓ | 2419 |
if (arg1) { |
432 |
968 |
*pass1 = app_get_pass(err, arg1, same); |
|
433 |
✗✓ | 968 |
if (!*pass1) |
434 |
return 0; |
||
435 |
✓✓ | 1451 |
} else if (pass1) |
436 |
1427 |
*pass1 = NULL; |
|
437 |
✓✓ | 2419 |
if (arg2) { |
438 |
80 |
*pass2 = app_get_pass(err, arg2, same ? 2 : 0); |
|
439 |
✗✓ | 80 |
if (!*pass2) |
440 |
return 0; |
||
441 |
✓✓ | 2339 |
} else if (pass2) |
442 |
866 |
*pass2 = NULL; |
|
443 |
2419 |
return 1; |
|
444 |
2419 |
} |
|
445 |
|||
446 |
static char * |
||
447 |
app_get_pass(BIO *err, char *arg, int keepbio) |
||
448 |
{ |
||
449 |
2096 |
char *tmp, tpass[APP_PASS_LEN]; |
|
450 |
static BIO *pwdbio = NULL; |
||
451 |
1048 |
const char *errstr = NULL; |
|
452 |
int i; |
||
453 |
|||
454 |
✓✗ | 1048 |
if (!strncmp(arg, "pass:", 5)) |
455 |
1048 |
return strdup(arg + 5); |
|
456 |
if (!strncmp(arg, "env:", 4)) { |
||
457 |
tmp = getenv(arg + 4); |
||
458 |
if (!tmp) { |
||
459 |
BIO_printf(err, "Can't read environment variable %s\n", |
||
460 |
arg + 4); |
||
461 |
return NULL; |
||
462 |
} |
||
463 |
return strdup(tmp); |
||
464 |
} |
||
465 |
if (!keepbio || !pwdbio) { |
||
466 |
if (!strncmp(arg, "file:", 5)) { |
||
467 |
pwdbio = BIO_new_file(arg + 5, "r"); |
||
468 |
if (!pwdbio) { |
||
469 |
BIO_printf(err, "Can't open file %s\n", |
||
470 |
arg + 5); |
||
471 |
return NULL; |
||
472 |
} |
||
473 |
} else if (!strncmp(arg, "fd:", 3)) { |
||
474 |
BIO *btmp; |
||
475 |
i = strtonum(arg + 3, 0, INT_MAX, &errstr); |
||
476 |
if (errstr) { |
||
477 |
BIO_printf(err, |
||
478 |
"Invalid file descriptor %s: %s\n", |
||
479 |
arg, errstr); |
||
480 |
return NULL; |
||
481 |
} |
||
482 |
pwdbio = BIO_new_fd(i, BIO_NOCLOSE); |
||
483 |
if (!pwdbio) { |
||
484 |
BIO_printf(err, |
||
485 |
"Can't access file descriptor %s\n", |
||
486 |
arg + 3); |
||
487 |
return NULL; |
||
488 |
} |
||
489 |
/* |
||
490 |
* Can't do BIO_gets on an fd BIO so add a buffering |
||
491 |
* BIO |
||
492 |
*/ |
||
493 |
btmp = BIO_new(BIO_f_buffer()); |
||
494 |
pwdbio = BIO_push(btmp, pwdbio); |
||
495 |
} else if (!strcmp(arg, "stdin")) { |
||
496 |
pwdbio = BIO_new_fp(stdin, BIO_NOCLOSE); |
||
497 |
if (!pwdbio) { |
||
498 |
BIO_printf(err, "Can't open BIO for stdin\n"); |
||
499 |
return NULL; |
||
500 |
} |
||
501 |
} else { |
||
502 |
BIO_printf(err, "Invalid password argument \"%s\"\n", |
||
503 |
arg); |
||
504 |
return NULL; |
||
505 |
} |
||
506 |
} |
||
507 |
i = BIO_gets(pwdbio, tpass, APP_PASS_LEN); |
||
508 |
if (keepbio != 1) { |
||
509 |
BIO_free_all(pwdbio); |
||
510 |
pwdbio = NULL; |
||
511 |
} |
||
512 |
if (i <= 0) { |
||
513 |
BIO_printf(err, "Error reading password from BIO\n"); |
||
514 |
return NULL; |
||
515 |
} |
||
516 |
tmp = strchr(tpass, '\n'); |
||
517 |
if (tmp) |
||
518 |
*tmp = 0; |
||
519 |
return strdup(tpass); |
||
520 |
1048 |
} |
|
521 |
|||
522 |
int |
||
523 |
add_oid_section(BIO *err, CONF *conf) |
||
524 |
{ |
||
525 |
char *p; |
||
526 |
STACK_OF(CONF_VALUE) *sktmp; |
||
527 |
CONF_VALUE *cnf; |
||
528 |
int i; |
||
529 |
|||
530 |
✓✓ | 372 |
if (!(p = NCONF_get_string(conf, NULL, "oid_section"))) { |
531 |
66 |
ERR_clear_error(); |
|
532 |
66 |
return 1; |
|
533 |
} |
||
534 |
✗✓ | 120 |
if (!(sktmp = NCONF_get_section(conf, p))) { |
535 |
BIO_printf(err, "problem loading oid section %s\n", p); |
||
536 |
return 0; |
||
537 |
} |
||
538 |
✓✓ | 960 |
for (i = 0; i < sk_CONF_VALUE_num(sktmp); i++) { |
539 |
360 |
cnf = sk_CONF_VALUE_value(sktmp, i); |
|
540 |
✗✓ | 360 |
if (OBJ_create(cnf->value, cnf->name, cnf->name) == NID_undef) { |
541 |
BIO_printf(err, "problem creating object %s=%s\n", |
||
542 |
cnf->name, cnf->value); |
||
543 |
return 0; |
||
544 |
} |
||
545 |
} |
||
546 |
120 |
return 1; |
|
547 |
186 |
} |
|
548 |
|||
549 |
static int |
||
550 |
load_pkcs12(BIO *err, BIO *in, const char *desc, pem_password_cb *pem_cb, |
||
551 |
void *cb_data, EVP_PKEY **pkey, X509 **cert, STACK_OF(X509) **ca) |
||
552 |
{ |
||
553 |
const char *pass; |
||
554 |
char tpass[PEM_BUFSIZE]; |
||
555 |
int len, ret = 0; |
||
556 |
PKCS12 *p12; |
||
557 |
|||
558 |
p12 = d2i_PKCS12_bio(in, NULL); |
||
559 |
if (p12 == NULL) { |
||
560 |
BIO_printf(err, "Error loading PKCS12 file for %s\n", desc); |
||
561 |
goto die; |
||
562 |
} |
||
563 |
/* See if an empty password will do */ |
||
564 |
if (PKCS12_verify_mac(p12, "", 0) || PKCS12_verify_mac(p12, NULL, 0)) |
||
565 |
pass = ""; |
||
566 |
else { |
||
567 |
if (!pem_cb) |
||
568 |
pem_cb = password_callback; |
||
569 |
len = pem_cb(tpass, PEM_BUFSIZE, 0, cb_data); |
||
570 |
if (len < 0) { |
||
571 |
BIO_printf(err, "Passpharse callback error for %s\n", |
||
572 |
desc); |
||
573 |
goto die; |
||
574 |
} |
||
575 |
if (len < PEM_BUFSIZE) |
||
576 |
tpass[len] = 0; |
||
577 |
if (!PKCS12_verify_mac(p12, tpass, len)) { |
||
578 |
BIO_printf(err, |
||
579 |
"Mac verify error (wrong password?) in PKCS12 file for %s\n", desc); |
||
580 |
goto die; |
||
581 |
} |
||
582 |
pass = tpass; |
||
583 |
} |
||
584 |
ret = PKCS12_parse(p12, pass, pkey, cert, ca); |
||
585 |
|||
586 |
die: |
||
587 |
if (p12) |
||
588 |
PKCS12_free(p12); |
||
589 |
return ret; |
||
590 |
} |
||
591 |
|||
592 |
X509 * |
||
593 |
load_cert(BIO *err, const char *file, int format, const char *pass, |
||
594 |
const char *cert_descrip) |
||
595 |
{ |
||
596 |
466 |
X509 *x = NULL; |
|
597 |
BIO *cert; |
||
598 |
|||
599 |
✗✓ | 233 |
if ((cert = BIO_new(BIO_s_file())) == NULL) { |
600 |
ERR_print_errors(err); |
||
601 |
goto end; |
||
602 |
} |
||
603 |
✗✓ | 233 |
if (file == NULL) { |
604 |
setvbuf(stdin, NULL, _IONBF, 0); |
||
605 |
BIO_set_fp(cert, stdin, BIO_NOCLOSE); |
||
606 |
} else { |
||
607 |
✗✓ | 233 |
if (BIO_read_filename(cert, file) <= 0) { |
608 |
BIO_printf(err, "Error opening %s %s\n", |
||
609 |
cert_descrip, file); |
||
610 |
ERR_print_errors(err); |
||
611 |
goto end; |
||
612 |
} |
||
613 |
} |
||
614 |
|||
615 |
✓✓ | 233 |
if (format == FORMAT_ASN1) |
616 |
8 |
x = d2i_X509_bio(cert, NULL); |
|
617 |
✗✓ | 225 |
else if (format == FORMAT_NETSCAPE) { |
618 |
NETSCAPE_X509 *nx; |
||
619 |
nx = ASN1_item_d2i_bio(&NETSCAPE_X509_it, |
||
620 |
cert, NULL); |
||
621 |
if (nx == NULL) |
||
622 |
goto end; |
||
623 |
|||
624 |
if ((strncmp(NETSCAPE_CERT_HDR, (char *) nx->header->data, |
||
625 |
nx->header->length) != 0)) { |
||
626 |
NETSCAPE_X509_free(nx); |
||
627 |
BIO_printf(err, |
||
628 |
"Error reading header on certificate\n"); |
||
629 |
goto end; |
||
630 |
} |
||
631 |
x = nx->cert; |
||
632 |
nx->cert = NULL; |
||
633 |
NETSCAPE_X509_free(nx); |
||
634 |
✗✗✗✓ ✗ |
225 |
} else if (format == FORMAT_PEM) |
635 |
225 |
x = PEM_read_bio_X509_AUX(cert, NULL, password_callback, NULL); |
|
636 |
else if (format == FORMAT_PKCS12) { |
||
637 |
if (!load_pkcs12(err, cert, cert_descrip, NULL, NULL, |
||
638 |
NULL, &x, NULL)) |
||
639 |
goto end; |
||
640 |
} else { |
||
641 |
BIO_printf(err, "bad input format specified for %s\n", |
||
642 |
cert_descrip); |
||
643 |
goto end; |
||
644 |
} |
||
645 |
|||
646 |
end: |
||
647 |
✗✓ | 233 |
if (x == NULL) { |
648 |
BIO_printf(err, "unable to load certificate\n"); |
||
649 |
ERR_print_errors(err); |
||
650 |
} |
||
651 |
233 |
BIO_free(cert); |
|
652 |
233 |
return (x); |
|
653 |
233 |
} |
|
654 |
|||
655 |
EVP_PKEY * |
||
656 |
load_key(BIO *err, const char *file, int format, int maybe_stdin, |
||
657 |
const char *pass, const char *key_descrip) |
||
658 |
{ |
||
659 |
BIO *key = NULL; |
||
660 |
456 |
EVP_PKEY *pkey = NULL; |
|
661 |
228 |
PW_CB_DATA cb_data; |
|
662 |
|||
663 |
228 |
cb_data.password = pass; |
|
664 |
228 |
cb_data.prompt_info = file; |
|
665 |
|||
666 |
✗✓ | 228 |
if (file == NULL && (!maybe_stdin)) { |
667 |
BIO_printf(err, "no keyfile specified\n"); |
||
668 |
goto end; |
||
669 |
} |
||
670 |
228 |
key = BIO_new(BIO_s_file()); |
|
671 |
✗✓ | 228 |
if (key == NULL) { |
672 |
ERR_print_errors(err); |
||
673 |
goto end; |
||
674 |
} |
||
675 |
✗✓ | 228 |
if (file == NULL && maybe_stdin) { |
676 |
setvbuf(stdin, NULL, _IONBF, 0); |
||
677 |
BIO_set_fp(key, stdin, BIO_NOCLOSE); |
||
678 |
✗✓ | 228 |
} else if (BIO_read_filename(key, file) <= 0) { |
679 |
BIO_printf(err, "Error opening %s %s\n", |
||
680 |
key_descrip, file); |
||
681 |
ERR_print_errors(err); |
||
682 |
goto end; |
||
683 |
} |
||
684 |
✗✓ | 228 |
if (format == FORMAT_ASN1) { |
685 |
pkey = d2i_PrivateKey_bio(key, NULL); |
||
686 |
✓✗ | 228 |
} else if (format == FORMAT_PEM) { |
687 |
228 |
pkey = PEM_read_bio_PrivateKey(key, NULL, password_callback, &cb_data); |
|
688 |
228 |
} |
|
689 |
#if !defined(OPENSSL_NO_RC4) && !defined(OPENSSL_NO_RSA) |
||
690 |
else if (format == FORMAT_NETSCAPE || format == FORMAT_IISSGC) |
||
691 |
pkey = load_netscape_key(err, key, file, key_descrip, format); |
||
692 |
#endif |
||
693 |
else if (format == FORMAT_PKCS12) { |
||
694 |
if (!load_pkcs12(err, key, key_descrip, password_callback, &cb_data, |
||
695 |
&pkey, NULL, NULL)) |
||
696 |
goto end; |
||
697 |
} |
||
698 |
#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DSA) && !defined (OPENSSL_NO_RC4) |
||
699 |
else if (format == FORMAT_MSBLOB) |
||
700 |
pkey = b2i_PrivateKey_bio(key); |
||
701 |
else if (format == FORMAT_PVK) |
||
702 |
pkey = b2i_PVK_bio(key, password_callback, |
||
703 |
&cb_data); |
||
704 |
#endif |
||
705 |
else { |
||
706 |
BIO_printf(err, "bad input format specified for key file\n"); |
||
707 |
goto end; |
||
708 |
} |
||
709 |
end: |
||
710 |
228 |
BIO_free(key); |
|
711 |
✗✓ | 228 |
if (pkey == NULL) { |
712 |
BIO_printf(err, "unable to load %s\n", key_descrip); |
||
713 |
ERR_print_errors(err); |
||
714 |
} |
||
715 |
456 |
return (pkey); |
|
716 |
228 |
} |
|
717 |
|||
718 |
EVP_PKEY * |
||
719 |
load_pubkey(BIO *err, const char *file, int format, int maybe_stdin, |
||
720 |
const char *pass, const char *key_descrip) |
||
721 |
{ |
||
722 |
BIO *key = NULL; |
||
723 |
EVP_PKEY *pkey = NULL; |
||
724 |
PW_CB_DATA cb_data; |
||
725 |
|||
726 |
cb_data.password = pass; |
||
727 |
cb_data.prompt_info = file; |
||
728 |
|||
729 |
if (file == NULL && !maybe_stdin) { |
||
730 |
BIO_printf(err, "no keyfile specified\n"); |
||
731 |
goto end; |
||
732 |
} |
||
733 |
key = BIO_new(BIO_s_file()); |
||
734 |
if (key == NULL) { |
||
735 |
ERR_print_errors(err); |
||
736 |
goto end; |
||
737 |
} |
||
738 |
if (file == NULL && maybe_stdin) { |
||
739 |
setvbuf(stdin, NULL, _IONBF, 0); |
||
740 |
BIO_set_fp(key, stdin, BIO_NOCLOSE); |
||
741 |
} else if (BIO_read_filename(key, file) <= 0) { |
||
742 |
BIO_printf(err, "Error opening %s %s\n", key_descrip, file); |
||
743 |
ERR_print_errors(err); |
||
744 |
goto end; |
||
745 |
} |
||
746 |
if (format == FORMAT_ASN1) { |
||
747 |
pkey = d2i_PUBKEY_bio(key, NULL); |
||
748 |
} |
||
749 |
else if (format == FORMAT_ASN1RSA) { |
||
750 |
RSA *rsa; |
||
751 |
rsa = d2i_RSAPublicKey_bio(key, NULL); |
||
752 |
if (rsa) { |
||
753 |
pkey = EVP_PKEY_new(); |
||
754 |
if (pkey) |
||
755 |
EVP_PKEY_set1_RSA(pkey, rsa); |
||
756 |
RSA_free(rsa); |
||
757 |
} else |
||
758 |
pkey = NULL; |
||
759 |
} else if (format == FORMAT_PEMRSA) { |
||
760 |
RSA *rsa; |
||
761 |
rsa = PEM_read_bio_RSAPublicKey(key, NULL, password_callback, &cb_data); |
||
762 |
if (rsa) { |
||
763 |
pkey = EVP_PKEY_new(); |
||
764 |
if (pkey) |
||
765 |
EVP_PKEY_set1_RSA(pkey, rsa); |
||
766 |
RSA_free(rsa); |
||
767 |
} else |
||
768 |
pkey = NULL; |
||
769 |
} |
||
770 |
else if (format == FORMAT_PEM) { |
||
771 |
pkey = PEM_read_bio_PUBKEY(key, NULL, password_callback, &cb_data); |
||
772 |
} |
||
773 |
#if !defined(OPENSSL_NO_RC4) && !defined(OPENSSL_NO_RSA) |
||
774 |
else if (format == FORMAT_NETSCAPE || format == FORMAT_IISSGC) |
||
775 |
pkey = load_netscape_key(err, key, file, key_descrip, format); |
||
776 |
#endif |
||
777 |
#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DSA) |
||
778 |
else if (format == FORMAT_MSBLOB) |
||
779 |
pkey = b2i_PublicKey_bio(key); |
||
780 |
#endif |
||
781 |
else { |
||
782 |
BIO_printf(err, "bad input format specified for key file\n"); |
||
783 |
goto end; |
||
784 |
} |
||
785 |
|||
786 |
end: |
||
787 |
BIO_free(key); |
||
788 |
if (pkey == NULL) |
||
789 |
BIO_printf(err, "unable to load %s\n", key_descrip); |
||
790 |
return (pkey); |
||
791 |
} |
||
792 |
|||
793 |
#if !defined(OPENSSL_NO_RC4) && !defined(OPENSSL_NO_RSA) |
||
794 |
static EVP_PKEY * |
||
795 |
load_netscape_key(BIO *err, BIO *key, const char *file, |
||
796 |
const char *key_descrip, int format) |
||
797 |
{ |
||
798 |
EVP_PKEY *pkey; |
||
799 |
BUF_MEM *buf; |
||
800 |
RSA *rsa; |
||
801 |
const unsigned char *p; |
||
802 |
int size, i; |
||
803 |
|||
804 |
buf = BUF_MEM_new(); |
||
805 |
pkey = EVP_PKEY_new(); |
||
806 |
size = 0; |
||
807 |
if (buf == NULL || pkey == NULL) |
||
808 |
goto error; |
||
809 |
for (;;) { |
||
810 |
if (!BUF_MEM_grow_clean(buf, size + 1024 * 10)) |
||
811 |
goto error; |
||
812 |
i = BIO_read(key, &(buf->data[size]), 1024 * 10); |
||
813 |
size += i; |
||
814 |
if (i == 0) |
||
815 |
break; |
||
816 |
if (i < 0) { |
||
817 |
BIO_printf(err, "Error reading %s %s", |
||
818 |
key_descrip, file); |
||
819 |
goto error; |
||
820 |
} |
||
821 |
} |
||
822 |
p = (unsigned char *) buf->data; |
||
823 |
rsa = d2i_RSA_NET(NULL, &p, (long) size, NULL, |
||
824 |
(format == FORMAT_IISSGC ? 1 : 0)); |
||
825 |
if (rsa == NULL) |
||
826 |
goto error; |
||
827 |
BUF_MEM_free(buf); |
||
828 |
EVP_PKEY_set1_RSA(pkey, rsa); |
||
829 |
return pkey; |
||
830 |
|||
831 |
error: |
||
832 |
BUF_MEM_free(buf); |
||
833 |
EVP_PKEY_free(pkey); |
||
834 |
return NULL; |
||
835 |
} |
||
836 |
#endif /* ndef OPENSSL_NO_RC4 */ |
||
837 |
|||
838 |
static int |
||
839 |
load_certs_crls(BIO *err, const char *file, int format, const char *pass, |
||
840 |
const char *desc, STACK_OF(X509) **pcerts, |
||
841 |
STACK_OF(X509_CRL) **pcrls) |
||
842 |
{ |
||
843 |
int i; |
||
844 |
BIO *bio; |
||
845 |
STACK_OF(X509_INFO) *xis = NULL; |
||
846 |
X509_INFO *xi; |
||
847 |
32 |
PW_CB_DATA cb_data; |
|
848 |
int rv = 0; |
||
849 |
|||
850 |
16 |
cb_data.password = pass; |
|
851 |
16 |
cb_data.prompt_info = file; |
|
852 |
|||
853 |
✗✓ | 16 |
if (format != FORMAT_PEM) { |
854 |
BIO_printf(err, "bad input format specified for %s\n", desc); |
||
855 |
return 0; |
||
856 |
} |
||
857 |
✗✓ | 16 |
if (file == NULL) |
858 |
bio = BIO_new_fp(stdin, BIO_NOCLOSE); |
||
859 |
else |
||
860 |
16 |
bio = BIO_new_file(file, "r"); |
|
861 |
|||
862 |
✗✓ | 16 |
if (bio == NULL) { |
863 |
BIO_printf(err, "Error opening %s %s\n", |
||
864 |
desc, file ? file : "stdin"); |
||
865 |
ERR_print_errors(err); |
||
866 |
return 0; |
||
867 |
} |
||
868 |
16 |
xis = PEM_X509_INFO_read_bio(bio, NULL, password_callback, &cb_data); |
|
869 |
|||
870 |
16 |
BIO_free(bio); |
|
871 |
|||
872 |
✓✗ | 16 |
if (pcerts) { |
873 |
16 |
*pcerts = sk_X509_new_null(); |
|
874 |
✓✗ | 16 |
if (!*pcerts) |
875 |
goto end; |
||
876 |
} |
||
877 |
✗✓ | 16 |
if (pcrls) { |
878 |
*pcrls = sk_X509_CRL_new_null(); |
||
879 |
if (!*pcrls) |
||
880 |
goto end; |
||
881 |
} |
||
882 |
✓✓ | 64 |
for (i = 0; i < sk_X509_INFO_num(xis); i++) { |
883 |
16 |
xi = sk_X509_INFO_value(xis, i); |
|
884 |
✓✗ | 16 |
if (xi->x509 && pcerts) { |
885 |
✓✗ | 16 |
if (!sk_X509_push(*pcerts, xi->x509)) |
886 |
goto end; |
||
887 |
16 |
xi->x509 = NULL; |
|
888 |
16 |
} |
|
889 |
✗✓ | 16 |
if (xi->crl && pcrls) { |
890 |
if (!sk_X509_CRL_push(*pcrls, xi->crl)) |
||
891 |
goto end; |
||
892 |
xi->crl = NULL; |
||
893 |
} |
||
894 |
} |
||
895 |
|||
896 |
✓✗✓✗ |
32 |
if (pcerts && sk_X509_num(*pcerts) > 0) |
897 |
16 |
rv = 1; |
|
898 |
|||
899 |
✗✓✗✗ |
16 |
if (pcrls && sk_X509_CRL_num(*pcrls) > 0) |
900 |
rv = 1; |
||
901 |
|||
902 |
end: |
||
903 |
✓✗ | 16 |
if (xis) |
904 |
16 |
sk_X509_INFO_pop_free(xis, X509_INFO_free); |
|
905 |
|||
906 |
✗✓ | 16 |
if (rv == 0) { |
907 |
if (pcerts) { |
||
908 |
sk_X509_pop_free(*pcerts, X509_free); |
||
909 |
*pcerts = NULL; |
||
910 |
} |
||
911 |
if (pcrls) { |
||
912 |
sk_X509_CRL_pop_free(*pcrls, X509_CRL_free); |
||
913 |
*pcrls = NULL; |
||
914 |
} |
||
915 |
BIO_printf(err, "unable to load %s\n", |
||
916 |
pcerts ? "certificates" : "CRLs"); |
||
917 |
ERR_print_errors(err); |
||
918 |
} |
||
919 |
16 |
return rv; |
|
920 |
16 |
} |
|
921 |
|||
922 |
STACK_OF(X509) * |
||
923 |
load_certs(BIO *err, const char *file, int format, const char *pass, |
||
924 |
const char *desc) |
||
925 |
{ |
||
926 |
32 |
STACK_OF(X509) *certs; |
|
927 |
|||
928 |
✗✓ | 16 |
if (!load_certs_crls(err, file, format, pass, desc, &certs, NULL)) |
929 |
return NULL; |
||
930 |
16 |
return certs; |
|
931 |
16 |
} |
|
932 |
|||
933 |
STACK_OF(X509_CRL) * |
||
934 |
load_crls(BIO *err, const char *file, int format, const char *pass, |
||
935 |
const char *desc) |
||
936 |
{ |
||
937 |
STACK_OF(X509_CRL) *crls; |
||
938 |
|||
939 |
if (!load_certs_crls(err, file, format, pass, desc, NULL, &crls)) |
||
940 |
return NULL; |
||
941 |
return crls; |
||
942 |
} |
||
943 |
|||
944 |
#define X509V3_EXT_UNKNOWN_MASK (0xfL << 16) |
||
945 |
/* Return error for unknown extensions */ |
||
946 |
#define X509V3_EXT_DEFAULT 0 |
||
947 |
/* Print error for unknown extensions */ |
||
948 |
#define X509V3_EXT_ERROR_UNKNOWN (1L << 16) |
||
949 |
/* ASN1 parse unknown extensions */ |
||
950 |
#define X509V3_EXT_PARSE_UNKNOWN (2L << 16) |
||
951 |
/* BIO_dump unknown extensions */ |
||
952 |
#define X509V3_EXT_DUMP_UNKNOWN (3L << 16) |
||
953 |
|||
954 |
#define X509_FLAG_CA (X509_FLAG_NO_ISSUER | X509_FLAG_NO_PUBKEY | \ |
||
955 |
X509_FLAG_NO_HEADER | X509_FLAG_NO_VERSION) |
||
956 |
|||
957 |
int |
||
958 |
set_cert_ex(unsigned long *flags, const char *arg) |
||
959 |
{ |
||
960 |
static const NAME_EX_TBL cert_tbl[] = { |
||
961 |
{"compatible", X509_FLAG_COMPAT, 0xffffffffl}, |
||
962 |
{"ca_default", X509_FLAG_CA, 0xffffffffl}, |
||
963 |
{"no_header", X509_FLAG_NO_HEADER, 0}, |
||
964 |
{"no_version", X509_FLAG_NO_VERSION, 0}, |
||
965 |
{"no_serial", X509_FLAG_NO_SERIAL, 0}, |
||
966 |
{"no_signame", X509_FLAG_NO_SIGNAME, 0}, |
||
967 |
{"no_validity", X509_FLAG_NO_VALIDITY, 0}, |
||
968 |
{"no_subject", X509_FLAG_NO_SUBJECT, 0}, |
||
969 |
{"no_issuer", X509_FLAG_NO_ISSUER, 0}, |
||
970 |
{"no_pubkey", X509_FLAG_NO_PUBKEY, 0}, |
||
971 |
{"no_extensions", X509_FLAG_NO_EXTENSIONS, 0}, |
||
972 |
{"no_sigdump", X509_FLAG_NO_SIGDUMP, 0}, |
||
973 |
{"no_aux", X509_FLAG_NO_AUX, 0}, |
||
974 |
{"no_attributes", X509_FLAG_NO_ATTRIBUTES, 0}, |
||
975 |
{"ext_default", X509V3_EXT_DEFAULT, X509V3_EXT_UNKNOWN_MASK}, |
||
976 |
{"ext_error", X509V3_EXT_ERROR_UNKNOWN, X509V3_EXT_UNKNOWN_MASK}, |
||
977 |
{"ext_parse", X509V3_EXT_PARSE_UNKNOWN, X509V3_EXT_UNKNOWN_MASK}, |
||
978 |
{"ext_dump", X509V3_EXT_DUMP_UNKNOWN, X509V3_EXT_UNKNOWN_MASK}, |
||
979 |
{NULL, 0, 0} |
||
980 |
}; |
||
981 |
return set_multi_opts(flags, arg, cert_tbl); |
||
982 |
} |
||
983 |
|||
984 |
int |
||
985 |
set_name_ex(unsigned long *flags, const char *arg) |
||
986 |
{ |
||
987 |
static const NAME_EX_TBL ex_tbl[] = { |
||
988 |
{"esc_2253", ASN1_STRFLGS_ESC_2253, 0}, |
||
989 |
{"esc_ctrl", ASN1_STRFLGS_ESC_CTRL, 0}, |
||
990 |
{"esc_msb", ASN1_STRFLGS_ESC_MSB, 0}, |
||
991 |
{"use_quote", ASN1_STRFLGS_ESC_QUOTE, 0}, |
||
992 |
{"utf8", ASN1_STRFLGS_UTF8_CONVERT, 0}, |
||
993 |
{"ignore_type", ASN1_STRFLGS_IGNORE_TYPE, 0}, |
||
994 |
{"show_type", ASN1_STRFLGS_SHOW_TYPE, 0}, |
||
995 |
{"dump_all", ASN1_STRFLGS_DUMP_ALL, 0}, |
||
996 |
{"dump_nostr", ASN1_STRFLGS_DUMP_UNKNOWN, 0}, |
||
997 |
{"dump_der", ASN1_STRFLGS_DUMP_DER, 0}, |
||
998 |
{"compat", XN_FLAG_COMPAT, 0xffffffffL}, |
||
999 |
{"sep_comma_plus", XN_FLAG_SEP_COMMA_PLUS, XN_FLAG_SEP_MASK}, |
||
1000 |
{"sep_comma_plus_space", XN_FLAG_SEP_CPLUS_SPC, XN_FLAG_SEP_MASK}, |
||
1001 |
{"sep_semi_plus_space", XN_FLAG_SEP_SPLUS_SPC, XN_FLAG_SEP_MASK}, |
||
1002 |
{"sep_multiline", XN_FLAG_SEP_MULTILINE, XN_FLAG_SEP_MASK}, |
||
1003 |
{"dn_rev", XN_FLAG_DN_REV, 0}, |
||
1004 |
{"nofname", XN_FLAG_FN_NONE, XN_FLAG_FN_MASK}, |
||
1005 |
{"sname", XN_FLAG_FN_SN, XN_FLAG_FN_MASK}, |
||
1006 |
{"lname", XN_FLAG_FN_LN, XN_FLAG_FN_MASK}, |
||
1007 |
{"align", XN_FLAG_FN_ALIGN, 0}, |
||
1008 |
{"oid", XN_FLAG_FN_OID, XN_FLAG_FN_MASK}, |
||
1009 |
{"space_eq", XN_FLAG_SPC_EQ, 0}, |
||
1010 |
{"dump_unknown", XN_FLAG_DUMP_UNKNOWN_FIELDS, 0}, |
||
1011 |
{"RFC2253", XN_FLAG_RFC2253, 0xffffffffL}, |
||
1012 |
{"oneline", XN_FLAG_ONELINE, 0xffffffffL}, |
||
1013 |
{"multiline", XN_FLAG_MULTILINE, 0xffffffffL}, |
||
1014 |
{"ca_default", XN_FLAG_MULTILINE, 0xffffffffL}, |
||
1015 |
{NULL, 0, 0} |
||
1016 |
}; |
||
1017 |
return set_multi_opts(flags, arg, ex_tbl); |
||
1018 |
} |
||
1019 |
|||
1020 |
int |
||
1021 |
set_ext_copy(int *copy_type, const char *arg) |
||
1022 |
{ |
||
1023 |
if (!strcasecmp(arg, "none")) |
||
1024 |
*copy_type = EXT_COPY_NONE; |
||
1025 |
else if (!strcasecmp(arg, "copy")) |
||
1026 |
*copy_type = EXT_COPY_ADD; |
||
1027 |
else if (!strcasecmp(arg, "copyall")) |
||
1028 |
*copy_type = EXT_COPY_ALL; |
||
1029 |
else |
||
1030 |
return 0; |
||
1031 |
return 1; |
||
1032 |
} |
||
1033 |
|||
1034 |
int |
||
1035 |
copy_extensions(X509 *x, X509_REQ *req, int copy_type) |
||
1036 |
{ |
||
1037 |
STACK_OF(X509_EXTENSION) *exts = NULL; |
||
1038 |
X509_EXTENSION *ext, *tmpext; |
||
1039 |
ASN1_OBJECT *obj; |
||
1040 |
int i, idx, ret = 0; |
||
1041 |
|||
1042 |
✓✗ | 80 |
if (!x || !req || (copy_type == EXT_COPY_NONE)) |
1043 |
40 |
return 1; |
|
1044 |
exts = X509_REQ_get_extensions(req); |
||
1045 |
|||
1046 |
for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) { |
||
1047 |
ext = sk_X509_EXTENSION_value(exts, i); |
||
1048 |
obj = X509_EXTENSION_get_object(ext); |
||
1049 |
idx = X509_get_ext_by_OBJ(x, obj, -1); |
||
1050 |
/* Does extension exist? */ |
||
1051 |
if (idx != -1) { |
||
1052 |
/* If normal copy don't override existing extension */ |
||
1053 |
if (copy_type == EXT_COPY_ADD) |
||
1054 |
continue; |
||
1055 |
/* Delete all extensions of same type */ |
||
1056 |
do { |
||
1057 |
tmpext = X509_get_ext(x, idx); |
||
1058 |
X509_delete_ext(x, idx); |
||
1059 |
X509_EXTENSION_free(tmpext); |
||
1060 |
idx = X509_get_ext_by_OBJ(x, obj, -1); |
||
1061 |
} while (idx != -1); |
||
1062 |
} |
||
1063 |
if (!X509_add_ext(x, ext, -1)) |
||
1064 |
goto end; |
||
1065 |
} |
||
1066 |
|||
1067 |
ret = 1; |
||
1068 |
|||
1069 |
end: |
||
1070 |
sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); |
||
1071 |
|||
1072 |
return ret; |
||
1073 |
40 |
} |
|
1074 |
|||
1075 |
static int |
||
1076 |
set_multi_opts(unsigned long *flags, const char *arg, |
||
1077 |
const NAME_EX_TBL *in_tbl) |
||
1078 |
{ |
||
1079 |
STACK_OF(CONF_VALUE) *vals; |
||
1080 |
CONF_VALUE *val; |
||
1081 |
int i, ret = 1; |
||
1082 |
|||
1083 |
if (!arg) |
||
1084 |
return 0; |
||
1085 |
vals = X509V3_parse_list(arg); |
||
1086 |
for (i = 0; i < sk_CONF_VALUE_num(vals); i++) { |
||
1087 |
val = sk_CONF_VALUE_value(vals, i); |
||
1088 |
if (!set_table_opts(flags, val->name, in_tbl)) |
||
1089 |
ret = 0; |
||
1090 |
} |
||
1091 |
sk_CONF_VALUE_pop_free(vals, X509V3_conf_free); |
||
1092 |
return ret; |
||
1093 |
} |
||
1094 |
|||
1095 |
static int |
||
1096 |
set_table_opts(unsigned long *flags, const char *arg, |
||
1097 |
const NAME_EX_TBL *in_tbl) |
||
1098 |
{ |
||
1099 |
char c; |
||
1100 |
const NAME_EX_TBL *ptbl; |
||
1101 |
|||
1102 |
c = arg[0]; |
||
1103 |
if (c == '-') { |
||
1104 |
c = 0; |
||
1105 |
arg++; |
||
1106 |
} else if (c == '+') { |
||
1107 |
c = 1; |
||
1108 |
arg++; |
||
1109 |
} else |
||
1110 |
c = 1; |
||
1111 |
|||
1112 |
for (ptbl = in_tbl; ptbl->name; ptbl++) { |
||
1113 |
if (!strcasecmp(arg, ptbl->name)) { |
||
1114 |
*flags &= ~ptbl->mask; |
||
1115 |
if (c) |
||
1116 |
*flags |= ptbl->flag; |
||
1117 |
else |
||
1118 |
*flags &= ~ptbl->flag; |
||
1119 |
return 1; |
||
1120 |
} |
||
1121 |
} |
||
1122 |
return 0; |
||
1123 |
} |
||
1124 |
|||
1125 |
void |
||
1126 |
print_name(BIO *out, const char *title, X509_NAME *nm, unsigned long lflags) |
||
1127 |
{ |
||
1128 |
char *buf; |
||
1129 |
char mline = 0; |
||
1130 |
int indent = 0; |
||
1131 |
|||
1132 |
✓✗ | 88 |
if (title) |
1133 |
44 |
BIO_puts(out, title); |
|
1134 |
✗✓ | 44 |
if ((lflags & XN_FLAG_SEP_MASK) == XN_FLAG_SEP_MULTILINE) { |
1135 |
mline = 1; |
||
1136 |
indent = 4; |
||
1137 |
} |
||
1138 |
✓✗ | 44 |
if (lflags == XN_FLAG_COMPAT) { |
1139 |
44 |
buf = X509_NAME_oneline(nm, 0, 0); |
|
1140 |
44 |
BIO_puts(out, buf); |
|
1141 |
44 |
BIO_puts(out, "\n"); |
|
1142 |
44 |
free(buf); |
|
1143 |
44 |
} else { |
|
1144 |
if (mline) |
||
1145 |
BIO_puts(out, "\n"); |
||
1146 |
X509_NAME_print_ex(out, nm, indent, lflags); |
||
1147 |
BIO_puts(out, "\n"); |
||
1148 |
} |
||
1149 |
44 |
} |
|
1150 |
|||
1151 |
X509_STORE * |
||
1152 |
setup_verify(BIO *bp, char *CAfile, char *CApath) |
||
1153 |
{ |
||
1154 |
X509_STORE *store; |
||
1155 |
X509_LOOKUP *lookup; |
||
1156 |
|||
1157 |
✓✗ | 48 |
if (!(store = X509_STORE_new())) |
1158 |
goto end; |
||
1159 |
24 |
lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); |
|
1160 |
✓✗ | 24 |
if (lookup == NULL) |
1161 |
goto end; |
||
1162 |
✓✗ | 24 |
if (CAfile) { |
1163 |
✗✓ | 24 |
if (!X509_LOOKUP_load_file(lookup, CAfile, X509_FILETYPE_PEM)) { |
1164 |
BIO_printf(bp, "Error loading file %s\n", CAfile); |
||
1165 |
goto end; |
||
1166 |
} |
||
1167 |
} else |
||
1168 |
X509_LOOKUP_load_file(lookup, NULL, X509_FILETYPE_DEFAULT); |
||
1169 |
|||
1170 |
24 |
lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir()); |
|
1171 |
✓✗ | 24 |
if (lookup == NULL) |
1172 |
goto end; |
||
1173 |
✗✓ | 24 |
if (CApath) { |
1174 |
if (!X509_LOOKUP_add_dir(lookup, CApath, X509_FILETYPE_PEM)) { |
||
1175 |
BIO_printf(bp, "Error loading directory %s\n", CApath); |
||
1176 |
goto end; |
||
1177 |
} |
||
1178 |
} else |
||
1179 |
24 |
X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT); |
|
1180 |
|||
1181 |
24 |
ERR_clear_error(); |
|
1182 |
24 |
return store; |
|
1183 |
|||
1184 |
end: |
||
1185 |
X509_STORE_free(store); |
||
1186 |
return NULL; |
||
1187 |
24 |
} |
|
1188 |
|||
1189 |
int |
||
1190 |
load_config(BIO *err, CONF *cnf) |
||
1191 |
{ |
||
1192 |
static int load_config_called = 0; |
||
1193 |
|||
1194 |
✓✓ | 11378 |
if (load_config_called) |
1195 |
114 |
return 1; |
|
1196 |
5575 |
load_config_called = 1; |
|
1197 |
✓✗ | 5575 |
if (cnf == NULL) |
1198 |
5575 |
cnf = config; |
|
1199 |
✗✓ | 5575 |
if (cnf == NULL) |
1200 |
return 1; |
||
1201 |
|||
1202 |
5575 |
OPENSSL_load_builtin_modules(); |
|
1203 |
|||
1204 |
✗✓ | 5575 |
if (CONF_modules_load(cnf, NULL, 0) <= 0) { |
1205 |
BIO_printf(err, "Error configuring OpenSSL\n"); |
||
1206 |
ERR_print_errors(err); |
||
1207 |
return 0; |
||
1208 |
} |
||
1209 |
5575 |
return 1; |
|
1210 |
5689 |
} |
|
1211 |
|||
1212 |
char * |
||
1213 |
make_config_name() |
||
1214 |
{ |
||
1215 |
3614 |
const char *t = X509_get_default_cert_area(); |
|
1216 |
1807 |
char *p; |
|
1217 |
|||
1218 |
✗✓ | 1807 |
if (asprintf(&p, "%s/openssl.cnf", t) == -1) |
1219 |
return NULL; |
||
1220 |
1807 |
return p; |
|
1221 |
1807 |
} |
|
1222 |
|||
1223 |
static unsigned long |
||
1224 |
index_serial_hash(const OPENSSL_CSTRING *a) |
||
1225 |
{ |
||
1226 |
const char *n; |
||
1227 |
|||
1228 |
800 |
n = a[DB_serial]; |
|
1229 |
✓✓ | 1440 |
while (*n == '0') |
1230 |
320 |
n++; |
|
1231 |
400 |
return (lh_strhash(n)); |
|
1232 |
} |
||
1233 |
|||
1234 |
static int |
||
1235 |
index_serial_cmp(const OPENSSL_CSTRING *a, const OPENSSL_CSTRING *b) |
||
1236 |
{ |
||
1237 |
const char *aa, *bb; |
||
1238 |
|||
1239 |
✓✓ | 152 |
for (aa = a[DB_serial]; *aa == '0'; aa++) |
1240 |
; |
||
1241 |
✓✓ | 112 |
for (bb = b[DB_serial]; *bb == '0'; bb++) |
1242 |
; |
||
1243 |
40 |
return (strcmp(aa, bb)); |
|
1244 |
} |
||
1245 |
|||
1246 |
static int |
||
1247 |
index_name_qual(char **a) |
||
1248 |
{ |
||
1249 |
624 |
return (a[0][0] == 'V'); |
|
1250 |
} |
||
1251 |
|||
1252 |
static unsigned long |
||
1253 |
index_name_hash(const OPENSSL_CSTRING *a) |
||
1254 |
{ |
||
1255 |
640 |
return (lh_strhash(a[DB_name])); |
|
1256 |
} |
||
1257 |
|||
1258 |
int |
||
1259 |
index_name_cmp(const OPENSSL_CSTRING *a, const OPENSSL_CSTRING *b) |
||
1260 |
{ |
||
1261 |
16 |
return (strcmp(a[DB_name], b[DB_name])); |
|
1262 |
} |
||
1263 |
|||
1264 |
800 |
static IMPLEMENT_LHASH_HASH_FN(index_serial, OPENSSL_CSTRING) |
|
1265 |
80 |
static IMPLEMENT_LHASH_COMP_FN(index_serial, OPENSSL_CSTRING) |
|
1266 |
640 |
static IMPLEMENT_LHASH_HASH_FN(index_name, OPENSSL_CSTRING) |
|
1267 |
static IMPLEMENT_LHASH_COMP_FN(index_name, OPENSSL_CSTRING) |
||
1268 |
|||
1269 |
BIGNUM * |
||
1270 |
load_serial(char *serialfile, int create, ASN1_INTEGER **retai) |
||
1271 |
{ |
||
1272 |
BIO *in = NULL; |
||
1273 |
BIGNUM *ret = NULL; |
||
1274 |
152 |
char buf[1024]; |
|
1275 |
ASN1_INTEGER *ai = NULL; |
||
1276 |
|||
1277 |
76 |
ai = ASN1_INTEGER_new(); |
|
1278 |
✓✗ | 76 |
if (ai == NULL) |
1279 |
goto err; |
||
1280 |
|||
1281 |
✗✓ | 76 |
if ((in = BIO_new(BIO_s_file())) == NULL) { |
1282 |
ERR_print_errors(bio_err); |
||
1283 |
goto err; |
||
1284 |
} |
||
1285 |
✓✓ | 76 |
if (BIO_read_filename(in, serialfile) <= 0) { |
1286 |
✗✓ | 23 |
if (!create) { |
1287 |
perror(serialfile); |
||
1288 |
goto err; |
||
1289 |
} else { |
||
1290 |
23 |
ret = BN_new(); |
|
1291 |
✓✗✗✓ |
46 |
if (ret == NULL || !rand_serial(ret, ai)) |
1292 |
BIO_printf(bio_err, "Out of memory\n"); |
||
1293 |
} |
||
1294 |
} else { |
||
1295 |
✗✓ | 53 |
if (!a2i_ASN1_INTEGER(in, ai, buf, sizeof buf)) { |
1296 |
BIO_printf(bio_err, "unable to load number from %s\n", |
||
1297 |
serialfile); |
||
1298 |
goto err; |
||
1299 |
} |
||
1300 |
53 |
ret = ASN1_INTEGER_to_BN(ai, NULL); |
|
1301 |
✗✓ | 53 |
if (ret == NULL) { |
1302 |
BIO_printf(bio_err, |
||
1303 |
"error converting number from bin to BIGNUM\n"); |
||
1304 |
goto err; |
||
1305 |
} |
||
1306 |
} |
||
1307 |
|||
1308 |
✗✓ | 76 |
if (ret && retai) { |
1309 |
*retai = ai; |
||
1310 |
ai = NULL; |
||
1311 |
} |
||
1312 |
|||
1313 |
err: |
||
1314 |
✓✗ | 76 |
if (in != NULL) |
1315 |
76 |
BIO_free(in); |
|
1316 |
✓✗ | 76 |
if (ai != NULL) |
1317 |
76 |
ASN1_INTEGER_free(ai); |
|
1318 |
76 |
return (ret); |
|
1319 |
76 |
} |
|
1320 |
|||
1321 |
int |
||
1322 |
save_serial(char *serialfile, char *suffix, BIGNUM *serial, |
||
1323 |
ASN1_INTEGER **retai) |
||
1324 |
{ |
||
1325 |
152 |
char serialpath[PATH_MAX]; |
|
1326 |
BIO *out = NULL; |
||
1327 |
int ret = 0, n; |
||
1328 |
ASN1_INTEGER *ai = NULL; |
||
1329 |
|||
1330 |
✓✓ | 76 |
if (suffix == NULL) |
1331 |
28 |
n = strlcpy(serialpath, serialfile, sizeof serialpath); |
|
1332 |
else |
||
1333 |
48 |
n = snprintf(serialpath, sizeof serialpath, "%s.%s", |
|
1334 |
serialfile, suffix); |
||
1335 |
✓✗✗✓ |
152 |
if (n == -1 || n >= sizeof(serialpath)) { |
1336 |
BIO_printf(bio_err, "serial too long\n"); |
||
1337 |
goto err; |
||
1338 |
} |
||
1339 |
76 |
out = BIO_new(BIO_s_file()); |
|
1340 |
✗✓ | 76 |
if (out == NULL) { |
1341 |
ERR_print_errors(bio_err); |
||
1342 |
goto err; |
||
1343 |
} |
||
1344 |
✗✓ | 76 |
if (BIO_write_filename(out, serialpath) <= 0) { |
1345 |
perror(serialfile); |
||
1346 |
goto err; |
||
1347 |
} |
||
1348 |
✗✓ | 76 |
if ((ai = BN_to_ASN1_INTEGER(serial, NULL)) == NULL) { |
1349 |
BIO_printf(bio_err, |
||
1350 |
"error converting serial to ASN.1 format\n"); |
||
1351 |
goto err; |
||
1352 |
} |
||
1353 |
76 |
i2a_ASN1_INTEGER(out, ai); |
|
1354 |
76 |
BIO_puts(out, "\n"); |
|
1355 |
ret = 1; |
||
1356 |
✓✓ | 76 |
if (retai) { |
1357 |
28 |
*retai = ai; |
|
1358 |
ai = NULL; |
||
1359 |
28 |
} |
|
1360 |
|||
1361 |
err: |
||
1362 |
✓✗ | 76 |
if (out != NULL) |
1363 |
76 |
BIO_free_all(out); |
|
1364 |
✓✓ | 76 |
if (ai != NULL) |
1365 |
48 |
ASN1_INTEGER_free(ai); |
|
1366 |
76 |
return (ret); |
|
1367 |
76 |
} |
|
1368 |
|||
1369 |
int |
||
1370 |
rotate_serial(char *serialfile, char *new_suffix, char *old_suffix) |
||
1371 |
{ |
||
1372 |
96 |
char opath[PATH_MAX], npath[PATH_MAX]; |
|
1373 |
|||
1374 |
✗✓ | 96 |
if (snprintf(npath, sizeof npath, "%s.%s", serialfile, |
1375 |
48 |
new_suffix) >= sizeof npath) { |
|
1376 |
BIO_printf(bio_err, "file name too long\n"); |
||
1377 |
goto err; |
||
1378 |
} |
||
1379 |
|||
1380 |
✗✓ | 96 |
if (snprintf(opath, sizeof opath, "%s.%s", serialfile, |
1381 |
48 |
old_suffix) >= sizeof opath) { |
|
1382 |
BIO_printf(bio_err, "file name too long\n"); |
||
1383 |
goto err; |
||
1384 |
} |
||
1385 |
|||
1386 |
✗✓✗✗ |
48 |
if (rename(serialfile, opath) < 0 && |
1387 |
errno != ENOENT && errno != ENOTDIR) { |
||
1388 |
BIO_printf(bio_err, "unable to rename %s to %s\n", |
||
1389 |
serialfile, opath); |
||
1390 |
perror("reason"); |
||
1391 |
goto err; |
||
1392 |
} |
||
1393 |
|||
1394 |
|||
1395 |
✗✓ | 48 |
if (rename(npath, serialfile) < 0) { |
1396 |
BIO_printf(bio_err, "unable to rename %s to %s\n", |
||
1397 |
npath, serialfile); |
||
1398 |
perror("reason"); |
||
1399 |
if (rename(opath, serialfile) < 0) { |
||
1400 |
BIO_printf(bio_err, "unable to rename %s to %s\n", |
||
1401 |
opath, serialfile); |
||
1402 |
perror("reason"); |
||
1403 |
} |
||
1404 |
goto err; |
||
1405 |
} |
||
1406 |
48 |
return 1; |
|
1407 |
|||
1408 |
err: |
||
1409 |
return 0; |
||
1410 |
48 |
} |
|
1411 |
|||
1412 |
int |
||
1413 |
rand_serial(BIGNUM *b, ASN1_INTEGER *ai) |
||
1414 |
{ |
||
1415 |
BIGNUM *btmp; |
||
1416 |
int ret = 0; |
||
1417 |
|||
1418 |
✓✓ | 210 |
if (b) |
1419 |
23 |
btmp = b; |
|
1420 |
else |
||
1421 |
82 |
btmp = BN_new(); |
|
1422 |
|||
1423 |
✗✓ | 105 |
if (!btmp) |
1424 |
return 0; |
||
1425 |
|||
1426 |
✓✗ | 105 |
if (!BN_pseudo_rand(btmp, SERIAL_RAND_BITS, 0, 0)) |
1427 |
goto error; |
||
1428 |
✓✗✓✗ |
210 |
if (ai && !BN_to_ASN1_INTEGER(btmp, ai)) |
1429 |
goto error; |
||
1430 |
|||
1431 |
105 |
ret = 1; |
|
1432 |
|||
1433 |
error: |
||
1434 |
✓✓ | 105 |
if (!b) |
1435 |
82 |
BN_free(btmp); |
|
1436 |
|||
1437 |
105 |
return ret; |
|
1438 |
105 |
} |
|
1439 |
|||
1440 |
CA_DB * |
||
1441 |
load_index(char *dbfile, DB_ATTR *db_attr) |
||
1442 |
{ |
||
1443 |
CA_DB *retdb = NULL; |
||
1444 |
TXT_DB *tmpdb = NULL; |
||
1445 |
128 |
BIO *in = BIO_new(BIO_s_file()); |
|
1446 |
CONF *dbattr_conf = NULL; |
||
1447 |
64 |
char attrpath[PATH_MAX]; |
|
1448 |
64 |
long errorline = -1; |
|
1449 |
|||
1450 |
✗✓ | 64 |
if (in == NULL) { |
1451 |
ERR_print_errors(bio_err); |
||
1452 |
goto err; |
||
1453 |
} |
||
1454 |
✗✓ | 64 |
if (BIO_read_filename(in, dbfile) <= 0) { |
1455 |
perror(dbfile); |
||
1456 |
BIO_printf(bio_err, "unable to open '%s'\n", dbfile); |
||
1457 |
goto err; |
||
1458 |
} |
||
1459 |
✓✗ | 64 |
if ((tmpdb = TXT_DB_read(in, DB_NUMBER)) == NULL) |
1460 |
goto err; |
||
1461 |
|||
1462 |
✗✓ | 128 |
if (snprintf(attrpath, sizeof attrpath, "%s.attr", dbfile) |
1463 |
64 |
>= sizeof attrpath) { |
|
1464 |
BIO_printf(bio_err, "attr filename too long\n"); |
||
1465 |
goto err; |
||
1466 |
} |
||
1467 |
|||
1468 |
64 |
dbattr_conf = NCONF_new(NULL); |
|
1469 |
✓✓ | 64 |
if (NCONF_load(dbattr_conf, attrpath, &errorline) <= 0) { |
1470 |
✗✓ | 8 |
if (errorline > 0) { |
1471 |
BIO_printf(bio_err, |
||
1472 |
"error on line %ld of db attribute file '%s'\n", |
||
1473 |
errorline, attrpath); |
||
1474 |
goto err; |
||
1475 |
} else { |
||
1476 |
8 |
NCONF_free(dbattr_conf); |
|
1477 |
dbattr_conf = NULL; |
||
1478 |
} |
||
1479 |
8 |
} |
|
1480 |
✗✓ | 64 |
if ((retdb = malloc(sizeof(CA_DB))) == NULL) { |
1481 |
fprintf(stderr, "Out of memory\n"); |
||
1482 |
goto err; |
||
1483 |
} |
||
1484 |
64 |
retdb->db = tmpdb; |
|
1485 |
tmpdb = NULL; |
||
1486 |
✓✓ | 64 |
if (db_attr) |
1487 |
48 |
retdb->attributes = *db_attr; |
|
1488 |
else { |
||
1489 |
16 |
retdb->attributes.unique_subject = 1; |
|
1490 |
} |
||
1491 |
|||
1492 |
✓✓ | 64 |
if (dbattr_conf) { |
1493 |
56 |
char *p = NCONF_get_string(dbattr_conf, NULL, "unique_subject"); |
|
1494 |
✓✗ | 56 |
if (p) { |
1495 |
56 |
retdb->attributes.unique_subject = parse_yesno(p, 1); |
|
1496 |
56 |
} |
|
1497 |
56 |
} |
|
1498 |
|||
1499 |
err: |
||
1500 |
✓✓ | 64 |
if (dbattr_conf) |
1501 |
56 |
NCONF_free(dbattr_conf); |
|
1502 |
✗✓ | 64 |
if (tmpdb) |
1503 |
TXT_DB_free(tmpdb); |
||
1504 |
✓✗ | 64 |
if (in) |
1505 |
64 |
BIO_free_all(in); |
|
1506 |
64 |
return retdb; |
|
1507 |
64 |
} |
|
1508 |
|||
1509 |
int |
||
1510 |
index_index(CA_DB *db) |
||
1511 |
{ |
||
1512 |
✗✓ | 128 |
if (!TXT_DB_create_index(db->db, DB_serial, NULL, |
1513 |
LHASH_HASH_FN(index_serial), LHASH_COMP_FN(index_serial))) { |
||
1514 |
BIO_printf(bio_err, |
||
1515 |
"error creating serial number index:(%ld,%ld,%ld)\n", |
||
1516 |
db->db->error, db->db->arg1, db->db->arg2); |
||
1517 |
return 0; |
||
1518 |
} |
||
1519 |
✓✗✗✓ |
128 |
if (db->attributes.unique_subject && |
1520 |
64 |
!TXT_DB_create_index(db->db, DB_name, index_name_qual, |
|
1521 |
LHASH_HASH_FN(index_name), LHASH_COMP_FN(index_name))) { |
||
1522 |
BIO_printf(bio_err, "error creating name index:(%ld,%ld,%ld)\n", |
||
1523 |
db->db->error, db->db->arg1, db->db->arg2); |
||
1524 |
return 0; |
||
1525 |
} |
||
1526 |
64 |
return 1; |
|
1527 |
64 |
} |
|
1528 |
|||
1529 |
int |
||
1530 |
save_index(const char *file, const char *suffix, CA_DB *db) |
||
1531 |
{ |
||
1532 |
96 |
char attrpath[PATH_MAX], dbfile[PATH_MAX]; |
|
1533 |
48 |
BIO *out = BIO_new(BIO_s_file()); |
|
1534 |
int j; |
||
1535 |
|||
1536 |
✗✓ | 48 |
if (out == NULL) { |
1537 |
ERR_print_errors(bio_err); |
||
1538 |
goto err; |
||
1539 |
} |
||
1540 |
✗✓ | 96 |
if (snprintf(attrpath, sizeof attrpath, "%s.attr.%s", |
1541 |
48 |
file, suffix) >= sizeof attrpath) { |
|
1542 |
BIO_printf(bio_err, "file name too long\n"); |
||
1543 |
goto err; |
||
1544 |
} |
||
1545 |
✗✓ | 96 |
if (snprintf(dbfile, sizeof dbfile, "%s.%s", |
1546 |
48 |
file, suffix) >= sizeof dbfile) { |
|
1547 |
BIO_printf(bio_err, "file name too long\n"); |
||
1548 |
goto err; |
||
1549 |
} |
||
1550 |
|||
1551 |
✗✓ | 48 |
if (BIO_write_filename(out, dbfile) <= 0) { |
1552 |
perror(dbfile); |
||
1553 |
BIO_printf(bio_err, "unable to open '%s'\n", dbfile); |
||
1554 |
goto err; |
||
1555 |
} |
||
1556 |
48 |
j = TXT_DB_write(out, db->db); |
|
1557 |
✓✗ | 48 |
if (j <= 0) |
1558 |
goto err; |
||
1559 |
|||
1560 |
48 |
BIO_free(out); |
|
1561 |
|||
1562 |
48 |
out = BIO_new(BIO_s_file()); |
|
1563 |
|||
1564 |
✗✓ | 48 |
if (BIO_write_filename(out, attrpath) <= 0) { |
1565 |
perror(attrpath); |
||
1566 |
BIO_printf(bio_err, "unable to open '%s'\n", attrpath); |
||
1567 |
goto err; |
||
1568 |
} |
||
1569 |
48 |
BIO_printf(out, "unique_subject = %s\n", |
|
1570 |
48 |
db->attributes.unique_subject ? "yes" : "no"); |
|
1571 |
48 |
BIO_free(out); |
|
1572 |
|||
1573 |
48 |
return 1; |
|
1574 |
|||
1575 |
err: |
||
1576 |
return 0; |
||
1577 |
48 |
} |
|
1578 |
|||
1579 |
int |
||
1580 |
rotate_index(const char *dbfile, const char *new_suffix, const char *old_suffix) |
||
1581 |
{ |
||
1582 |
96 |
char attrpath[PATH_MAX], nattrpath[PATH_MAX], oattrpath[PATH_MAX]; |
|
1583 |
48 |
char dbpath[PATH_MAX], odbpath[PATH_MAX]; |
|
1584 |
|||
1585 |
✗✓ | 96 |
if (snprintf(attrpath, sizeof attrpath, "%s.attr", |
1586 |
48 |
dbfile) >= sizeof attrpath) { |
|
1587 |
BIO_printf(bio_err, "file name too long\n"); |
||
1588 |
goto err; |
||
1589 |
} |
||
1590 |
✗✓ | 96 |
if (snprintf(nattrpath, sizeof nattrpath, "%s.attr.%s", |
1591 |
48 |
dbfile, new_suffix) >= sizeof nattrpath) { |
|
1592 |
BIO_printf(bio_err, "file name too long\n"); |
||
1593 |
goto err; |
||
1594 |
} |
||
1595 |
✗✓ | 96 |
if (snprintf(oattrpath, sizeof oattrpath, "%s.attr.%s", |
1596 |
48 |
dbfile, old_suffix) >= sizeof oattrpath) { |
|
1597 |
BIO_printf(bio_err, "file name too long\n"); |
||
1598 |
goto err; |
||
1599 |
} |
||
1600 |
✗✓ | 96 |
if (snprintf(dbpath, sizeof dbpath, "%s.%s", |
1601 |
48 |
dbfile, new_suffix) >= sizeof dbpath) { |
|
1602 |
BIO_printf(bio_err, "file name too long\n"); |
||
1603 |
goto err; |
||
1604 |
} |
||
1605 |
✗✓ | 96 |
if (snprintf(odbpath, sizeof odbpath, "%s.%s", |
1606 |
48 |
dbfile, old_suffix) >= sizeof odbpath) { |
|
1607 |
BIO_printf(bio_err, "file name too long\n"); |
||
1608 |
goto err; |
||
1609 |
} |
||
1610 |
|||
1611 |
✗✓✗✗ ✗✗ |
48 |
if (rename(dbfile, odbpath) < 0 && errno != ENOENT && errno != ENOTDIR) { |
1612 |
BIO_printf(bio_err, "unable to rename %s to %s\n", |
||
1613 |
dbfile, odbpath); |
||
1614 |
perror("reason"); |
||
1615 |
goto err; |
||
1616 |
} |
||
1617 |
|||
1618 |
✗✓ | 48 |
if (rename(dbpath, dbfile) < 0) { |
1619 |
BIO_printf(bio_err, "unable to rename %s to %s\n", |
||
1620 |
dbpath, dbfile); |
||
1621 |
perror("reason"); |
||
1622 |
if (rename(odbpath, dbfile) < 0) { |
||
1623 |
BIO_printf(bio_err, "unable to rename %s to %s\n", |
||
1624 |
odbpath, dbfile); |
||
1625 |
perror("reason"); |
||
1626 |
} |
||
1627 |
goto err; |
||
1628 |
} |
||
1629 |
|||
1630 |
✓✓✗✓ ✗✗ |
56 |
if (rename(attrpath, oattrpath) < 0 && errno != ENOENT && errno != ENOTDIR) { |
1631 |
BIO_printf(bio_err, "unable to rename %s to %s\n", |
||
1632 |
attrpath, oattrpath); |
||
1633 |
perror("reason"); |
||
1634 |
if (rename(dbfile, dbpath) < 0) { |
||
1635 |
BIO_printf(bio_err, "unable to rename %s to %s\n", |
||
1636 |
dbfile, dbpath); |
||
1637 |
perror("reason"); |
||
1638 |
} |
||
1639 |
if (rename(odbpath, dbfile) < 0) { |
||
1640 |
BIO_printf(bio_err, "unable to rename %s to %s\n", |
||
1641 |
odbpath, dbfile); |
||
1642 |
perror("reason"); |
||
1643 |
} |
||
1644 |
goto err; |
||
1645 |
} |
||
1646 |
|||
1647 |
✗✓ | 48 |
if (rename(nattrpath, attrpath) < 0) { |
1648 |
BIO_printf(bio_err, "unable to rename %s to %s\n", |
||
1649 |
nattrpath, attrpath); |
||
1650 |
perror("reason"); |
||
1651 |
if (rename(oattrpath, attrpath) < 0) { |
||
1652 |
BIO_printf(bio_err, "unable to rename %s to %s\n", |
||
1653 |
oattrpath, attrpath); |
||
1654 |
perror("reason"); |
||
1655 |
} |
||
1656 |
if (rename(dbfile, dbpath) < 0) { |
||
1657 |
BIO_printf(bio_err, "unable to rename %s to %s\n", |
||
1658 |
dbfile, dbpath); |
||
1659 |
perror("reason"); |
||
1660 |
} |
||
1661 |
if (rename(odbpath, dbfile) < 0) { |
||
1662 |
BIO_printf(bio_err, "unable to rename %s to %s\n", |
||
1663 |
odbpath, dbfile); |
||
1664 |
perror("reason"); |
||
1665 |
} |
||
1666 |
goto err; |
||
1667 |
} |
||
1668 |
48 |
return 1; |
|
1669 |
|||
1670 |
err: |
||
1671 |
return 0; |
||
1672 |
48 |
} |
|
1673 |
|||
1674 |
void |
||
1675 |
free_index(CA_DB *db) |
||
1676 |
{ |
||
1677 |
✓✓ | 192 |
if (db) { |
1678 |
✓✗ | 64 |
if (db->db) |
1679 |
64 |
TXT_DB_free(db->db); |
|
1680 |
64 |
free(db); |
|
1681 |
64 |
} |
|
1682 |
96 |
} |
|
1683 |
|||
1684 |
int |
||
1685 |
parse_yesno(const char *str, int def) |
||
1686 |
{ |
||
1687 |
int ret = def; |
||
1688 |
|||
1689 |
✓✗ | 112 |
if (str) { |
1690 |
✗✗✗✗ ✗✗✗✗ ✗✓✗ |
56 |
switch (*str) { |
1691 |
case 'f': /* false */ |
||
1692 |
case 'F': /* FALSE */ |
||
1693 |
case 'n': /* no */ |
||
1694 |
case 'N': /* NO */ |
||
1695 |
case '0': /* 0 */ |
||
1696 |
ret = 0; |
||
1697 |
break; |
||
1698 |
case 't': /* true */ |
||
1699 |
case 'T': /* TRUE */ |
||
1700 |
case 'y': /* yes */ |
||
1701 |
case 'Y': /* YES */ |
||
1702 |
case '1': /* 1 */ |
||
1703 |
ret = 1; |
||
1704 |
56 |
break; |
|
1705 |
default: |
||
1706 |
ret = def; |
||
1707 |
break; |
||
1708 |
} |
||
1709 |
} |
||
1710 |
56 |
return ret; |
|
1711 |
} |
||
1712 |
|||
1713 |
/* |
||
1714 |
* subject is expected to be in the format /type0=value0/type1=value1/type2=... |
||
1715 |
* where characters may be escaped by \ |
||
1716 |
*/ |
||
1717 |
X509_NAME * |
||
1718 |
parse_name(char *subject, long chtype, int multirdn) |
||
1719 |
{ |
||
1720 |
X509_NAME *name = NULL; |
||
1721 |
size_t buflen, max_ne; |
||
1722 |
char **ne_types, **ne_values; |
||
1723 |
char *buf, *bp, *sp; |
||
1724 |
int i, nid, ne_num = 0; |
||
1725 |
int *mval; |
||
1726 |
|||
1727 |
/* |
||
1728 |
* Buffer to copy the types and values into. Due to escaping the |
||
1729 |
* copy can only become shorter. |
||
1730 |
*/ |
||
1731 |
180 |
buflen = strlen(subject) + 1; |
|
1732 |
90 |
buf = malloc(buflen); |
|
1733 |
|||
1734 |
/* Maximum number of name elements. */ |
||
1735 |
90 |
max_ne = buflen / 2 + 1; |
|
1736 |
90 |
ne_types = reallocarray(NULL, max_ne, sizeof(char *)); |
|
1737 |
90 |
ne_values = reallocarray(NULL, max_ne, sizeof(char *)); |
|
1738 |
90 |
mval = reallocarray(NULL, max_ne, sizeof(int)); |
|
1739 |
|||
1740 |
✗✓ | 180 |
if (buf == NULL || ne_types == NULL || ne_values == NULL || |
1741 |
90 |
mval == NULL) { |
|
1742 |
BIO_printf(bio_err, "malloc error\n"); |
||
1743 |
goto error; |
||
1744 |
} |
||
1745 |
|||
1746 |
bp = buf; |
||
1747 |
sp = subject; |
||
1748 |
|||
1749 |
✗✓ | 90 |
if (*subject != '/') { |
1750 |
BIO_printf(bio_err, "Subject does not start with '/'.\n"); |
||
1751 |
goto error; |
||
1752 |
} |
||
1753 |
|||
1754 |
/* Skip leading '/'. */ |
||
1755 |
90 |
sp++; |
|
1756 |
|||
1757 |
/* No multivalued RDN by default. */ |
||
1758 |
90 |
mval[ne_num] = 0; |
|
1759 |
|||
1760 |
✓✓ | 900 |
while (*sp) { |
1761 |
/* Collect type. */ |
||
1762 |
360 |
ne_types[ne_num] = bp; |
|
1763 |
✓✗ | 1260 |
while (*sp) { |
1764 |
/* is there anything to escape in the type...? */ |
||
1765 |
✗✓ | 900 |
if (*sp == '\\') { |
1766 |
if (*++sp) |
||
1767 |
*bp++ = *sp++; |
||
1768 |
else { |
||
1769 |
BIO_printf(bio_err, "escape character " |
||
1770 |
"at end of string\n"); |
||
1771 |
goto error; |
||
1772 |
} |
||
1773 |
✓✓ | 900 |
} else if (*sp == '=') { |
1774 |
sp++; |
||
1775 |
360 |
*bp++ = '\0'; |
|
1776 |
360 |
break; |
|
1777 |
} else |
||
1778 |
540 |
*bp++ = *sp++; |
|
1779 |
} |
||
1780 |
✗✓ | 360 |
if (!*sp) { |
1781 |
BIO_printf(bio_err, "end of string encountered while " |
||
1782 |
"processing type of subject name element #%d\n", |
||
1783 |
ne_num); |
||
1784 |
goto error; |
||
1785 |
} |
||
1786 |
360 |
ne_values[ne_num] = bp; |
|
1787 |
✓✗ | 4240 |
while (*sp) { |
1788 |
✗✓ | 3880 |
if (*sp == '\\') { |
1789 |
if (*++sp) |
||
1790 |
*bp++ = *sp++; |
||
1791 |
else { |
||
1792 |
BIO_printf(bio_err, "escape character " |
||
1793 |
"at end of string\n"); |
||
1794 |
goto error; |
||
1795 |
} |
||
1796 |
✓✓ | 3880 |
} else if (*sp == '/') { |
1797 |
360 |
sp++; |
|
1798 |
/* no multivalued RDN by default */ |
||
1799 |
mval[ne_num + 1] = 0; |
||
1800 |
360 |
break; |
|
1801 |
✗✓ | 3520 |
} else if (*sp == '+' && multirdn) { |
1802 |
/* a not escaped + signals a multivalued RDN */ |
||
1803 |
sp++; |
||
1804 |
mval[ne_num + 1] = -1; |
||
1805 |
break; |
||
1806 |
} else |
||
1807 |
3520 |
*bp++ = *sp++; |
|
1808 |
} |
||
1809 |
720 |
*bp++ = '\0'; |
|
1810 |
360 |
ne_num++; |
|
1811 |
} |
||
1812 |
|||
1813 |
✓✗ | 90 |
if ((name = X509_NAME_new()) == NULL) |
1814 |
goto error; |
||
1815 |
|||
1816 |
✓✓ | 900 |
for (i = 0; i < ne_num; i++) { |
1817 |
✗✓ | 360 |
if ((nid = OBJ_txt2nid(ne_types[i])) == NID_undef) { |
1818 |
BIO_printf(bio_err, |
||
1819 |
"Subject Attribute %s has no known NID, skipped\n", |
||
1820 |
ne_types[i]); |
||
1821 |
continue; |
||
1822 |
} |
||
1823 |
✗✓ | 360 |
if (!*ne_values[i]) { |
1824 |
BIO_printf(bio_err, "No value provided for Subject " |
||
1825 |
"Attribute %s, skipped\n", ne_types[i]); |
||
1826 |
continue; |
||
1827 |
} |
||
1828 |
✓✗ | 720 |
if (!X509_NAME_add_entry_by_NID(name, nid, chtype, |
1829 |
360 |
(unsigned char *) ne_values[i], -1, -1, mval[i])) |
|
1830 |
goto error; |
||
1831 |
} |
||
1832 |
goto done; |
||
1833 |
|||
1834 |
error: |
||
1835 |
X509_NAME_free(name); |
||
1836 |
name = NULL; |
||
1837 |
|||
1838 |
done: |
||
1839 |
90 |
free(ne_values); |
|
1840 |
90 |
free(ne_types); |
|
1841 |
90 |
free(mval); |
|
1842 |
90 |
free(buf); |
|
1843 |
|||
1844 |
90 |
return name; |
|
1845 |
} |
||
1846 |
|||
1847 |
int |
||
1848 |
args_verify(char ***pargs, int *pargc, int *badarg, BIO *err, |
||
1849 |
X509_VERIFY_PARAM **pm) |
||
1850 |
{ |
||
1851 |
ASN1_OBJECT *otmp = NULL; |
||
1852 |
unsigned long flags = 0; |
||
1853 |
int i; |
||
1854 |
int purpose = 0, depth = -1; |
||
1855 |
240 |
char **oldargs = *pargs; |
|
1856 |
120 |
char *arg = **pargs, *argn = (*pargs)[1]; |
|
1857 |
time_t at_time = 0; |
||
1858 |
120 |
const char *errstr = NULL; |
|
1859 |
|||
1860 |
✗✓ | 120 |
if (!strcmp(arg, "-policy")) { |
1861 |
if (!argn) |
||
1862 |
*badarg = 1; |
||
1863 |
else { |
||
1864 |
otmp = OBJ_txt2obj(argn, 0); |
||
1865 |
if (!otmp) { |
||
1866 |
BIO_printf(err, "Invalid Policy \"%s\"\n", |
||
1867 |
argn); |
||
1868 |
*badarg = 1; |
||
1869 |
} |
||
1870 |
} |
||
1871 |
(*pargs)++; |
||
1872 |
✗✓ | 120 |
} else if (strcmp(arg, "-purpose") == 0) { |
1873 |
X509_PURPOSE *xptmp; |
||
1874 |
if (!argn) |
||
1875 |
*badarg = 1; |
||
1876 |
else { |
||
1877 |
i = X509_PURPOSE_get_by_sname(argn); |
||
1878 |
if (i < 0) { |
||
1879 |
BIO_printf(err, "unrecognized purpose\n"); |
||
1880 |
*badarg = 1; |
||
1881 |
} else { |
||
1882 |
xptmp = X509_PURPOSE_get0(i); |
||
1883 |
purpose = X509_PURPOSE_get_id(xptmp); |
||
1884 |
} |
||
1885 |
} |
||
1886 |
(*pargs)++; |
||
1887 |
✗✓ | 120 |
} else if (strcmp(arg, "-verify_depth") == 0) { |
1888 |
if (!argn) |
||
1889 |
*badarg = 1; |
||
1890 |
else { |
||
1891 |
depth = strtonum(argn, 1, INT_MAX, &errstr); |
||
1892 |
if (errstr) { |
||
1893 |
BIO_printf(err, "invalid depth %s: %s\n", |
||
1894 |
argn, errstr); |
||
1895 |
*badarg = 1; |
||
1896 |
} |
||
1897 |
} |
||
1898 |
(*pargs)++; |
||
1899 |
✗✓ | 120 |
} else if (strcmp(arg, "-attime") == 0) { |
1900 |
if (!argn) |
||
1901 |
*badarg = 1; |
||
1902 |
else { |
||
1903 |
long long timestamp; |
||
1904 |
/* |
||
1905 |
* interpret the -attime argument as seconds since |
||
1906 |
* Epoch |
||
1907 |
*/ |
||
1908 |
if (sscanf(argn, "%lli", ×tamp) != 1) { |
||
1909 |
BIO_printf(bio_err, |
||
1910 |
"Error parsing timestamp %s\n", |
||
1911 |
argn); |
||
1912 |
*badarg = 1; |
||
1913 |
} |
||
1914 |
/* XXX 2038 truncation */ |
||
1915 |
at_time = (time_t) timestamp; |
||
1916 |
} |
||
1917 |
(*pargs)++; |
||
1918 |
✗✓ | 120 |
} else if (!strcmp(arg, "-ignore_critical")) |
1919 |
flags |= X509_V_FLAG_IGNORE_CRITICAL; |
||
1920 |
✓✓ | 120 |
else if (!strcmp(arg, "-issuer_checks")) |
1921 |
8 |
flags |= X509_V_FLAG_CB_ISSUER_CHECK; |
|
1922 |
✓✓ | 112 |
else if (!strcmp(arg, "-crl_check")) |
1923 |
8 |
flags |= X509_V_FLAG_CRL_CHECK; |
|
1924 |
✗✓ | 104 |
else if (!strcmp(arg, "-crl_check_all")) |
1925 |
flags |= X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL; |
||
1926 |
✓✓ | 104 |
else if (!strcmp(arg, "-policy_check")) |
1927 |
8 |
flags |= X509_V_FLAG_POLICY_CHECK; |
|
1928 |
✗✓ | 96 |
else if (!strcmp(arg, "-explicit_policy")) |
1929 |
flags |= X509_V_FLAG_EXPLICIT_POLICY; |
||
1930 |
✗✓ | 96 |
else if (!strcmp(arg, "-inhibit_any")) |
1931 |
flags |= X509_V_FLAG_INHIBIT_ANY; |
||
1932 |
✗✓ | 96 |
else if (!strcmp(arg, "-inhibit_map")) |
1933 |
flags |= X509_V_FLAG_INHIBIT_MAP; |
||
1934 |
✗✓ | 96 |
else if (!strcmp(arg, "-x509_strict")) |
1935 |
flags |= X509_V_FLAG_X509_STRICT; |
||
1936 |
✗✓ | 96 |
else if (!strcmp(arg, "-extended_crl")) |
1937 |
flags |= X509_V_FLAG_EXTENDED_CRL_SUPPORT; |
||
1938 |
✗✓ | 96 |
else if (!strcmp(arg, "-use_deltas")) |
1939 |
flags |= X509_V_FLAG_USE_DELTAS; |
||
1940 |
✗✓ | 96 |
else if (!strcmp(arg, "-policy_print")) |
1941 |
flags |= X509_V_FLAG_NOTIFY_POLICY; |
||
1942 |
✗✓ | 96 |
else if (!strcmp(arg, "-check_ss_sig")) |
1943 |
flags |= X509_V_FLAG_CHECK_SS_SIGNATURE; |
||
1944 |
else |
||
1945 |
96 |
return 0; |
|
1946 |
|||
1947 |
✗✓ | 24 |
if (*badarg) { |
1948 |
if (*pm) |
||
1949 |
X509_VERIFY_PARAM_free(*pm); |
||
1950 |
*pm = NULL; |
||
1951 |
goto end; |
||
1952 |
} |
||
1953 |
✓✓✗✓ |
32 |
if (!*pm && !(*pm = X509_VERIFY_PARAM_new())) { |
1954 |
*badarg = 1; |
||
1955 |
goto end; |
||
1956 |
} |
||
1957 |
✗✓ | 24 |
if (otmp) { |
1958 |
X509_VERIFY_PARAM_add0_policy(*pm, otmp); |
||
1959 |
otmp = NULL; |
||
1960 |
} |
||
1961 |
✓✗ | 24 |
if (flags) |
1962 |
24 |
X509_VERIFY_PARAM_set_flags(*pm, flags); |
|
1963 |
|||
1964 |
✗✓ | 24 |
if (purpose) |
1965 |
X509_VERIFY_PARAM_set_purpose(*pm, purpose); |
||
1966 |
|||
1967 |
✗✓ | 24 |
if (depth >= 0) |
1968 |
X509_VERIFY_PARAM_set_depth(*pm, depth); |
||
1969 |
|||
1970 |
✗✓ | 24 |
if (at_time) |
1971 |
X509_VERIFY_PARAM_set_time(*pm, at_time); |
||
1972 |
|||
1973 |
end: |
||
1974 |
24 |
(*pargs)++; |
|
1975 |
|||
1976 |
✓✗ | 24 |
if (pargc) |
1977 |
24 |
*pargc -= *pargs - oldargs; |
|
1978 |
|||
1979 |
24 |
ASN1_OBJECT_free(otmp); |
|
1980 |
24 |
return 1; |
|
1981 |
120 |
} |
|
1982 |
|||
1983 |
/* Read whole contents of a BIO into an allocated memory buffer and |
||
1984 |
* return it. |
||
1985 |
*/ |
||
1986 |
|||
1987 |
int |
||
1988 |
bio_to_mem(unsigned char **out, int maxlen, BIO *in) |
||
1989 |
{ |
||
1990 |
BIO *mem; |
||
1991 |
int len, ret; |
||
1992 |
64 |
unsigned char tbuf[1024]; |
|
1993 |
|||
1994 |
32 |
mem = BIO_new(BIO_s_mem()); |
|
1995 |
✗✓ | 32 |
if (!mem) |
1996 |
return -1; |
||
1997 |
for (;;) { |
||
1998 |
✗✓ | 64 |
if ((maxlen != -1) && maxlen < 1024) |
1999 |
len = maxlen; |
||
2000 |
else |
||
2001 |
len = 1024; |
||
2002 |
64 |
len = BIO_read(in, tbuf, len); |
|
2003 |
✓✓ | 64 |
if (len <= 0) |
2004 |
break; |
||
2005 |
✗✓ | 32 |
if (BIO_write(mem, tbuf, len) != len) { |
2006 |
BIO_free(mem); |
||
2007 |
return -1; |
||
2008 |
} |
||
2009 |
32 |
maxlen -= len; |
|
2010 |
|||
2011 |
✓✗ | 32 |
if (maxlen == 0) |
2012 |
break; |
||
2013 |
} |
||
2014 |
32 |
ret = BIO_get_mem_data(mem, (char **) out); |
|
2015 |
32 |
BIO_set_flags(mem, BIO_FLAGS_MEM_RDONLY); |
|
2016 |
32 |
BIO_free(mem); |
|
2017 |
32 |
return ret; |
|
2018 |
32 |
} |
|
2019 |
|||
2020 |
int |
||
2021 |
pkey_ctrl_string(EVP_PKEY_CTX *ctx, char *value) |
||
2022 |
{ |
||
2023 |
int rv; |
||
2024 |
char *stmp, *vtmp = NULL; |
||
2025 |
|||
2026 |
✗✓ | 496 |
if (value == NULL) |
2027 |
return -1; |
||
2028 |
248 |
stmp = strdup(value); |
|
2029 |
✗✓ | 248 |
if (!stmp) |
2030 |
return -1; |
||
2031 |
248 |
vtmp = strchr(stmp, ':'); |
|
2032 |
✓✗ | 248 |
if (vtmp) { |
2033 |
248 |
*vtmp = 0; |
|
2034 |
248 |
vtmp++; |
|
2035 |
248 |
} |
|
2036 |
248 |
rv = EVP_PKEY_CTX_ctrl_str(ctx, stmp, vtmp); |
|
2037 |
248 |
free(stmp); |
|
2038 |
|||
2039 |
248 |
return rv; |
|
2040 |
248 |
} |
|
2041 |
|||
2042 |
static void |
||
2043 |
nodes_print(BIO *out, const char *name, STACK_OF(X509_POLICY_NODE) *nodes) |
||
2044 |
{ |
||
2045 |
X509_POLICY_NODE *node; |
||
2046 |
int i; |
||
2047 |
|||
2048 |
BIO_printf(out, "%s Policies:", name); |
||
2049 |
if (nodes) { |
||
2050 |
BIO_puts(out, "\n"); |
||
2051 |
for (i = 0; i < sk_X509_POLICY_NODE_num(nodes); i++) { |
||
2052 |
node = sk_X509_POLICY_NODE_value(nodes, i); |
||
2053 |
X509_POLICY_NODE_print(out, node, 2); |
||
2054 |
} |
||
2055 |
} else |
||
2056 |
BIO_puts(out, " <empty>\n"); |
||
2057 |
} |
||
2058 |
|||
2059 |
void |
||
2060 |
policies_print(BIO *out, X509_STORE_CTX *ctx) |
||
2061 |
{ |
||
2062 |
X509_POLICY_TREE *tree; |
||
2063 |
int explicit_policy; |
||
2064 |
int free_out = 0; |
||
2065 |
|||
2066 |
if (out == NULL) { |
||
2067 |
out = BIO_new_fp(stderr, BIO_NOCLOSE); |
||
2068 |
free_out = 1; |
||
2069 |
} |
||
2070 |
tree = X509_STORE_CTX_get0_policy_tree(ctx); |
||
2071 |
explicit_policy = X509_STORE_CTX_get_explicit_policy(ctx); |
||
2072 |
|||
2073 |
BIO_printf(out, "Require explicit Policy: %s\n", |
||
2074 |
explicit_policy ? "True" : "False"); |
||
2075 |
|||
2076 |
nodes_print(out, "Authority", X509_policy_tree_get0_policies(tree)); |
||
2077 |
nodes_print(out, "User", X509_policy_tree_get0_user_policies(tree)); |
||
2078 |
if (free_out) |
||
2079 |
BIO_free(out); |
||
2080 |
} |
||
2081 |
|||
2082 |
/* |
||
2083 |
* next_protos_parse parses a comma separated list of strings into a string |
||
2084 |
* in a format suitable for passing to SSL_CTX_set_next_protos_advertised. |
||
2085 |
* outlen: (output) set to the length of the resulting buffer on success. |
||
2086 |
* err: (maybe NULL) on failure, an error message line is written to this BIO. |
||
2087 |
* in: a NUL termianted string like "abc,def,ghi" |
||
2088 |
* |
||
2089 |
* returns: a malloced buffer or NULL on failure. |
||
2090 |
*/ |
||
2091 |
unsigned char * |
||
2092 |
next_protos_parse(unsigned short *outlen, const char *in) |
||
2093 |
{ |
||
2094 |
size_t len; |
||
2095 |
unsigned char *out; |
||
2096 |
size_t i, start = 0; |
||
2097 |
|||
2098 |
16 |
len = strlen(in); |
|
2099 |
✗✓ | 8 |
if (len >= 65535) |
2100 |
return NULL; |
||
2101 |
|||
2102 |
8 |
out = malloc(strlen(in) + 1); |
|
2103 |
✗✓ | 8 |
if (!out) |
2104 |
return NULL; |
||
2105 |
|||
2106 |
✓✓ | 272 |
for (i = 0; i <= len; ++i) { |
2107 |
✓✓✓✓ |
248 |
if (i == len || in[i] == ',') { |
2108 |
✗✓ | 16 |
if (i - start > 255) { |
2109 |
free(out); |
||
2110 |
return NULL; |
||
2111 |
} |
||
2112 |
16 |
out[start] = i - start; |
|
2113 |
16 |
start = i + 1; |
|
2114 |
16 |
} else |
|
2115 |
112 |
out[i + 1] = in[i]; |
|
2116 |
} |
||
2117 |
|||
2118 |
8 |
*outlen = len + 1; |
|
2119 |
8 |
return out; |
|
2120 |
8 |
} |
|
2121 |
|||
2122 |
int |
||
2123 |
app_isdir(const char *name) |
||
2124 |
{ |
||
2125 |
struct stat st; |
||
2126 |
|||
2127 |
if (stat(name, &st) == 0) |
||
2128 |
return S_ISDIR(st.st_mode); |
||
2129 |
return -1; |
||
2130 |
} |
||
2131 |
|||
2132 |
#define OPTION_WIDTH 18 |
||
2133 |
|||
2134 |
void |
||
2135 |
options_usage(struct option *opts) |
||
2136 |
{ |
||
2137 |
const char *p, *q; |
||
2138 |
416 |
char optstr[32]; |
|
2139 |
int i; |
||
2140 |
|||
2141 |
✓✓ | 4272 |
for (i = 0; opts[i].name != NULL; i++) { |
2142 |
✓✓ | 1928 |
if (opts[i].desc == NULL) |
2143 |
continue; |
||
2144 |
|||
2145 |
3680 |
snprintf(optstr, sizeof(optstr), "-%s %s", opts[i].name, |
|
2146 |
✓✓ | 4576 |
(opts[i].argname != NULL) ? opts[i].argname : ""); |
2147 |
1840 |
fprintf(stderr, " %-*s", OPTION_WIDTH, optstr); |
|
2148 |
✗✓ | 1840 |
if (strlen(optstr) > OPTION_WIDTH) |
2149 |
fprintf(stderr, "\n %-*s", OPTION_WIDTH, ""); |
||
2150 |
|||
2151 |
1840 |
p = opts[i].desc; |
|
2152 |
✓✓ | 3728 |
while ((q = strchr(p, '\n')) != NULL) { |
2153 |
24 |
fprintf(stderr, " %.*s", (int)(q - p), p); |
|
2154 |
24 |
fprintf(stderr, "\n %-*s", OPTION_WIDTH, ""); |
|
2155 |
24 |
p = q + 1; |
|
2156 |
} |
||
2157 |
1840 |
fprintf(stderr, " %s\n", p); |
|
2158 |
1840 |
} |
|
2159 |
208 |
} |
|
2160 |
|||
2161 |
int |
||
2162 |
options_parse(int argc, char **argv, struct option *opts, char **unnamed, |
||
2163 |
int *argsused) |
||
2164 |
{ |
||
2165 |
8846 |
const char *errstr; |
|
2166 |
struct option *opt; |
||
2167 |
long long val; |
||
2168 |
char *arg, *p; |
||
2169 |
4423 |
int fmt, used; |
|
2170 |
int ord = 0; |
||
2171 |
int i, j; |
||
2172 |
|||
2173 |
✓✓ | 4423 |
if (unnamed != NULL) |
2174 |
162 |
*unnamed = NULL; |
|
2175 |
|||
2176 |
✓✓ | 47938 |
for (i = 1; i < argc; i++) { |
2177 |
19778 |
p = arg = argv[i]; |
|
2178 |
|||
2179 |
/* Single unnamed argument (without leading hyphen). */ |
||
2180 |
✓✓ | 19778 |
if (*p++ != '-') { |
2181 |
✓✓ | 90 |
if (argsused != NULL) |
2182 |
goto done; |
||
2183 |
✓✗ | 66 |
if (unnamed == NULL) |
2184 |
goto unknown; |
||
2185 |
✓✗ | 66 |
if (*unnamed != NULL) |
2186 |
goto toomany; |
||
2187 |
66 |
*unnamed = arg; |
|
2188 |
66 |
continue; |
|
2189 |
} |
||
2190 |
|||
2191 |
/* End of named options (single hyphen). */ |
||
2192 |
✗✓ | 19688 |
if (*p == '\0') { |
2193 |
if (++i >= argc) |
||
2194 |
goto done; |
||
2195 |
if (argsused != NULL) |
||
2196 |
goto done; |
||
2197 |
if (unnamed != NULL && i == argc - 1) { |
||
2198 |
if (*unnamed != NULL) |
||
2199 |
goto toomany; |
||
2200 |
*unnamed = argv[i]; |
||
2201 |
continue; |
||
2202 |
} |
||
2203 |
goto unknown; |
||
2204 |
} |
||
2205 |
|||
2206 |
/* See if there is a matching option... */ |
||
2207 |
✓✓ | 376800 |
for (j = 0; opts[j].name != NULL; j++) { |
2208 |
✓✓ | 185776 |
if (strcmp(p, opts[j].name) == 0) |
2209 |
break; |
||
2210 |
} |
||
2211 |
opt = &opts[j]; |
||
2212 |
✓✓✓✓ |
22312 |
if (opt->name == NULL && opt->type == 0) |
2213 |
goto unknown; |
||
2214 |
|||
2215 |
✓✓✓✓ |
28560 |
if (opt->type == OPTION_ARG || |
2216 |
✓✓ | 10560 |
opt->type == OPTION_ARG_FORMAT || |
2217 |
✓✓ | 10552 |
opt->type == OPTION_ARG_FUNC || |
2218 |
✓✓ | 9064 |
opt->type == OPTION_ARG_INT || |
2219 |
✓✗ | 9048 |
opt->type == OPTION_ARG_LONG || |
2220 |
9048 |
opt->type == OPTION_ARG_TIME) { |
|
2221 |
✗✓ | 10472 |
if (++i >= argc) { |
2222 |
fprintf(stderr, "missing %s argument for -%s\n", |
||
2223 |
opt->argname, opt->name); |
||
2224 |
return (1); |
||
2225 |
} |
||
2226 |
} |
||
2227 |
|||
2228 |
✓✓✓✓ ✓✗✓✓ ✓✓✓✗ ✗✗✓ |
39024 |
switch (opt->type) { |
2229 |
case OPTION_ARG: |
||
2230 |
8952 |
*opt->opt.arg = argv[i]; |
|
2231 |
8952 |
break; |
|
2232 |
|||
2233 |
case OPTION_ARGV_FUNC: |
||
2234 |
✓✓ | 2448 |
if (opt->opt.argvfunc(argc - i, &argv[i], &used) != 0) |
2235 |
32 |
return (1); |
|
2236 |
2416 |
i += used - 1; |
|
2237 |
2416 |
break; |
|
2238 |
|||
2239 |
case OPTION_ARG_FORMAT: |
||
2240 |
8 |
fmt = str2fmt(argv[i]); |
|
2241 |
✗✓ | 8 |
if (fmt == FORMAT_UNDEF) { |
2242 |
fprintf(stderr, "unknown %s '%s' for -%s\n", |
||
2243 |
opt->argname, argv[i], opt->name); |
||
2244 |
return (1); |
||
2245 |
} |
||
2246 |
8 |
*opt->opt.value = fmt; |
|
2247 |
8 |
break; |
|
2248 |
|||
2249 |
case OPTION_ARG_FUNC: |
||
2250 |
✗✓ | 1488 |
if (opt->opt.argfunc(argv[i]) != 0) |
2251 |
return (1); |
||
2252 |
break; |
||
2253 |
|||
2254 |
case OPTION_ARG_INT: |
||
2255 |
16 |
val = strtonum(argv[i], 0, INT_MAX, &errstr); |
|
2256 |
✗✓ | 16 |
if (errstr != NULL) { |
2257 |
fprintf(stderr, "%s %s argument for -%s\n", |
||
2258 |
errstr, opt->argname, opt->name); |
||
2259 |
return (1); |
||
2260 |
} |
||
2261 |
16 |
*opt->opt.value = (int)val; |
|
2262 |
16 |
break; |
|
2263 |
|||
2264 |
case OPTION_ARG_LONG: |
||
2265 |
val = strtonum(argv[i], 0, LONG_MAX, &errstr); |
||
2266 |
if (errstr != NULL) { |
||
2267 |
fprintf(stderr, "%s %s argument for -%s\n", |
||
2268 |
errstr, opt->argname, opt->name); |
||
2269 |
return (1); |
||
2270 |
} |
||
2271 |
*opt->opt.lvalue = (long)val; |
||
2272 |
break; |
||
2273 |
|||
2274 |
case OPTION_ARG_TIME: |
||
2275 |
8 |
val = strtonum(argv[i], 0, LLONG_MAX, &errstr); |
|
2276 |
✗✓ | 8 |
if (errstr != NULL) { |
2277 |
fprintf(stderr, "%s %s argument for -%s\n", |
||
2278 |
errstr, opt->argname, opt->name); |
||
2279 |
return (1); |
||
2280 |
} |
||
2281 |
8 |
*opt->opt.tvalue = val; |
|
2282 |
8 |
break; |
|
2283 |
|||
2284 |
case OPTION_DISCARD: |
||
2285 |
break; |
||
2286 |
|||
2287 |
case OPTION_FUNC: |
||
2288 |
✗✓ | 8 |
if (opt->opt.func() != 0) |
2289 |
return (1); |
||
2290 |
break; |
||
2291 |
|||
2292 |
case OPTION_FLAG: |
||
2293 |
4104 |
*opt->opt.flag = 1; |
|
2294 |
4104 |
break; |
|
2295 |
|||
2296 |
case OPTION_FLAG_ORD: |
||
2297 |
8 |
*opt->opt.flag = ++ord; |
|
2298 |
8 |
break; |
|
2299 |
|||
2300 |
case OPTION_VALUE: |
||
2301 |
2472 |
*opt->opt.value = opt->value; |
|
2302 |
2472 |
break; |
|
2303 |
|||
2304 |
case OPTION_VALUE_AND: |
||
2305 |
*opt->opt.value &= opt->value; |
||
2306 |
break; |
||
2307 |
|||
2308 |
case OPTION_VALUE_OR: |
||
2309 |
*opt->opt.value |= opt->value; |
||
2310 |
break; |
||
2311 |
|||
2312 |
default: |
||
2313 |
fprintf(stderr, "option %s - unknown type %i\n", |
||
2314 |
opt->name, opt->type); |
||
2315 |
return (1); |
||
2316 |
} |
||
2317 |
} |
||
2318 |
|||
2319 |
done: |
||
2320 |
✓✓ | 4215 |
if (argsused != NULL) |
2321 |
48 |
*argsused = i; |
|
2322 |
|||
2323 |
4215 |
return (0); |
|
2324 |
|||
2325 |
toomany: |
||
2326 |
fprintf(stderr, "too many arguments\n"); |
||
2327 |
return (1); |
||
2328 |
|||
2329 |
unknown: |
||
2330 |
176 |
fprintf(stderr, "unknown option '%s'\n", arg); |
|
2331 |
176 |
return (1); |
|
2332 |
4423 |
} |
Generated by: GCOVR (Version 3.3) |