1*92d49c07Stb /* $OpenBSD: apps.c,v 1.70 2025/01/03 09:14:42 tb Exp $ */ 26b8b4364Sjsing /* 36b8b4364Sjsing * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> 46b8b4364Sjsing * 56b8b4364Sjsing * Permission to use, copy, modify, and distribute this software for any 66b8b4364Sjsing * purpose with or without fee is hereby granted, provided that the above 76b8b4364Sjsing * copyright notice and this permission notice appear in all copies. 86b8b4364Sjsing * 96b8b4364Sjsing * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 106b8b4364Sjsing * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 116b8b4364Sjsing * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 126b8b4364Sjsing * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 136b8b4364Sjsing * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 146b8b4364Sjsing * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 156b8b4364Sjsing * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 166b8b4364Sjsing */ 17dab3f910Sjsing /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 18dab3f910Sjsing * All rights reserved. 19dab3f910Sjsing * 20dab3f910Sjsing * This package is an SSL implementation written 21dab3f910Sjsing * by Eric Young (eay@cryptsoft.com). 22dab3f910Sjsing * The implementation was written so as to conform with Netscapes SSL. 23dab3f910Sjsing * 24dab3f910Sjsing * This library is free for commercial and non-commercial use as long as 25dab3f910Sjsing * the following conditions are aheared to. The following conditions 26dab3f910Sjsing * apply to all code found in this distribution, be it the RC4, RSA, 27dab3f910Sjsing * lhash, DES, etc., code; not just the SSL code. The SSL documentation 28dab3f910Sjsing * included with this distribution is covered by the same copyright terms 29dab3f910Sjsing * except that the holder is Tim Hudson (tjh@cryptsoft.com). 30dab3f910Sjsing * 31dab3f910Sjsing * Copyright remains Eric Young's, and as such any Copyright notices in 32dab3f910Sjsing * the code are not to be removed. 33dab3f910Sjsing * If this package is used in a product, Eric Young should be given attribution 34dab3f910Sjsing * as the author of the parts of the library used. 35dab3f910Sjsing * This can be in the form of a textual message at program startup or 36dab3f910Sjsing * in documentation (online or textual) provided with the package. 37dab3f910Sjsing * 38dab3f910Sjsing * Redistribution and use in source and binary forms, with or without 39dab3f910Sjsing * modification, are permitted provided that the following conditions 40dab3f910Sjsing * are met: 41dab3f910Sjsing * 1. Redistributions of source code must retain the copyright 42dab3f910Sjsing * notice, this list of conditions and the following disclaimer. 43dab3f910Sjsing * 2. Redistributions in binary form must reproduce the above copyright 44dab3f910Sjsing * notice, this list of conditions and the following disclaimer in the 45dab3f910Sjsing * documentation and/or other materials provided with the distribution. 46dab3f910Sjsing * 3. All advertising materials mentioning features or use of this software 47dab3f910Sjsing * must display the following acknowledgement: 48dab3f910Sjsing * "This product includes cryptographic software written by 49dab3f910Sjsing * Eric Young (eay@cryptsoft.com)" 50dab3f910Sjsing * The word 'cryptographic' can be left out if the rouines from the library 51dab3f910Sjsing * being used are not cryptographic related :-). 52dab3f910Sjsing * 4. If you include any Windows specific code (or a derivative thereof) from 53dab3f910Sjsing * the apps directory (application code) you must include an acknowledgement: 54dab3f910Sjsing * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 55dab3f910Sjsing * 56dab3f910Sjsing * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 57dab3f910Sjsing * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 58dab3f910Sjsing * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 59dab3f910Sjsing * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 60dab3f910Sjsing * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 61dab3f910Sjsing * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 62dab3f910Sjsing * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 63dab3f910Sjsing * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 64dab3f910Sjsing * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 65dab3f910Sjsing * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 66dab3f910Sjsing * SUCH DAMAGE. 67dab3f910Sjsing * 68dab3f910Sjsing * The licence and distribution terms for any publically available version or 69dab3f910Sjsing * derivative of this code cannot be changed. i.e. this code cannot simply be 70dab3f910Sjsing * copied and put under another distribution licence 71dab3f910Sjsing * [including the GNU Public Licence.] 72dab3f910Sjsing */ 73dab3f910Sjsing /* ==================================================================== 74dab3f910Sjsing * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. 75dab3f910Sjsing * 76dab3f910Sjsing * Redistribution and use in source and binary forms, with or without 77dab3f910Sjsing * modification, are permitted provided that the following conditions 78dab3f910Sjsing * are met: 79dab3f910Sjsing * 80dab3f910Sjsing * 1. Redistributions of source code must retain the above copyright 81dab3f910Sjsing * notice, this list of conditions and the following disclaimer. 82dab3f910Sjsing * 83dab3f910Sjsing * 2. Redistributions in binary form must reproduce the above copyright 84dab3f910Sjsing * notice, this list of conditions and the following disclaimer in 85dab3f910Sjsing * the documentation and/or other materials provided with the 86dab3f910Sjsing * distribution. 87dab3f910Sjsing * 88dab3f910Sjsing * 3. All advertising materials mentioning features or use of this 89dab3f910Sjsing * software must display the following acknowledgment: 90dab3f910Sjsing * "This product includes software developed by the OpenSSL Project 91dab3f910Sjsing * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 92dab3f910Sjsing * 93dab3f910Sjsing * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 94dab3f910Sjsing * endorse or promote products derived from this software without 95dab3f910Sjsing * prior written permission. For written permission, please contact 96dab3f910Sjsing * openssl-core@openssl.org. 97dab3f910Sjsing * 98dab3f910Sjsing * 5. Products derived from this software may not be called "OpenSSL" 99dab3f910Sjsing * nor may "OpenSSL" appear in their names without prior written 100dab3f910Sjsing * permission of the OpenSSL Project. 101dab3f910Sjsing * 102dab3f910Sjsing * 6. Redistributions of any form whatsoever must retain the following 103dab3f910Sjsing * acknowledgment: 104dab3f910Sjsing * "This product includes software developed by the OpenSSL Project 105dab3f910Sjsing * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 106dab3f910Sjsing * 107dab3f910Sjsing * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 108dab3f910Sjsing * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 109dab3f910Sjsing * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 110dab3f910Sjsing * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 111dab3f910Sjsing * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 112dab3f910Sjsing * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 113dab3f910Sjsing * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 114dab3f910Sjsing * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 115dab3f910Sjsing * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 116dab3f910Sjsing * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 117dab3f910Sjsing * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 118dab3f910Sjsing * OF THE POSSIBILITY OF SUCH DAMAGE. 119dab3f910Sjsing * ==================================================================== 120dab3f910Sjsing * 121dab3f910Sjsing * This product includes cryptographic software written by Eric Young 122dab3f910Sjsing * (eay@cryptsoft.com). This product includes software written by Tim 123dab3f910Sjsing * Hudson (tjh@cryptsoft.com). 124dab3f910Sjsing * 125dab3f910Sjsing */ 126dab3f910Sjsing 127dab3f910Sjsing #include <sys/types.h> 128dab3f910Sjsing #include <sys/stat.h> 129dab3f910Sjsing 130dab3f910Sjsing #include <ctype.h> 131dab3f910Sjsing #include <errno.h> 132dab3f910Sjsing #include <stdio.h> 133dab3f910Sjsing #include <stdlib.h> 134dab3f910Sjsing #include <limits.h> 135dab3f910Sjsing #include <string.h> 136dab3f910Sjsing #include <unistd.h> 137dab3f910Sjsing 138dab3f910Sjsing #include "apps.h" 139dab3f910Sjsing 140dab3f910Sjsing #include <openssl/bn.h> 141dab3f910Sjsing #include <openssl/err.h> 142dab3f910Sjsing #include <openssl/pem.h> 143dab3f910Sjsing #include <openssl/pkcs12.h> 14493dafd19Sjsing #include <openssl/rsa.h> 145dab3f910Sjsing #include <openssl/safestack.h> 14693dafd19Sjsing #include <openssl/ssl.h> 147dab3f910Sjsing #include <openssl/x509.h> 148dab3f910Sjsing #include <openssl/x509v3.h> 149dab3f910Sjsing 150dab3f910Sjsing typedef struct { 151dab3f910Sjsing const char *name; 152dab3f910Sjsing unsigned long flag; 153dab3f910Sjsing unsigned long mask; 154dab3f910Sjsing } NAME_EX_TBL; 155dab3f910Sjsing 1565827cb97Sbcook UI_METHOD *ui_method = NULL; 157dab3f910Sjsing 158dab3f910Sjsing static int set_table_opts(unsigned long *flags, const char *arg, 159dab3f910Sjsing const NAME_EX_TBL *in_tbl); 160dab3f910Sjsing static int set_multi_opts(unsigned long *flags, const char *arg, 161dab3f910Sjsing const NAME_EX_TBL *in_tbl); 162dab3f910Sjsing 163dab3f910Sjsing int 164dab3f910Sjsing str2fmt(char *s) 165dab3f910Sjsing { 166dab3f910Sjsing if (s == NULL) 167dab3f910Sjsing return FORMAT_UNDEF; 168dab3f910Sjsing if ((*s == 'D') || (*s == 'd')) 169dab3f910Sjsing return (FORMAT_ASN1); 170dab3f910Sjsing else if ((*s == 'T') || (*s == 't')) 171dab3f910Sjsing return (FORMAT_TEXT); 172dab3f910Sjsing else if ((*s == 'S') || (*s == 's')) 173dab3f910Sjsing return (FORMAT_SMIME); 174dab3f910Sjsing else if ((*s == 'M') || (*s == 'm')) 175dab3f910Sjsing return (FORMAT_MSBLOB); 176dab3f910Sjsing else if ((*s == '1') || 177dab3f910Sjsing (strcmp(s, "PKCS12") == 0) || (strcmp(s, "pkcs12") == 0) || 178dab3f910Sjsing (strcmp(s, "P12") == 0) || (strcmp(s, "p12") == 0)) 179dab3f910Sjsing return (FORMAT_PKCS12); 180dab3f910Sjsing else if ((*s == 'P') || (*s == 'p')) { 181dab3f910Sjsing if (s[1] == 'V' || s[1] == 'v') 182dab3f910Sjsing return FORMAT_PVK; 183dab3f910Sjsing else 184dab3f910Sjsing return (FORMAT_PEM); 185dab3f910Sjsing } else 186dab3f910Sjsing return (FORMAT_UNDEF); 187dab3f910Sjsing } 188dab3f910Sjsing 189dab3f910Sjsing void 190dab3f910Sjsing program_name(char *in, char *out, int size) 191dab3f910Sjsing { 192dab3f910Sjsing char *p; 193dab3f910Sjsing 194dab3f910Sjsing p = strrchr(in, '/'); 195dab3f910Sjsing if (p != NULL) 196dab3f910Sjsing p++; 197dab3f910Sjsing else 198dab3f910Sjsing p = in; 199dab3f910Sjsing strlcpy(out, p, size); 200dab3f910Sjsing } 201dab3f910Sjsing 202dab3f910Sjsing int 203dab3f910Sjsing dump_cert_text(BIO *out, X509 *x) 204dab3f910Sjsing { 205dab3f910Sjsing char *p; 206dab3f910Sjsing 207dab3f910Sjsing p = X509_NAME_oneline(X509_get_subject_name(x), NULL, 0); 208dab3f910Sjsing BIO_puts(out, "subject="); 209dab3f910Sjsing BIO_puts(out, p); 210dab3f910Sjsing free(p); 211dab3f910Sjsing 212dab3f910Sjsing p = X509_NAME_oneline(X509_get_issuer_name(x), NULL, 0); 213dab3f910Sjsing BIO_puts(out, "\nissuer="); 214dab3f910Sjsing BIO_puts(out, p); 215dab3f910Sjsing BIO_puts(out, "\n"); 216dab3f910Sjsing free(p); 217dab3f910Sjsing 218dab3f910Sjsing return 0; 219dab3f910Sjsing } 220dab3f910Sjsing 2215827cb97Sbcook int 222dab3f910Sjsing ui_open(UI *ui) 223dab3f910Sjsing { 224dab3f910Sjsing return UI_method_get_opener(UI_OpenSSL()) (ui); 225dab3f910Sjsing } 226dab3f910Sjsing 2275827cb97Sbcook int 228dab3f910Sjsing ui_read(UI *ui, UI_STRING *uis) 229dab3f910Sjsing { 2305827cb97Sbcook const char *password; 2315827cb97Sbcook int string_type; 2325827cb97Sbcook 233dab3f910Sjsing if (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD && 234dab3f910Sjsing UI_get0_user_data(ui)) { 2355827cb97Sbcook string_type = UI_get_string_type(uis); 2365827cb97Sbcook if (string_type == UIT_PROMPT || string_type == UIT_VERIFY) { 2375827cb97Sbcook password = 238dab3f910Sjsing ((PW_CB_DATA *)UI_get0_user_data(ui))->password; 239dab3f910Sjsing if (password && password[0] != '\0') { 240dab3f910Sjsing UI_set_result(ui, uis, password); 241dab3f910Sjsing return 1; 242dab3f910Sjsing } 243dab3f910Sjsing } 244dab3f910Sjsing } 245dab3f910Sjsing return UI_method_get_reader(UI_OpenSSL()) (ui, uis); 246dab3f910Sjsing } 247dab3f910Sjsing 2485827cb97Sbcook int 249dab3f910Sjsing ui_write(UI *ui, UI_STRING *uis) 250dab3f910Sjsing { 2515827cb97Sbcook const char *password; 2525827cb97Sbcook int string_type; 2535827cb97Sbcook 254dab3f910Sjsing if (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD && 255dab3f910Sjsing UI_get0_user_data(ui)) { 2565827cb97Sbcook string_type = UI_get_string_type(uis); 2575827cb97Sbcook if (string_type == UIT_PROMPT || string_type == UIT_VERIFY) { 2585827cb97Sbcook password = 259dab3f910Sjsing ((PW_CB_DATA *)UI_get0_user_data(ui))->password; 260dab3f910Sjsing if (password && password[0] != '\0') 261dab3f910Sjsing return 1; 262dab3f910Sjsing } 263dab3f910Sjsing } 264dab3f910Sjsing return UI_method_get_writer(UI_OpenSSL()) (ui, uis); 265dab3f910Sjsing } 266dab3f910Sjsing 2675827cb97Sbcook int 268dab3f910Sjsing ui_close(UI *ui) 269dab3f910Sjsing { 270dab3f910Sjsing return UI_method_get_closer(UI_OpenSSL()) (ui); 271dab3f910Sjsing } 272dab3f910Sjsing 273dab3f910Sjsing int 274dab3f910Sjsing password_callback(char *buf, int bufsiz, int verify, void *arg) 275dab3f910Sjsing { 276dab3f910Sjsing PW_CB_DATA *cb_tmp = arg; 277dab3f910Sjsing UI *ui = NULL; 278dab3f910Sjsing int res = 0; 279dab3f910Sjsing const char *prompt_info = NULL; 280dab3f910Sjsing const char *password = NULL; 281dab3f910Sjsing PW_CB_DATA *cb_data = (PW_CB_DATA *) cb_tmp; 282dab3f910Sjsing 283dab3f910Sjsing if (cb_data) { 284dab3f910Sjsing if (cb_data->password) 285dab3f910Sjsing password = cb_data->password; 286dab3f910Sjsing if (cb_data->prompt_info) 287dab3f910Sjsing prompt_info = cb_data->prompt_info; 288dab3f910Sjsing } 289dab3f910Sjsing if (password) { 290dab3f910Sjsing res = strlen(password); 291dab3f910Sjsing if (res > bufsiz) 292dab3f910Sjsing res = bufsiz; 293dab3f910Sjsing memcpy(buf, password, res); 294dab3f910Sjsing return res; 295dab3f910Sjsing } 296dab3f910Sjsing ui = UI_new_method(ui_method); 297dab3f910Sjsing if (ui) { 298dab3f910Sjsing int ok = 0; 299dab3f910Sjsing char *buff = NULL; 300dab3f910Sjsing int ui_flags = 0; 301dab3f910Sjsing char *prompt = NULL; 302dab3f910Sjsing 303dab3f910Sjsing prompt = UI_construct_prompt(ui, "pass phrase", prompt_info); 304dab3f910Sjsing 305dab3f910Sjsing ui_flags |= UI_INPUT_FLAG_DEFAULT_PWD; 306dab3f910Sjsing UI_ctrl(ui, UI_CTRL_PRINT_ERRORS, 1, 0, 0); 307dab3f910Sjsing 308dab3f910Sjsing if (ok >= 0) 309dab3f910Sjsing ok = UI_add_input_string(ui, prompt, ui_flags, buf, 310dab3f910Sjsing PW_MIN_LENGTH, bufsiz - 1); 311dab3f910Sjsing if (ok >= 0 && verify) { 312dab3f910Sjsing buff = malloc(bufsiz); 313dab3f910Sjsing ok = UI_add_verify_string(ui, prompt, ui_flags, buff, 314dab3f910Sjsing PW_MIN_LENGTH, bufsiz - 1, buf); 315dab3f910Sjsing } 316dab3f910Sjsing if (ok >= 0) 317dab3f910Sjsing do { 318dab3f910Sjsing ok = UI_process(ui); 319dab3f910Sjsing } while (ok < 0 && 320dab3f910Sjsing UI_ctrl(ui, UI_CTRL_IS_REDOABLE, 0, 0, 0)); 321dab3f910Sjsing 322cf4db30dSderaadt freezero(buff, (unsigned int) bufsiz); 323dab3f910Sjsing if (ok >= 0) 324dab3f910Sjsing res = strlen(buf); 325dab3f910Sjsing if (ok == -1) { 326dab3f910Sjsing BIO_printf(bio_err, "User interface error\n"); 327dab3f910Sjsing ERR_print_errors(bio_err); 3289fd20351Sjsing explicit_bzero(buf, (unsigned int) bufsiz); 329dab3f910Sjsing res = 0; 330dab3f910Sjsing } 331dab3f910Sjsing if (ok == -2) { 332dab3f910Sjsing BIO_printf(bio_err, "aborted!\n"); 3339fd20351Sjsing explicit_bzero(buf, (unsigned int) bufsiz); 334dab3f910Sjsing res = 0; 335dab3f910Sjsing } 336dab3f910Sjsing UI_free(ui); 337dab3f910Sjsing free(prompt); 338dab3f910Sjsing } 339dab3f910Sjsing return res; 340dab3f910Sjsing } 341dab3f910Sjsing 342dab3f910Sjsing static char *app_get_pass(BIO *err, char *arg, int keepbio); 343dab3f910Sjsing 344dab3f910Sjsing int 345dab3f910Sjsing app_passwd(BIO *err, char *arg1, char *arg2, char **pass1, char **pass2) 346dab3f910Sjsing { 347dab3f910Sjsing int same; 348dab3f910Sjsing 349dab3f910Sjsing if (!arg2 || !arg1 || strcmp(arg1, arg2)) 350dab3f910Sjsing same = 0; 351dab3f910Sjsing else 352dab3f910Sjsing same = 1; 353dab3f910Sjsing if (arg1) { 354dab3f910Sjsing *pass1 = app_get_pass(err, arg1, same); 355dab3f910Sjsing if (!*pass1) 356dab3f910Sjsing return 0; 357dab3f910Sjsing } else if (pass1) 358dab3f910Sjsing *pass1 = NULL; 359dab3f910Sjsing if (arg2) { 360dab3f910Sjsing *pass2 = app_get_pass(err, arg2, same ? 2 : 0); 361dab3f910Sjsing if (!*pass2) 362dab3f910Sjsing return 0; 363dab3f910Sjsing } else if (pass2) 364dab3f910Sjsing *pass2 = NULL; 365dab3f910Sjsing return 1; 366dab3f910Sjsing } 367dab3f910Sjsing 368dab3f910Sjsing static char * 369dab3f910Sjsing app_get_pass(BIO *err, char *arg, int keepbio) 370dab3f910Sjsing { 371dab3f910Sjsing char *tmp, tpass[APP_PASS_LEN]; 372dab3f910Sjsing static BIO *pwdbio = NULL; 373dab3f910Sjsing const char *errstr = NULL; 374dab3f910Sjsing int i; 375dab3f910Sjsing 376dab3f910Sjsing if (!strncmp(arg, "pass:", 5)) 377dab3f910Sjsing return strdup(arg + 5); 378dab3f910Sjsing if (!strncmp(arg, "env:", 4)) { 379dab3f910Sjsing tmp = getenv(arg + 4); 380dab3f910Sjsing if (!tmp) { 381dab3f910Sjsing BIO_printf(err, "Can't read environment variable %s\n", 382dab3f910Sjsing arg + 4); 383dab3f910Sjsing return NULL; 384dab3f910Sjsing } 385dab3f910Sjsing return strdup(tmp); 386dab3f910Sjsing } 387dab3f910Sjsing if (!keepbio || !pwdbio) { 388dab3f910Sjsing if (!strncmp(arg, "file:", 5)) { 389dab3f910Sjsing pwdbio = BIO_new_file(arg + 5, "r"); 390dab3f910Sjsing if (!pwdbio) { 391dab3f910Sjsing BIO_printf(err, "Can't open file %s\n", 392dab3f910Sjsing arg + 5); 393dab3f910Sjsing return NULL; 394dab3f910Sjsing } 395dab3f910Sjsing } else if (!strncmp(arg, "fd:", 3)) { 396dab3f910Sjsing BIO *btmp; 397dab3f910Sjsing i = strtonum(arg + 3, 0, INT_MAX, &errstr); 398dab3f910Sjsing if (errstr) { 399dab3f910Sjsing BIO_printf(err, 400dab3f910Sjsing "Invalid file descriptor %s: %s\n", 401dab3f910Sjsing arg, errstr); 402dab3f910Sjsing return NULL; 403dab3f910Sjsing } 404dab3f910Sjsing pwdbio = BIO_new_fd(i, BIO_NOCLOSE); 405dab3f910Sjsing if (!pwdbio) { 406dab3f910Sjsing BIO_printf(err, 407dab3f910Sjsing "Can't access file descriptor %s\n", 408dab3f910Sjsing arg + 3); 409dab3f910Sjsing return NULL; 410dab3f910Sjsing } 411dab3f910Sjsing /* 412dab3f910Sjsing * Can't do BIO_gets on an fd BIO so add a buffering 413dab3f910Sjsing * BIO 414dab3f910Sjsing */ 415dab3f910Sjsing btmp = BIO_new(BIO_f_buffer()); 416dab3f910Sjsing pwdbio = BIO_push(btmp, pwdbio); 417dab3f910Sjsing } else if (!strcmp(arg, "stdin")) { 418dab3f910Sjsing pwdbio = BIO_new_fp(stdin, BIO_NOCLOSE); 419dab3f910Sjsing if (!pwdbio) { 420dab3f910Sjsing BIO_printf(err, "Can't open BIO for stdin\n"); 421dab3f910Sjsing return NULL; 422dab3f910Sjsing } 423dab3f910Sjsing } else { 424dab3f910Sjsing BIO_printf(err, "Invalid password argument \"%s\"\n", 425dab3f910Sjsing arg); 426dab3f910Sjsing return NULL; 427dab3f910Sjsing } 428dab3f910Sjsing } 429dab3f910Sjsing i = BIO_gets(pwdbio, tpass, APP_PASS_LEN); 430dab3f910Sjsing if (keepbio != 1) { 431dab3f910Sjsing BIO_free_all(pwdbio); 432dab3f910Sjsing pwdbio = NULL; 433dab3f910Sjsing } 434dab3f910Sjsing if (i <= 0) { 435dab3f910Sjsing BIO_printf(err, "Error reading password from BIO\n"); 436dab3f910Sjsing return NULL; 437dab3f910Sjsing } 438dab3f910Sjsing tmp = strchr(tpass, '\n'); 439dab3f910Sjsing if (tmp) 440dab3f910Sjsing *tmp = 0; 441dab3f910Sjsing return strdup(tpass); 442dab3f910Sjsing } 443dab3f910Sjsing 444dab3f910Sjsing int 445dab3f910Sjsing add_oid_section(BIO *err, CONF *conf) 446dab3f910Sjsing { 447dab3f910Sjsing char *p; 448dab3f910Sjsing STACK_OF(CONF_VALUE) *sktmp; 449dab3f910Sjsing CONF_VALUE *cnf; 450dab3f910Sjsing int i; 451dab3f910Sjsing 452dab3f910Sjsing if (!(p = NCONF_get_string(conf, NULL, "oid_section"))) { 453dab3f910Sjsing ERR_clear_error(); 454dab3f910Sjsing return 1; 455dab3f910Sjsing } 456dab3f910Sjsing if (!(sktmp = NCONF_get_section(conf, p))) { 457dab3f910Sjsing BIO_printf(err, "problem loading oid section %s\n", p); 458dab3f910Sjsing return 0; 459dab3f910Sjsing } 460dab3f910Sjsing for (i = 0; i < sk_CONF_VALUE_num(sktmp); i++) { 461dab3f910Sjsing cnf = sk_CONF_VALUE_value(sktmp, i); 462dab3f910Sjsing if (OBJ_create(cnf->value, cnf->name, cnf->name) == NID_undef) { 463dab3f910Sjsing BIO_printf(err, "problem creating object %s=%s\n", 464dab3f910Sjsing cnf->name, cnf->value); 465dab3f910Sjsing return 0; 466dab3f910Sjsing } 467dab3f910Sjsing } 468dab3f910Sjsing return 1; 469dab3f910Sjsing } 470dab3f910Sjsing 471dab3f910Sjsing static int 472dab3f910Sjsing load_pkcs12(BIO *err, BIO *in, const char *desc, pem_password_cb *pem_cb, 473dab3f910Sjsing void *cb_data, EVP_PKEY **pkey, X509 **cert, STACK_OF(X509) **ca) 474dab3f910Sjsing { 475dab3f910Sjsing const char *pass; 476dab3f910Sjsing char tpass[PEM_BUFSIZE]; 477dab3f910Sjsing int len, ret = 0; 478dab3f910Sjsing PKCS12 *p12; 479dab3f910Sjsing 480dab3f910Sjsing p12 = d2i_PKCS12_bio(in, NULL); 481dab3f910Sjsing if (p12 == NULL) { 482dab3f910Sjsing BIO_printf(err, "Error loading PKCS12 file for %s\n", desc); 483dab3f910Sjsing goto die; 484dab3f910Sjsing } 485dab3f910Sjsing /* See if an empty password will do */ 486dab3f910Sjsing if (PKCS12_verify_mac(p12, "", 0) || PKCS12_verify_mac(p12, NULL, 0)) 487dab3f910Sjsing pass = ""; 488dab3f910Sjsing else { 489dab3f910Sjsing if (!pem_cb) 490dab3f910Sjsing pem_cb = password_callback; 491dab3f910Sjsing len = pem_cb(tpass, PEM_BUFSIZE, 0, cb_data); 492dab3f910Sjsing if (len < 0) { 493dab3f910Sjsing BIO_printf(err, "Passpharse callback error for %s\n", 494dab3f910Sjsing desc); 495dab3f910Sjsing goto die; 496dab3f910Sjsing } 497dab3f910Sjsing if (len < PEM_BUFSIZE) 498dab3f910Sjsing tpass[len] = 0; 499dab3f910Sjsing if (!PKCS12_verify_mac(p12, tpass, len)) { 500dab3f910Sjsing BIO_printf(err, 501dab3f910Sjsing "Mac verify error (wrong password?) in PKCS12 file for %s\n", desc); 502dab3f910Sjsing goto die; 503dab3f910Sjsing } 504dab3f910Sjsing pass = tpass; 505dab3f910Sjsing } 506dab3f910Sjsing ret = PKCS12_parse(p12, pass, pkey, cert, ca); 507dab3f910Sjsing 508dab3f910Sjsing die: 509dab3f910Sjsing PKCS12_free(p12); 510dab3f910Sjsing return ret; 511dab3f910Sjsing } 512dab3f910Sjsing 513dab3f910Sjsing X509 * 5145284dfeaSbcook load_cert(BIO *err, const char *file, int format, const char *pass, 515dab3f910Sjsing const char *cert_descrip) 516dab3f910Sjsing { 517dab3f910Sjsing X509 *x = NULL; 518dab3f910Sjsing BIO *cert; 519dab3f910Sjsing 520dab3f910Sjsing if ((cert = BIO_new(BIO_s_file())) == NULL) { 521dab3f910Sjsing ERR_print_errors(err); 522dab3f910Sjsing goto end; 523dab3f910Sjsing } 524dab3f910Sjsing if (file == NULL) { 525dab3f910Sjsing setvbuf(stdin, NULL, _IONBF, 0); 526dab3f910Sjsing BIO_set_fp(cert, stdin, BIO_NOCLOSE); 527dab3f910Sjsing } else { 528dab3f910Sjsing if (BIO_read_filename(cert, file) <= 0) { 529dab3f910Sjsing BIO_printf(err, "Error opening %s %s\n", 530dab3f910Sjsing cert_descrip, file); 531dab3f910Sjsing ERR_print_errors(err); 532dab3f910Sjsing goto end; 533dab3f910Sjsing } 534dab3f910Sjsing } 535dab3f910Sjsing 536dab3f910Sjsing if (format == FORMAT_ASN1) 537dab3f910Sjsing x = d2i_X509_bio(cert, NULL); 538b1044e52Stb else if (format == FORMAT_PEM) 539dab3f910Sjsing x = PEM_read_bio_X509_AUX(cert, NULL, password_callback, NULL); 540dab3f910Sjsing else if (format == FORMAT_PKCS12) { 541dab3f910Sjsing if (!load_pkcs12(err, cert, cert_descrip, NULL, NULL, 542dab3f910Sjsing NULL, &x, NULL)) 543dab3f910Sjsing goto end; 544dab3f910Sjsing } else { 545dab3f910Sjsing BIO_printf(err, "bad input format specified for %s\n", 546dab3f910Sjsing cert_descrip); 547dab3f910Sjsing goto end; 548dab3f910Sjsing } 549dab3f910Sjsing 550dab3f910Sjsing end: 551dab3f910Sjsing if (x == NULL) { 552dab3f910Sjsing BIO_printf(err, "unable to load certificate\n"); 553dab3f910Sjsing ERR_print_errors(err); 554dab3f910Sjsing } 555dab3f910Sjsing BIO_free(cert); 556dab3f910Sjsing return (x); 557dab3f910Sjsing } 558dab3f910Sjsing 559dab3f910Sjsing EVP_PKEY * 560dab3f910Sjsing load_key(BIO *err, const char *file, int format, int maybe_stdin, 5615284dfeaSbcook const char *pass, const char *key_descrip) 562dab3f910Sjsing { 563dab3f910Sjsing BIO *key = NULL; 564dab3f910Sjsing EVP_PKEY *pkey = NULL; 565dab3f910Sjsing PW_CB_DATA cb_data; 566dab3f910Sjsing 567dab3f910Sjsing cb_data.password = pass; 568dab3f910Sjsing cb_data.prompt_info = file; 569dab3f910Sjsing 5705284dfeaSbcook if (file == NULL && (!maybe_stdin)) { 571dab3f910Sjsing BIO_printf(err, "no keyfile specified\n"); 572dab3f910Sjsing goto end; 573dab3f910Sjsing } 574dab3f910Sjsing key = BIO_new(BIO_s_file()); 575dab3f910Sjsing if (key == NULL) { 576dab3f910Sjsing ERR_print_errors(err); 577dab3f910Sjsing goto end; 578dab3f910Sjsing } 579dab3f910Sjsing if (file == NULL && maybe_stdin) { 580dab3f910Sjsing setvbuf(stdin, NULL, _IONBF, 0); 581dab3f910Sjsing BIO_set_fp(key, stdin, BIO_NOCLOSE); 582dab3f910Sjsing } else if (BIO_read_filename(key, file) <= 0) { 583dab3f910Sjsing BIO_printf(err, "Error opening %s %s\n", 584dab3f910Sjsing key_descrip, file); 585dab3f910Sjsing ERR_print_errors(err); 586dab3f910Sjsing goto end; 587dab3f910Sjsing } 588dab3f910Sjsing if (format == FORMAT_ASN1) { 589dab3f910Sjsing pkey = d2i_PrivateKey_bio(key, NULL); 590dab3f910Sjsing } else if (format == FORMAT_PEM) { 591dab3f910Sjsing pkey = PEM_read_bio_PrivateKey(key, NULL, password_callback, &cb_data); 592dab3f910Sjsing } 593dab3f910Sjsing else if (format == FORMAT_PKCS12) { 594dab3f910Sjsing if (!load_pkcs12(err, key, key_descrip, password_callback, &cb_data, 595dab3f910Sjsing &pkey, NULL, NULL)) 596dab3f910Sjsing goto end; 597dab3f910Sjsing } 598dab3f910Sjsing #if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DSA) && !defined (OPENSSL_NO_RC4) 599dab3f910Sjsing else if (format == FORMAT_MSBLOB) 600dab3f910Sjsing pkey = b2i_PrivateKey_bio(key); 601dab3f910Sjsing else if (format == FORMAT_PVK) 602dab3f910Sjsing pkey = b2i_PVK_bio(key, password_callback, 603dab3f910Sjsing &cb_data); 604dab3f910Sjsing #endif 605dab3f910Sjsing else { 606dab3f910Sjsing BIO_printf(err, "bad input format specified for key file\n"); 607dab3f910Sjsing goto end; 608dab3f910Sjsing } 609dab3f910Sjsing end: 610dab3f910Sjsing BIO_free(key); 611dab3f910Sjsing if (pkey == NULL) { 612dab3f910Sjsing BIO_printf(err, "unable to load %s\n", key_descrip); 613dab3f910Sjsing ERR_print_errors(err); 614dab3f910Sjsing } 615dab3f910Sjsing return (pkey); 616dab3f910Sjsing } 617dab3f910Sjsing 618dab3f910Sjsing EVP_PKEY * 619dab3f910Sjsing load_pubkey(BIO *err, const char *file, int format, int maybe_stdin, 6205284dfeaSbcook const char *pass, const char *key_descrip) 621dab3f910Sjsing { 622dab3f910Sjsing BIO *key = NULL; 623dab3f910Sjsing EVP_PKEY *pkey = NULL; 624dab3f910Sjsing PW_CB_DATA cb_data; 625dab3f910Sjsing 626dab3f910Sjsing cb_data.password = pass; 627dab3f910Sjsing cb_data.prompt_info = file; 628dab3f910Sjsing 6295284dfeaSbcook if (file == NULL && !maybe_stdin) { 630dab3f910Sjsing BIO_printf(err, "no keyfile specified\n"); 631dab3f910Sjsing goto end; 632dab3f910Sjsing } 633dab3f910Sjsing key = BIO_new(BIO_s_file()); 634dab3f910Sjsing if (key == NULL) { 635dab3f910Sjsing ERR_print_errors(err); 636dab3f910Sjsing goto end; 637dab3f910Sjsing } 638dab3f910Sjsing if (file == NULL && maybe_stdin) { 639dab3f910Sjsing setvbuf(stdin, NULL, _IONBF, 0); 640dab3f910Sjsing BIO_set_fp(key, stdin, BIO_NOCLOSE); 641dab3f910Sjsing } else if (BIO_read_filename(key, file) <= 0) { 642dab3f910Sjsing BIO_printf(err, "Error opening %s %s\n", key_descrip, file); 643dab3f910Sjsing ERR_print_errors(err); 644dab3f910Sjsing goto end; 645dab3f910Sjsing } 646dab3f910Sjsing if (format == FORMAT_ASN1) { 647dab3f910Sjsing pkey = d2i_PUBKEY_bio(key, NULL); 648dab3f910Sjsing } 649dab3f910Sjsing else if (format == FORMAT_ASN1RSA) { 650dab3f910Sjsing RSA *rsa; 651dab3f910Sjsing rsa = d2i_RSAPublicKey_bio(key, NULL); 652dab3f910Sjsing if (rsa) { 653dab3f910Sjsing pkey = EVP_PKEY_new(); 654dab3f910Sjsing if (pkey) 655dab3f910Sjsing EVP_PKEY_set1_RSA(pkey, rsa); 656dab3f910Sjsing RSA_free(rsa); 657dab3f910Sjsing } else 658dab3f910Sjsing pkey = NULL; 659dab3f910Sjsing } else if (format == FORMAT_PEMRSA) { 660dab3f910Sjsing RSA *rsa; 661dab3f910Sjsing rsa = PEM_read_bio_RSAPublicKey(key, NULL, password_callback, &cb_data); 662dab3f910Sjsing if (rsa) { 663dab3f910Sjsing pkey = EVP_PKEY_new(); 664dab3f910Sjsing if (pkey) 665dab3f910Sjsing EVP_PKEY_set1_RSA(pkey, rsa); 666dab3f910Sjsing RSA_free(rsa); 667dab3f910Sjsing } else 668dab3f910Sjsing pkey = NULL; 669dab3f910Sjsing } 670dab3f910Sjsing else if (format == FORMAT_PEM) { 671dab3f910Sjsing pkey = PEM_read_bio_PUBKEY(key, NULL, password_callback, &cb_data); 672dab3f910Sjsing } 673dab3f910Sjsing #if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DSA) 674dab3f910Sjsing else if (format == FORMAT_MSBLOB) 675dab3f910Sjsing pkey = b2i_PublicKey_bio(key); 676dab3f910Sjsing #endif 677dab3f910Sjsing else { 678dab3f910Sjsing BIO_printf(err, "bad input format specified for key file\n"); 679dab3f910Sjsing goto end; 680dab3f910Sjsing } 681dab3f910Sjsing 682dab3f910Sjsing end: 683dab3f910Sjsing BIO_free(key); 684dab3f910Sjsing if (pkey == NULL) 685dab3f910Sjsing BIO_printf(err, "unable to load %s\n", key_descrip); 686dab3f910Sjsing return (pkey); 687dab3f910Sjsing } 688dab3f910Sjsing 689dab3f910Sjsing static int 690dab3f910Sjsing load_certs_crls(BIO *err, const char *file, int format, const char *pass, 6915284dfeaSbcook const char *desc, STACK_OF(X509) **pcerts, 692dab3f910Sjsing STACK_OF(X509_CRL) **pcrls) 693dab3f910Sjsing { 694dab3f910Sjsing int i; 695dab3f910Sjsing BIO *bio; 696dab3f910Sjsing STACK_OF(X509_INFO) *xis = NULL; 697dab3f910Sjsing X509_INFO *xi; 698dab3f910Sjsing PW_CB_DATA cb_data; 699dab3f910Sjsing int rv = 0; 700dab3f910Sjsing 701dab3f910Sjsing cb_data.password = pass; 702dab3f910Sjsing cb_data.prompt_info = file; 703dab3f910Sjsing 704dab3f910Sjsing if (format != FORMAT_PEM) { 705dab3f910Sjsing BIO_printf(err, "bad input format specified for %s\n", desc); 706dab3f910Sjsing return 0; 707dab3f910Sjsing } 708dab3f910Sjsing if (file == NULL) 709dab3f910Sjsing bio = BIO_new_fp(stdin, BIO_NOCLOSE); 710dab3f910Sjsing else 711dab3f910Sjsing bio = BIO_new_file(file, "r"); 712dab3f910Sjsing 713dab3f910Sjsing if (bio == NULL) { 714dab3f910Sjsing BIO_printf(err, "Error opening %s %s\n", 715dab3f910Sjsing desc, file ? file : "stdin"); 716dab3f910Sjsing ERR_print_errors(err); 717dab3f910Sjsing return 0; 718dab3f910Sjsing } 719dab3f910Sjsing xis = PEM_X509_INFO_read_bio(bio, NULL, password_callback, &cb_data); 720dab3f910Sjsing 721dab3f910Sjsing BIO_free(bio); 722dab3f910Sjsing 723dab3f910Sjsing if (pcerts) { 724dab3f910Sjsing *pcerts = sk_X509_new_null(); 725dab3f910Sjsing if (!*pcerts) 726dab3f910Sjsing goto end; 727dab3f910Sjsing } 728dab3f910Sjsing if (pcrls) { 729dab3f910Sjsing *pcrls = sk_X509_CRL_new_null(); 730dab3f910Sjsing if (!*pcrls) 731dab3f910Sjsing goto end; 732dab3f910Sjsing } 733dab3f910Sjsing for (i = 0; i < sk_X509_INFO_num(xis); i++) { 734dab3f910Sjsing xi = sk_X509_INFO_value(xis, i); 735dab3f910Sjsing if (xi->x509 && pcerts) { 736dab3f910Sjsing if (!sk_X509_push(*pcerts, xi->x509)) 737dab3f910Sjsing goto end; 738dab3f910Sjsing xi->x509 = NULL; 739dab3f910Sjsing } 740dab3f910Sjsing if (xi->crl && pcrls) { 741dab3f910Sjsing if (!sk_X509_CRL_push(*pcrls, xi->crl)) 742dab3f910Sjsing goto end; 743dab3f910Sjsing xi->crl = NULL; 744dab3f910Sjsing } 745dab3f910Sjsing } 746dab3f910Sjsing 747dab3f910Sjsing if (pcerts && sk_X509_num(*pcerts) > 0) 748dab3f910Sjsing rv = 1; 749dab3f910Sjsing 750dab3f910Sjsing if (pcrls && sk_X509_CRL_num(*pcrls) > 0) 751dab3f910Sjsing rv = 1; 752dab3f910Sjsing 753dab3f910Sjsing end: 754dab3f910Sjsing sk_X509_INFO_pop_free(xis, X509_INFO_free); 755dab3f910Sjsing 756dab3f910Sjsing if (rv == 0) { 757dab3f910Sjsing if (pcerts) { 758dab3f910Sjsing sk_X509_pop_free(*pcerts, X509_free); 759dab3f910Sjsing *pcerts = NULL; 760dab3f910Sjsing } 761dab3f910Sjsing if (pcrls) { 762dab3f910Sjsing sk_X509_CRL_pop_free(*pcrls, X509_CRL_free); 763dab3f910Sjsing *pcrls = NULL; 764dab3f910Sjsing } 765dab3f910Sjsing BIO_printf(err, "unable to load %s\n", 766dab3f910Sjsing pcerts ? "certificates" : "CRLs"); 767dab3f910Sjsing ERR_print_errors(err); 768dab3f910Sjsing } 769dab3f910Sjsing return rv; 770dab3f910Sjsing } 771dab3f910Sjsing 772dab3f910Sjsing STACK_OF(X509) * 773dab3f910Sjsing load_certs(BIO *err, const char *file, int format, const char *pass, 7745284dfeaSbcook const char *desc) 775dab3f910Sjsing { 776dab3f910Sjsing STACK_OF(X509) *certs; 777dab3f910Sjsing 7785284dfeaSbcook if (!load_certs_crls(err, file, format, pass, desc, &certs, NULL)) 779dab3f910Sjsing return NULL; 780dab3f910Sjsing return certs; 781dab3f910Sjsing } 782dab3f910Sjsing 783dab3f910Sjsing STACK_OF(X509_CRL) * 7845284dfeaSbcook load_crls(BIO *err, const char *file, int format, const char *pass, 785dab3f910Sjsing const char *desc) 786dab3f910Sjsing { 787dab3f910Sjsing STACK_OF(X509_CRL) *crls; 788dab3f910Sjsing 7895284dfeaSbcook if (!load_certs_crls(err, file, format, pass, desc, NULL, &crls)) 790dab3f910Sjsing return NULL; 791dab3f910Sjsing return crls; 792dab3f910Sjsing } 793dab3f910Sjsing 794dab3f910Sjsing #define X509V3_EXT_UNKNOWN_MASK (0xfL << 16) 795dab3f910Sjsing /* Return error for unknown extensions */ 796dab3f910Sjsing #define X509V3_EXT_DEFAULT 0 797dab3f910Sjsing /* Print error for unknown extensions */ 798dab3f910Sjsing #define X509V3_EXT_ERROR_UNKNOWN (1L << 16) 799dab3f910Sjsing /* ASN1 parse unknown extensions */ 800dab3f910Sjsing #define X509V3_EXT_PARSE_UNKNOWN (2L << 16) 801dab3f910Sjsing /* BIO_dump unknown extensions */ 802dab3f910Sjsing #define X509V3_EXT_DUMP_UNKNOWN (3L << 16) 803dab3f910Sjsing 804dab3f910Sjsing #define X509_FLAG_CA (X509_FLAG_NO_ISSUER | X509_FLAG_NO_PUBKEY | \ 805dab3f910Sjsing X509_FLAG_NO_HEADER | X509_FLAG_NO_VERSION) 806dab3f910Sjsing 807dab3f910Sjsing int 808dab3f910Sjsing set_cert_ex(unsigned long *flags, const char *arg) 809dab3f910Sjsing { 810dab3f910Sjsing static const NAME_EX_TBL cert_tbl[] = { 811dab3f910Sjsing {"compatible", X509_FLAG_COMPAT, 0xffffffffl}, 812dab3f910Sjsing {"ca_default", X509_FLAG_CA, 0xffffffffl}, 813dab3f910Sjsing {"no_header", X509_FLAG_NO_HEADER, 0}, 814dab3f910Sjsing {"no_version", X509_FLAG_NO_VERSION, 0}, 815dab3f910Sjsing {"no_serial", X509_FLAG_NO_SERIAL, 0}, 816dab3f910Sjsing {"no_signame", X509_FLAG_NO_SIGNAME, 0}, 817dab3f910Sjsing {"no_validity", X509_FLAG_NO_VALIDITY, 0}, 818dab3f910Sjsing {"no_subject", X509_FLAG_NO_SUBJECT, 0}, 819dab3f910Sjsing {"no_issuer", X509_FLAG_NO_ISSUER, 0}, 820dab3f910Sjsing {"no_pubkey", X509_FLAG_NO_PUBKEY, 0}, 821dab3f910Sjsing {"no_extensions", X509_FLAG_NO_EXTENSIONS, 0}, 822dab3f910Sjsing {"no_sigdump", X509_FLAG_NO_SIGDUMP, 0}, 823dab3f910Sjsing {"no_aux", X509_FLAG_NO_AUX, 0}, 824dab3f910Sjsing {"no_attributes", X509_FLAG_NO_ATTRIBUTES, 0}, 825dab3f910Sjsing {"ext_default", X509V3_EXT_DEFAULT, X509V3_EXT_UNKNOWN_MASK}, 826dab3f910Sjsing {"ext_error", X509V3_EXT_ERROR_UNKNOWN, X509V3_EXT_UNKNOWN_MASK}, 827dab3f910Sjsing {"ext_parse", X509V3_EXT_PARSE_UNKNOWN, X509V3_EXT_UNKNOWN_MASK}, 828dab3f910Sjsing {"ext_dump", X509V3_EXT_DUMP_UNKNOWN, X509V3_EXT_UNKNOWN_MASK}, 829dab3f910Sjsing {NULL, 0, 0} 830dab3f910Sjsing }; 831dab3f910Sjsing return set_multi_opts(flags, arg, cert_tbl); 832dab3f910Sjsing } 833dab3f910Sjsing 834dab3f910Sjsing int 835dab3f910Sjsing set_name_ex(unsigned long *flags, const char *arg) 836dab3f910Sjsing { 837dab3f910Sjsing static const NAME_EX_TBL ex_tbl[] = { 838dab3f910Sjsing {"esc_2253", ASN1_STRFLGS_ESC_2253, 0}, 839dab3f910Sjsing {"esc_ctrl", ASN1_STRFLGS_ESC_CTRL, 0}, 840dab3f910Sjsing {"esc_msb", ASN1_STRFLGS_ESC_MSB, 0}, 841dab3f910Sjsing {"use_quote", ASN1_STRFLGS_ESC_QUOTE, 0}, 842dab3f910Sjsing {"utf8", ASN1_STRFLGS_UTF8_CONVERT, 0}, 843dab3f910Sjsing {"ignore_type", ASN1_STRFLGS_IGNORE_TYPE, 0}, 844dab3f910Sjsing {"show_type", ASN1_STRFLGS_SHOW_TYPE, 0}, 845dab3f910Sjsing {"dump_all", ASN1_STRFLGS_DUMP_ALL, 0}, 846dab3f910Sjsing {"dump_nostr", ASN1_STRFLGS_DUMP_UNKNOWN, 0}, 847dab3f910Sjsing {"dump_der", ASN1_STRFLGS_DUMP_DER, 0}, 848dab3f910Sjsing {"compat", XN_FLAG_COMPAT, 0xffffffffL}, 849dab3f910Sjsing {"sep_comma_plus", XN_FLAG_SEP_COMMA_PLUS, XN_FLAG_SEP_MASK}, 850dab3f910Sjsing {"sep_comma_plus_space", XN_FLAG_SEP_CPLUS_SPC, XN_FLAG_SEP_MASK}, 851dab3f910Sjsing {"sep_semi_plus_space", XN_FLAG_SEP_SPLUS_SPC, XN_FLAG_SEP_MASK}, 852dab3f910Sjsing {"sep_multiline", XN_FLAG_SEP_MULTILINE, XN_FLAG_SEP_MASK}, 853dab3f910Sjsing {"dn_rev", XN_FLAG_DN_REV, 0}, 854dab3f910Sjsing {"nofname", XN_FLAG_FN_NONE, XN_FLAG_FN_MASK}, 855dab3f910Sjsing {"sname", XN_FLAG_FN_SN, XN_FLAG_FN_MASK}, 856dab3f910Sjsing {"lname", XN_FLAG_FN_LN, XN_FLAG_FN_MASK}, 857dab3f910Sjsing {"align", XN_FLAG_FN_ALIGN, 0}, 858dab3f910Sjsing {"oid", XN_FLAG_FN_OID, XN_FLAG_FN_MASK}, 859dab3f910Sjsing {"space_eq", XN_FLAG_SPC_EQ, 0}, 860dab3f910Sjsing {"dump_unknown", XN_FLAG_DUMP_UNKNOWN_FIELDS, 0}, 861dab3f910Sjsing {"RFC2253", XN_FLAG_RFC2253, 0xffffffffL}, 862dab3f910Sjsing {"oneline", XN_FLAG_ONELINE, 0xffffffffL}, 863dab3f910Sjsing {"multiline", XN_FLAG_MULTILINE, 0xffffffffL}, 864dab3f910Sjsing {"ca_default", XN_FLAG_MULTILINE, 0xffffffffL}, 865dab3f910Sjsing {NULL, 0, 0} 866dab3f910Sjsing }; 86707cb660dStb if (!set_multi_opts(flags, arg, ex_tbl)) 86807cb660dStb return 0; 86907cb660dStb if (*flags != XN_FLAG_COMPAT && (*flags & XN_FLAG_SEP_MASK) == 0) 87007cb660dStb *flags |= XN_FLAG_SEP_CPLUS_SPC; 87107cb660dStb return 1; 872dab3f910Sjsing } 873dab3f910Sjsing 874dab3f910Sjsing int 875dab3f910Sjsing set_ext_copy(int *copy_type, const char *arg) 876dab3f910Sjsing { 877dab3f910Sjsing if (!strcasecmp(arg, "none")) 878dab3f910Sjsing *copy_type = EXT_COPY_NONE; 879dab3f910Sjsing else if (!strcasecmp(arg, "copy")) 880dab3f910Sjsing *copy_type = EXT_COPY_ADD; 881dab3f910Sjsing else if (!strcasecmp(arg, "copyall")) 882dab3f910Sjsing *copy_type = EXT_COPY_ALL; 883dab3f910Sjsing else 884dab3f910Sjsing return 0; 885dab3f910Sjsing return 1; 886dab3f910Sjsing } 887dab3f910Sjsing 888dab3f910Sjsing int 889dab3f910Sjsing copy_extensions(X509 *x, X509_REQ *req, int copy_type) 890dab3f910Sjsing { 891dab3f910Sjsing STACK_OF(X509_EXTENSION) *exts = NULL; 892dab3f910Sjsing X509_EXTENSION *ext, *tmpext; 893dab3f910Sjsing ASN1_OBJECT *obj; 894dab3f910Sjsing int i, idx, ret = 0; 895dab3f910Sjsing 896dab3f910Sjsing if (!x || !req || (copy_type == EXT_COPY_NONE)) 897dab3f910Sjsing return 1; 898dab3f910Sjsing exts = X509_REQ_get_extensions(req); 899dab3f910Sjsing 900dab3f910Sjsing for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) { 901dab3f910Sjsing ext = sk_X509_EXTENSION_value(exts, i); 902dab3f910Sjsing obj = X509_EXTENSION_get_object(ext); 903dab3f910Sjsing idx = X509_get_ext_by_OBJ(x, obj, -1); 904dab3f910Sjsing /* Does extension exist? */ 905dab3f910Sjsing if (idx != -1) { 906dab3f910Sjsing /* If normal copy don't override existing extension */ 907dab3f910Sjsing if (copy_type == EXT_COPY_ADD) 908dab3f910Sjsing continue; 909dab3f910Sjsing /* Delete all extensions of same type */ 910dab3f910Sjsing do { 911dab3f910Sjsing tmpext = X509_get_ext(x, idx); 912dab3f910Sjsing X509_delete_ext(x, idx); 913dab3f910Sjsing X509_EXTENSION_free(tmpext); 914dab3f910Sjsing idx = X509_get_ext_by_OBJ(x, obj, -1); 915dab3f910Sjsing } while (idx != -1); 916dab3f910Sjsing } 917dab3f910Sjsing if (!X509_add_ext(x, ext, -1)) 918dab3f910Sjsing goto end; 919dab3f910Sjsing } 920dab3f910Sjsing 921dab3f910Sjsing ret = 1; 922dab3f910Sjsing 923dab3f910Sjsing end: 924dab3f910Sjsing sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); 925dab3f910Sjsing 926dab3f910Sjsing return ret; 927dab3f910Sjsing } 928dab3f910Sjsing 929dab3f910Sjsing static int 930dab3f910Sjsing set_multi_opts(unsigned long *flags, const char *arg, 931dab3f910Sjsing const NAME_EX_TBL *in_tbl) 932dab3f910Sjsing { 933dab3f910Sjsing STACK_OF(CONF_VALUE) *vals; 934dab3f910Sjsing CONF_VALUE *val; 935dab3f910Sjsing int i, ret = 1; 936dab3f910Sjsing 937dab3f910Sjsing if (!arg) 938dab3f910Sjsing return 0; 939dab3f910Sjsing vals = X509V3_parse_list(arg); 940dab3f910Sjsing for (i = 0; i < sk_CONF_VALUE_num(vals); i++) { 941dab3f910Sjsing val = sk_CONF_VALUE_value(vals, i); 942dab3f910Sjsing if (!set_table_opts(flags, val->name, in_tbl)) 943dab3f910Sjsing ret = 0; 944dab3f910Sjsing } 945dab3f910Sjsing sk_CONF_VALUE_pop_free(vals, X509V3_conf_free); 946dab3f910Sjsing return ret; 947dab3f910Sjsing } 948dab3f910Sjsing 949dab3f910Sjsing static int 950dab3f910Sjsing set_table_opts(unsigned long *flags, const char *arg, 951dab3f910Sjsing const NAME_EX_TBL *in_tbl) 952dab3f910Sjsing { 953dab3f910Sjsing char c; 954dab3f910Sjsing const NAME_EX_TBL *ptbl; 955dab3f910Sjsing 956dab3f910Sjsing c = arg[0]; 957dab3f910Sjsing if (c == '-') { 958dab3f910Sjsing c = 0; 959dab3f910Sjsing arg++; 960dab3f910Sjsing } else if (c == '+') { 961dab3f910Sjsing c = 1; 962dab3f910Sjsing arg++; 963dab3f910Sjsing } else 964dab3f910Sjsing c = 1; 965dab3f910Sjsing 966dab3f910Sjsing for (ptbl = in_tbl; ptbl->name; ptbl++) { 967dab3f910Sjsing if (!strcasecmp(arg, ptbl->name)) { 968dab3f910Sjsing *flags &= ~ptbl->mask; 969dab3f910Sjsing if (c) 970dab3f910Sjsing *flags |= ptbl->flag; 971dab3f910Sjsing else 972dab3f910Sjsing *flags &= ~ptbl->flag; 973dab3f910Sjsing return 1; 974dab3f910Sjsing } 975dab3f910Sjsing } 976dab3f910Sjsing return 0; 977dab3f910Sjsing } 978dab3f910Sjsing 979dab3f910Sjsing void 980dab3f910Sjsing print_name(BIO *out, const char *title, X509_NAME *nm, unsigned long lflags) 981dab3f910Sjsing { 982dab3f910Sjsing char *buf; 983dab3f910Sjsing char mline = 0; 984dab3f910Sjsing int indent = 0; 985dab3f910Sjsing 986dab3f910Sjsing if (title) 987dab3f910Sjsing BIO_puts(out, title); 988dab3f910Sjsing if ((lflags & XN_FLAG_SEP_MASK) == XN_FLAG_SEP_MULTILINE) { 989dab3f910Sjsing mline = 1; 990dab3f910Sjsing indent = 4; 991dab3f910Sjsing } 992dab3f910Sjsing if (lflags == XN_FLAG_COMPAT) { 993dab3f910Sjsing buf = X509_NAME_oneline(nm, 0, 0); 994dab3f910Sjsing BIO_puts(out, buf); 995dab3f910Sjsing BIO_puts(out, "\n"); 996dab3f910Sjsing free(buf); 997dab3f910Sjsing } else { 998dab3f910Sjsing if (mline) 999dab3f910Sjsing BIO_puts(out, "\n"); 1000dab3f910Sjsing X509_NAME_print_ex(out, nm, indent, lflags); 1001dab3f910Sjsing BIO_puts(out, "\n"); 1002dab3f910Sjsing } 1003dab3f910Sjsing } 1004dab3f910Sjsing 1005dab3f910Sjsing X509_STORE * 1006dab3f910Sjsing setup_verify(BIO *bp, char *CAfile, char *CApath) 1007dab3f910Sjsing { 1008dab3f910Sjsing X509_STORE *store; 1009dab3f910Sjsing X509_LOOKUP *lookup; 1010dab3f910Sjsing 1011dab3f910Sjsing if (!(store = X509_STORE_new())) 1012dab3f910Sjsing goto end; 1013dab3f910Sjsing lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); 1014dab3f910Sjsing if (lookup == NULL) 1015dab3f910Sjsing goto end; 1016dab3f910Sjsing if (CAfile) { 1017dab3f910Sjsing if (!X509_LOOKUP_load_file(lookup, CAfile, X509_FILETYPE_PEM)) { 1018dab3f910Sjsing BIO_printf(bp, "Error loading file %s\n", CAfile); 1019dab3f910Sjsing goto end; 1020dab3f910Sjsing } 1021dab3f910Sjsing } else 1022dab3f910Sjsing X509_LOOKUP_load_file(lookup, NULL, X509_FILETYPE_DEFAULT); 1023dab3f910Sjsing 1024dab3f910Sjsing lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir()); 1025dab3f910Sjsing if (lookup == NULL) 1026dab3f910Sjsing goto end; 1027dab3f910Sjsing if (CApath) { 1028dab3f910Sjsing if (!X509_LOOKUP_add_dir(lookup, CApath, X509_FILETYPE_PEM)) { 1029dab3f910Sjsing BIO_printf(bp, "Error loading directory %s\n", CApath); 1030dab3f910Sjsing goto end; 1031dab3f910Sjsing } 1032dab3f910Sjsing } else 1033dab3f910Sjsing X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT); 1034dab3f910Sjsing 1035dab3f910Sjsing ERR_clear_error(); 1036dab3f910Sjsing return store; 1037dab3f910Sjsing 1038dab3f910Sjsing end: 1039dab3f910Sjsing X509_STORE_free(store); 1040dab3f910Sjsing return NULL; 1041dab3f910Sjsing } 1042dab3f910Sjsing 1043dab3f910Sjsing int 1044dab3f910Sjsing load_config(BIO *err, CONF *cnf) 1045dab3f910Sjsing { 1046dab3f910Sjsing static int load_config_called = 0; 1047dab3f910Sjsing 1048dab3f910Sjsing if (load_config_called) 1049dab3f910Sjsing return 1; 1050dab3f910Sjsing load_config_called = 1; 1051dab3f910Sjsing if (cnf == NULL) 1052dab3f910Sjsing cnf = config; 1053dab3f910Sjsing if (cnf == NULL) 1054dab3f910Sjsing return 1; 1055dab3f910Sjsing 10561ba4ec79Stb OPENSSL_config(NULL); 1057dab3f910Sjsing 1058dab3f910Sjsing if (CONF_modules_load(cnf, NULL, 0) <= 0) { 1059dab3f910Sjsing BIO_printf(err, "Error configuring OpenSSL\n"); 1060dab3f910Sjsing ERR_print_errors(err); 1061dab3f910Sjsing return 0; 1062dab3f910Sjsing } 1063dab3f910Sjsing return 1; 1064dab3f910Sjsing } 1065dab3f910Sjsing 1066dab3f910Sjsing char * 1067440d1414Stb make_config_name(void) 1068dab3f910Sjsing { 1069dab3f910Sjsing const char *t = X509_get_default_cert_area(); 1070dab3f910Sjsing char *p; 1071dab3f910Sjsing 1072dab3f910Sjsing if (asprintf(&p, "%s/openssl.cnf", t) == -1) 1073dab3f910Sjsing return NULL; 1074dab3f910Sjsing return p; 1075dab3f910Sjsing } 1076dab3f910Sjsing 1077dab3f910Sjsing static unsigned long 1078dab3f910Sjsing index_serial_hash(const OPENSSL_CSTRING *a) 1079dab3f910Sjsing { 1080dab3f910Sjsing const char *n; 1081dab3f910Sjsing 1082dab3f910Sjsing n = a[DB_serial]; 1083dab3f910Sjsing while (*n == '0') 1084dab3f910Sjsing n++; 1085dab3f910Sjsing return (lh_strhash(n)); 1086dab3f910Sjsing } 1087dab3f910Sjsing 1088dab3f910Sjsing static int 1089dab3f910Sjsing index_serial_cmp(const OPENSSL_CSTRING *a, const OPENSSL_CSTRING *b) 1090dab3f910Sjsing { 1091dab3f910Sjsing const char *aa, *bb; 1092dab3f910Sjsing 1093dab3f910Sjsing for (aa = a[DB_serial]; *aa == '0'; aa++) 1094dab3f910Sjsing ; 1095dab3f910Sjsing for (bb = b[DB_serial]; *bb == '0'; bb++) 1096dab3f910Sjsing ; 1097dab3f910Sjsing return (strcmp(aa, bb)); 1098dab3f910Sjsing } 1099dab3f910Sjsing 1100dab3f910Sjsing static int 1101dab3f910Sjsing index_name_qual(char **a) 1102dab3f910Sjsing { 1103dab3f910Sjsing return (a[0][0] == 'V'); 1104dab3f910Sjsing } 1105dab3f910Sjsing 1106dab3f910Sjsing static unsigned long 1107dab3f910Sjsing index_name_hash(const OPENSSL_CSTRING *a) 1108dab3f910Sjsing { 1109dab3f910Sjsing return (lh_strhash(a[DB_name])); 1110dab3f910Sjsing } 1111dab3f910Sjsing 1112dab3f910Sjsing int 1113dab3f910Sjsing index_name_cmp(const OPENSSL_CSTRING *a, const OPENSSL_CSTRING *b) 1114dab3f910Sjsing { 1115dab3f910Sjsing return (strcmp(a[DB_name], b[DB_name])); 1116dab3f910Sjsing } 1117dab3f910Sjsing 1118dab3f910Sjsing static IMPLEMENT_LHASH_HASH_FN(index_serial, OPENSSL_CSTRING) 1119dab3f910Sjsing static IMPLEMENT_LHASH_COMP_FN(index_serial, OPENSSL_CSTRING) 1120dab3f910Sjsing static IMPLEMENT_LHASH_HASH_FN(index_name, OPENSSL_CSTRING) 1121dab3f910Sjsing static IMPLEMENT_LHASH_COMP_FN(index_name, OPENSSL_CSTRING) 1122dab3f910Sjsing 1123dab3f910Sjsing BIGNUM * 1124dab3f910Sjsing load_serial(char *serialfile, int create, ASN1_INTEGER **retai) 1125dab3f910Sjsing { 1126dab3f910Sjsing BIO *in = NULL; 1127dab3f910Sjsing BIGNUM *ret = NULL; 1128dab3f910Sjsing char buf[1024]; 1129dab3f910Sjsing ASN1_INTEGER *ai = NULL; 1130dab3f910Sjsing 1131dab3f910Sjsing ai = ASN1_INTEGER_new(); 1132dab3f910Sjsing if (ai == NULL) 1133dab3f910Sjsing goto err; 1134dab3f910Sjsing 1135dab3f910Sjsing if ((in = BIO_new(BIO_s_file())) == NULL) { 1136dab3f910Sjsing ERR_print_errors(bio_err); 1137dab3f910Sjsing goto err; 1138dab3f910Sjsing } 1139dab3f910Sjsing if (BIO_read_filename(in, serialfile) <= 0) { 1140dab3f910Sjsing if (!create) { 1141dab3f910Sjsing perror(serialfile); 1142dab3f910Sjsing goto err; 1143dab3f910Sjsing } else { 1144dab3f910Sjsing ret = BN_new(); 1145dab3f910Sjsing if (ret == NULL || !rand_serial(ret, ai)) 1146dab3f910Sjsing BIO_printf(bio_err, "Out of memory\n"); 1147dab3f910Sjsing } 1148dab3f910Sjsing } else { 11498907b694Sderaadt if (!a2i_ASN1_INTEGER(in, ai, buf, sizeof buf)) { 1150dab3f910Sjsing BIO_printf(bio_err, "unable to load number from %s\n", 1151dab3f910Sjsing serialfile); 1152dab3f910Sjsing goto err; 1153dab3f910Sjsing } 1154dab3f910Sjsing ret = ASN1_INTEGER_to_BN(ai, NULL); 1155dab3f910Sjsing if (ret == NULL) { 1156dab3f910Sjsing BIO_printf(bio_err, 1157dab3f910Sjsing "error converting number from bin to BIGNUM\n"); 1158dab3f910Sjsing goto err; 1159dab3f910Sjsing } 1160dab3f910Sjsing } 1161dab3f910Sjsing 1162dab3f910Sjsing if (ret && retai) { 1163dab3f910Sjsing *retai = ai; 1164dab3f910Sjsing ai = NULL; 1165dab3f910Sjsing } 1166dab3f910Sjsing 1167dab3f910Sjsing err: 1168dab3f910Sjsing BIO_free(in); 1169dab3f910Sjsing ASN1_INTEGER_free(ai); 1170dab3f910Sjsing return (ret); 1171dab3f910Sjsing } 1172dab3f910Sjsing 1173dab3f910Sjsing int 1174dab3f910Sjsing save_serial(char *serialfile, char *suffix, BIGNUM *serial, 1175dab3f910Sjsing ASN1_INTEGER **retai) 1176dab3f910Sjsing { 11778907b694Sderaadt char serialpath[PATH_MAX]; 1178dab3f910Sjsing BIO *out = NULL; 1179dab3f910Sjsing int ret = 0, n; 1180dab3f910Sjsing ASN1_INTEGER *ai = NULL; 1181dab3f910Sjsing 1182dab3f910Sjsing if (suffix == NULL) 11838907b694Sderaadt n = strlcpy(serialpath, serialfile, sizeof serialpath); 1184dab3f910Sjsing else 11858907b694Sderaadt n = snprintf(serialpath, sizeof serialpath, "%s.%s", 1186dab3f910Sjsing serialfile, suffix); 1187515e489cSderaadt if (n < 0 || n >= sizeof(serialpath)) { 1188dab3f910Sjsing BIO_printf(bio_err, "serial too long\n"); 1189dab3f910Sjsing goto err; 1190dab3f910Sjsing } 1191dab3f910Sjsing out = BIO_new(BIO_s_file()); 1192dab3f910Sjsing if (out == NULL) { 1193dab3f910Sjsing ERR_print_errors(bio_err); 1194dab3f910Sjsing goto err; 1195dab3f910Sjsing } 11968907b694Sderaadt if (BIO_write_filename(out, serialpath) <= 0) { 1197dab3f910Sjsing perror(serialfile); 1198dab3f910Sjsing goto err; 1199dab3f910Sjsing } 1200dab3f910Sjsing if ((ai = BN_to_ASN1_INTEGER(serial, NULL)) == NULL) { 1201dab3f910Sjsing BIO_printf(bio_err, 1202dab3f910Sjsing "error converting serial to ASN.1 format\n"); 1203dab3f910Sjsing goto err; 1204dab3f910Sjsing } 1205dab3f910Sjsing i2a_ASN1_INTEGER(out, ai); 1206dab3f910Sjsing BIO_puts(out, "\n"); 1207dab3f910Sjsing ret = 1; 1208dab3f910Sjsing if (retai) { 1209dab3f910Sjsing *retai = ai; 1210dab3f910Sjsing ai = NULL; 1211dab3f910Sjsing } 1212dab3f910Sjsing 1213dab3f910Sjsing err: 1214dab3f910Sjsing BIO_free_all(out); 1215dab3f910Sjsing ASN1_INTEGER_free(ai); 1216dab3f910Sjsing return (ret); 1217dab3f910Sjsing } 1218dab3f910Sjsing 1219dab3f910Sjsing int 1220dab3f910Sjsing rotate_serial(char *serialfile, char *new_suffix, char *old_suffix) 1221dab3f910Sjsing { 12228907b694Sderaadt char opath[PATH_MAX], npath[PATH_MAX]; 1223dab3f910Sjsing 12248907b694Sderaadt if (snprintf(npath, sizeof npath, "%s.%s", serialfile, 12258907b694Sderaadt new_suffix) >= sizeof npath) { 1226dab3f910Sjsing BIO_printf(bio_err, "file name too long\n"); 1227dab3f910Sjsing goto err; 1228dab3f910Sjsing } 1229dab3f910Sjsing 12308907b694Sderaadt if (snprintf(opath, sizeof opath, "%s.%s", serialfile, 12318907b694Sderaadt old_suffix) >= sizeof opath) { 12328907b694Sderaadt BIO_printf(bio_err, "file name too long\n"); 12338907b694Sderaadt goto err; 12348907b694Sderaadt } 1235dab3f910Sjsing 12363aaa63ebSderaadt if (rename(serialfile, opath) == -1 && 1237dab3f910Sjsing errno != ENOENT && errno != ENOTDIR) { 1238dab3f910Sjsing BIO_printf(bio_err, "unable to rename %s to %s\n", 12398907b694Sderaadt serialfile, opath); 1240dab3f910Sjsing perror("reason"); 1241dab3f910Sjsing goto err; 1242dab3f910Sjsing } 1243dab3f910Sjsing 1244dab3f910Sjsing 12453aaa63ebSderaadt if (rename(npath, serialfile) == -1) { 1246dab3f910Sjsing BIO_printf(bio_err, "unable to rename %s to %s\n", 12478907b694Sderaadt npath, serialfile); 1248dab3f910Sjsing perror("reason"); 12493aaa63ebSderaadt if (rename(opath, serialfile) == -1) { 1250270038edSdoug BIO_printf(bio_err, "unable to rename %s to %s\n", 12518907b694Sderaadt opath, serialfile); 1252270038edSdoug perror("reason"); 1253270038edSdoug } 1254dab3f910Sjsing goto err; 1255dab3f910Sjsing } 1256dab3f910Sjsing return 1; 1257dab3f910Sjsing 1258dab3f910Sjsing err: 1259dab3f910Sjsing return 0; 1260dab3f910Sjsing } 1261dab3f910Sjsing 1262dab3f910Sjsing int 1263dab3f910Sjsing rand_serial(BIGNUM *b, ASN1_INTEGER *ai) 1264dab3f910Sjsing { 1265dab3f910Sjsing BIGNUM *btmp; 1266dab3f910Sjsing int ret = 0; 1267dab3f910Sjsing 1268dab3f910Sjsing if (b) 1269dab3f910Sjsing btmp = b; 1270dab3f910Sjsing else 1271dab3f910Sjsing btmp = BN_new(); 1272dab3f910Sjsing 1273dab3f910Sjsing if (!btmp) 1274dab3f910Sjsing return 0; 1275dab3f910Sjsing 1276dab3f910Sjsing if (!BN_pseudo_rand(btmp, SERIAL_RAND_BITS, 0, 0)) 1277dab3f910Sjsing goto error; 1278dab3f910Sjsing if (ai && !BN_to_ASN1_INTEGER(btmp, ai)) 1279dab3f910Sjsing goto error; 1280dab3f910Sjsing 1281dab3f910Sjsing ret = 1; 1282dab3f910Sjsing 1283dab3f910Sjsing error: 1284c4ec5d7dSjsing if (b != btmp) 1285dab3f910Sjsing BN_free(btmp); 1286dab3f910Sjsing 1287dab3f910Sjsing return ret; 1288dab3f910Sjsing } 1289dab3f910Sjsing 1290dab3f910Sjsing CA_DB * 1291dab3f910Sjsing load_index(char *dbfile, DB_ATTR *db_attr) 1292dab3f910Sjsing { 1293dab3f910Sjsing CA_DB *retdb = NULL; 1294dab3f910Sjsing TXT_DB *tmpdb = NULL; 1295dab3f910Sjsing BIO *in = BIO_new(BIO_s_file()); 1296dab3f910Sjsing CONF *dbattr_conf = NULL; 12978907b694Sderaadt char attrpath[PATH_MAX]; 1298dab3f910Sjsing long errorline = -1; 1299dab3f910Sjsing 1300dab3f910Sjsing if (in == NULL) { 1301dab3f910Sjsing ERR_print_errors(bio_err); 1302dab3f910Sjsing goto err; 1303dab3f910Sjsing } 1304dab3f910Sjsing if (BIO_read_filename(in, dbfile) <= 0) { 1305dab3f910Sjsing perror(dbfile); 1306dab3f910Sjsing BIO_printf(bio_err, "unable to open '%s'\n", dbfile); 1307dab3f910Sjsing goto err; 1308dab3f910Sjsing } 1309dab3f910Sjsing if ((tmpdb = TXT_DB_read(in, DB_NUMBER)) == NULL) 1310dab3f910Sjsing goto err; 1311dab3f910Sjsing 13128907b694Sderaadt if (snprintf(attrpath, sizeof attrpath, "%s.attr", dbfile) 13138907b694Sderaadt >= sizeof attrpath) { 13148907b694Sderaadt BIO_printf(bio_err, "attr filename too long\n"); 13158907b694Sderaadt goto err; 13168907b694Sderaadt } 13178907b694Sderaadt 1318dab3f910Sjsing dbattr_conf = NCONF_new(NULL); 13198907b694Sderaadt if (NCONF_load(dbattr_conf, attrpath, &errorline) <= 0) { 1320dab3f910Sjsing if (errorline > 0) { 1321dab3f910Sjsing BIO_printf(bio_err, 1322dab3f910Sjsing "error on line %ld of db attribute file '%s'\n", 13238907b694Sderaadt errorline, attrpath); 1324dab3f910Sjsing goto err; 1325dab3f910Sjsing } else { 1326dab3f910Sjsing NCONF_free(dbattr_conf); 1327dab3f910Sjsing dbattr_conf = NULL; 1328dab3f910Sjsing } 1329dab3f910Sjsing } 1330dab3f910Sjsing if ((retdb = malloc(sizeof(CA_DB))) == NULL) { 1331dab3f910Sjsing fprintf(stderr, "Out of memory\n"); 1332dab3f910Sjsing goto err; 1333dab3f910Sjsing } 1334dab3f910Sjsing retdb->db = tmpdb; 1335dab3f910Sjsing tmpdb = NULL; 1336dab3f910Sjsing if (db_attr) 1337dab3f910Sjsing retdb->attributes = *db_attr; 1338dab3f910Sjsing else { 1339dab3f910Sjsing retdb->attributes.unique_subject = 1; 1340dab3f910Sjsing } 1341dab3f910Sjsing 1342dab3f910Sjsing if (dbattr_conf) { 1343dab3f910Sjsing char *p = NCONF_get_string(dbattr_conf, NULL, "unique_subject"); 1344dab3f910Sjsing if (p) { 1345dab3f910Sjsing retdb->attributes.unique_subject = parse_yesno(p, 1); 1346dab3f910Sjsing } 1347dab3f910Sjsing } 1348dab3f910Sjsing 1349dab3f910Sjsing err: 1350dab3f910Sjsing NCONF_free(dbattr_conf); 1351dab3f910Sjsing TXT_DB_free(tmpdb); 1352dab3f910Sjsing BIO_free_all(in); 1353dab3f910Sjsing return retdb; 1354dab3f910Sjsing } 1355dab3f910Sjsing 1356dab3f910Sjsing int 1357dab3f910Sjsing index_index(CA_DB *db) 1358dab3f910Sjsing { 1359dab3f910Sjsing if (!TXT_DB_create_index(db->db, DB_serial, NULL, 1360dab3f910Sjsing LHASH_HASH_FN(index_serial), LHASH_COMP_FN(index_serial))) { 1361dab3f910Sjsing BIO_printf(bio_err, 1362dab3f910Sjsing "error creating serial number index:(%ld,%ld,%ld)\n", 1363dab3f910Sjsing db->db->error, db->db->arg1, db->db->arg2); 1364dab3f910Sjsing return 0; 1365dab3f910Sjsing } 1366dab3f910Sjsing if (db->attributes.unique_subject && 1367dab3f910Sjsing !TXT_DB_create_index(db->db, DB_name, index_name_qual, 1368dab3f910Sjsing LHASH_HASH_FN(index_name), LHASH_COMP_FN(index_name))) { 1369dab3f910Sjsing BIO_printf(bio_err, "error creating name index:(%ld,%ld,%ld)\n", 1370dab3f910Sjsing db->db->error, db->db->arg1, db->db->arg2); 1371dab3f910Sjsing return 0; 1372dab3f910Sjsing } 1373dab3f910Sjsing return 1; 1374dab3f910Sjsing } 1375dab3f910Sjsing 1376dab3f910Sjsing int 13778907b694Sderaadt save_index(const char *file, const char *suffix, CA_DB *db) 1378dab3f910Sjsing { 13798907b694Sderaadt char attrpath[PATH_MAX], dbfile[PATH_MAX]; 1380dab3f910Sjsing BIO *out = BIO_new(BIO_s_file()); 1381dab3f910Sjsing int j; 1382dab3f910Sjsing 1383dab3f910Sjsing if (out == NULL) { 1384dab3f910Sjsing ERR_print_errors(bio_err); 1385dab3f910Sjsing goto err; 1386dab3f910Sjsing } 13878907b694Sderaadt if (snprintf(attrpath, sizeof attrpath, "%s.attr.%s", 13888907b694Sderaadt file, suffix) >= sizeof attrpath) { 1389dab3f910Sjsing BIO_printf(bio_err, "file name too long\n"); 1390dab3f910Sjsing goto err; 1391dab3f910Sjsing } 13928907b694Sderaadt if (snprintf(dbfile, sizeof dbfile, "%s.%s", 13938907b694Sderaadt file, suffix) >= sizeof dbfile) { 13948907b694Sderaadt BIO_printf(bio_err, "file name too long\n"); 13958907b694Sderaadt goto err; 13968907b694Sderaadt } 1397dab3f910Sjsing 13988907b694Sderaadt if (BIO_write_filename(out, dbfile) <= 0) { 1399dab3f910Sjsing perror(dbfile); 1400dab3f910Sjsing BIO_printf(bio_err, "unable to open '%s'\n", dbfile); 1401dab3f910Sjsing goto err; 1402dab3f910Sjsing } 1403dab3f910Sjsing j = TXT_DB_write(out, db->db); 1404dab3f910Sjsing if (j <= 0) 1405dab3f910Sjsing goto err; 1406dab3f910Sjsing 1407dab3f910Sjsing BIO_free(out); 1408dab3f910Sjsing 1409dab3f910Sjsing out = BIO_new(BIO_s_file()); 1410dab3f910Sjsing 14118907b694Sderaadt if (BIO_write_filename(out, attrpath) <= 0) { 14128907b694Sderaadt perror(attrpath); 14138907b694Sderaadt BIO_printf(bio_err, "unable to open '%s'\n", attrpath); 1414dab3f910Sjsing goto err; 1415dab3f910Sjsing } 1416dab3f910Sjsing BIO_printf(out, "unique_subject = %s\n", 1417dab3f910Sjsing db->attributes.unique_subject ? "yes" : "no"); 1418dab3f910Sjsing BIO_free(out); 1419dab3f910Sjsing 1420dab3f910Sjsing return 1; 1421dab3f910Sjsing 1422dab3f910Sjsing err: 1423dab3f910Sjsing return 0; 1424dab3f910Sjsing } 1425dab3f910Sjsing 1426dab3f910Sjsing int 1427dab3f910Sjsing rotate_index(const char *dbfile, const char *new_suffix, const char *old_suffix) 1428dab3f910Sjsing { 14298907b694Sderaadt char attrpath[PATH_MAX], nattrpath[PATH_MAX], oattrpath[PATH_MAX]; 14308907b694Sderaadt char dbpath[PATH_MAX], odbpath[PATH_MAX]; 1431dab3f910Sjsing 14328907b694Sderaadt if (snprintf(attrpath, sizeof attrpath, "%s.attr", 14338907b694Sderaadt dbfile) >= sizeof attrpath) { 1434dab3f910Sjsing BIO_printf(bio_err, "file name too long\n"); 1435dab3f910Sjsing goto err; 1436dab3f910Sjsing } 14378907b694Sderaadt if (snprintf(nattrpath, sizeof nattrpath, "%s.attr.%s", 14388907b694Sderaadt dbfile, new_suffix) >= sizeof nattrpath) { 14398907b694Sderaadt BIO_printf(bio_err, "file name too long\n"); 14408907b694Sderaadt goto err; 14418907b694Sderaadt } 14428907b694Sderaadt if (snprintf(oattrpath, sizeof oattrpath, "%s.attr.%s", 14438907b694Sderaadt dbfile, old_suffix) >= sizeof oattrpath) { 14448907b694Sderaadt BIO_printf(bio_err, "file name too long\n"); 14458907b694Sderaadt goto err; 14468907b694Sderaadt } 14478907b694Sderaadt if (snprintf(dbpath, sizeof dbpath, "%s.%s", 14488907b694Sderaadt dbfile, new_suffix) >= sizeof dbpath) { 14498907b694Sderaadt BIO_printf(bio_err, "file name too long\n"); 14508907b694Sderaadt goto err; 14518907b694Sderaadt } 14528907b694Sderaadt if (snprintf(odbpath, sizeof odbpath, "%s.%s", 14538907b694Sderaadt dbfile, old_suffix) >= sizeof odbpath) { 14548907b694Sderaadt BIO_printf(bio_err, "file name too long\n"); 14558907b694Sderaadt goto err; 14568907b694Sderaadt } 1457dab3f910Sjsing 14583aaa63ebSderaadt if (rename(dbfile, odbpath) == -1 && errno != ENOENT && errno != ENOTDIR) { 1459dab3f910Sjsing BIO_printf(bio_err, "unable to rename %s to %s\n", 14608907b694Sderaadt dbfile, odbpath); 1461dab3f910Sjsing perror("reason"); 1462dab3f910Sjsing goto err; 1463dab3f910Sjsing } 1464dab3f910Sjsing 14653aaa63ebSderaadt if (rename(dbpath, dbfile) == -1) { 1466dab3f910Sjsing BIO_printf(bio_err, "unable to rename %s to %s\n", 14678907b694Sderaadt dbpath, dbfile); 1468dab3f910Sjsing perror("reason"); 14693aaa63ebSderaadt if (rename(odbpath, dbfile) == -1) { 1470270038edSdoug BIO_printf(bio_err, "unable to rename %s to %s\n", 14718907b694Sderaadt odbpath, dbfile); 1472270038edSdoug perror("reason"); 1473270038edSdoug } 1474dab3f910Sjsing goto err; 1475dab3f910Sjsing } 1476dab3f910Sjsing 14773aaa63ebSderaadt if (rename(attrpath, oattrpath) == -1 && errno != ENOENT && errno != ENOTDIR) { 1478dab3f910Sjsing BIO_printf(bio_err, "unable to rename %s to %s\n", 14798907b694Sderaadt attrpath, oattrpath); 1480dab3f910Sjsing perror("reason"); 14813aaa63ebSderaadt if (rename(dbfile, dbpath) == -1) { 1482270038edSdoug BIO_printf(bio_err, "unable to rename %s to %s\n", 14838907b694Sderaadt dbfile, dbpath); 1484270038edSdoug perror("reason"); 1485270038edSdoug } 14863aaa63ebSderaadt if (rename(odbpath, dbfile) == -1) { 1487270038edSdoug BIO_printf(bio_err, "unable to rename %s to %s\n", 14888907b694Sderaadt odbpath, dbfile); 1489270038edSdoug perror("reason"); 1490270038edSdoug } 1491dab3f910Sjsing goto err; 1492dab3f910Sjsing } 1493dab3f910Sjsing 14943aaa63ebSderaadt if (rename(nattrpath, attrpath) == -1) { 1495dab3f910Sjsing BIO_printf(bio_err, "unable to rename %s to %s\n", 14968907b694Sderaadt nattrpath, attrpath); 1497dab3f910Sjsing perror("reason"); 14983aaa63ebSderaadt if (rename(oattrpath, attrpath) == -1) { 1499270038edSdoug BIO_printf(bio_err, "unable to rename %s to %s\n", 15008907b694Sderaadt oattrpath, attrpath); 1501270038edSdoug perror("reason"); 1502270038edSdoug } 15033aaa63ebSderaadt if (rename(dbfile, dbpath) == -1) { 1504270038edSdoug BIO_printf(bio_err, "unable to rename %s to %s\n", 15058907b694Sderaadt dbfile, dbpath); 1506270038edSdoug perror("reason"); 1507270038edSdoug } 15083aaa63ebSderaadt if (rename(odbpath, dbfile) == -1) { 1509270038edSdoug BIO_printf(bio_err, "unable to rename %s to %s\n", 15108907b694Sderaadt odbpath, dbfile); 1511270038edSdoug perror("reason"); 1512270038edSdoug } 1513dab3f910Sjsing goto err; 1514dab3f910Sjsing } 1515dab3f910Sjsing return 1; 1516dab3f910Sjsing 1517dab3f910Sjsing err: 1518dab3f910Sjsing return 0; 1519dab3f910Sjsing } 1520dab3f910Sjsing 1521dab3f910Sjsing void 1522dab3f910Sjsing free_index(CA_DB *db) 1523dab3f910Sjsing { 1524dab3f910Sjsing if (db) { 1525dab3f910Sjsing TXT_DB_free(db->db); 1526dab3f910Sjsing free(db); 1527dab3f910Sjsing } 1528dab3f910Sjsing } 1529dab3f910Sjsing 1530dab3f910Sjsing int 1531dab3f910Sjsing parse_yesno(const char *str, int def) 1532dab3f910Sjsing { 1533dab3f910Sjsing int ret = def; 1534dab3f910Sjsing 1535dab3f910Sjsing if (str) { 1536dab3f910Sjsing switch (*str) { 1537dab3f910Sjsing case 'f': /* false */ 1538dab3f910Sjsing case 'F': /* FALSE */ 1539dab3f910Sjsing case 'n': /* no */ 1540dab3f910Sjsing case 'N': /* NO */ 1541dab3f910Sjsing case '0': /* 0 */ 1542dab3f910Sjsing ret = 0; 1543dab3f910Sjsing break; 1544dab3f910Sjsing case 't': /* true */ 1545dab3f910Sjsing case 'T': /* TRUE */ 1546dab3f910Sjsing case 'y': /* yes */ 1547dab3f910Sjsing case 'Y': /* YES */ 1548dab3f910Sjsing case '1': /* 1 */ 1549dab3f910Sjsing ret = 1; 1550dab3f910Sjsing break; 1551dab3f910Sjsing default: 1552dab3f910Sjsing ret = def; 1553dab3f910Sjsing break; 1554dab3f910Sjsing } 1555dab3f910Sjsing } 1556dab3f910Sjsing return ret; 1557dab3f910Sjsing } 1558dab3f910Sjsing 1559dab3f910Sjsing /* 1560dab3f910Sjsing * subject is expected to be in the format /type0=value0/type1=value1/type2=... 1561dab3f910Sjsing * where characters may be escaped by \ 1562dab3f910Sjsing */ 1563dab3f910Sjsing X509_NAME * 1564dab3f910Sjsing parse_name(char *subject, long chtype, int multirdn) 1565dab3f910Sjsing { 1566dab3f910Sjsing X509_NAME *name = NULL; 1567dab3f910Sjsing size_t buflen, max_ne; 1568dab3f910Sjsing char **ne_types, **ne_values; 1569dab3f910Sjsing char *buf, *bp, *sp; 1570dab3f910Sjsing int i, nid, ne_num = 0; 1571dab3f910Sjsing int *mval; 1572dab3f910Sjsing 1573dab3f910Sjsing /* 1574dab3f910Sjsing * Buffer to copy the types and values into. Due to escaping the 1575dab3f910Sjsing * copy can only become shorter. 1576dab3f910Sjsing */ 1577dab3f910Sjsing buflen = strlen(subject) + 1; 1578dab3f910Sjsing buf = malloc(buflen); 1579dab3f910Sjsing 1580dab3f910Sjsing /* Maximum number of name elements. */ 1581dab3f910Sjsing max_ne = buflen / 2 + 1; 1582dab3f910Sjsing ne_types = reallocarray(NULL, max_ne, sizeof(char *)); 1583dab3f910Sjsing ne_values = reallocarray(NULL, max_ne, sizeof(char *)); 1584dab3f910Sjsing mval = reallocarray(NULL, max_ne, sizeof(int)); 1585dab3f910Sjsing 1586dab3f910Sjsing if (buf == NULL || ne_types == NULL || ne_values == NULL || 1587dab3f910Sjsing mval == NULL) { 1588dab3f910Sjsing BIO_printf(bio_err, "malloc error\n"); 1589dab3f910Sjsing goto error; 1590dab3f910Sjsing } 1591dab3f910Sjsing 1592dab3f910Sjsing bp = buf; 1593dab3f910Sjsing sp = subject; 1594dab3f910Sjsing 1595dab3f910Sjsing if (*subject != '/') { 1596dab3f910Sjsing BIO_printf(bio_err, "Subject does not start with '/'.\n"); 1597dab3f910Sjsing goto error; 1598dab3f910Sjsing } 1599dab3f910Sjsing 1600dab3f910Sjsing /* Skip leading '/'. */ 1601dab3f910Sjsing sp++; 1602dab3f910Sjsing 1603dab3f910Sjsing /* No multivalued RDN by default. */ 1604dab3f910Sjsing mval[ne_num] = 0; 1605dab3f910Sjsing 1606dab3f910Sjsing while (*sp) { 1607dab3f910Sjsing /* Collect type. */ 1608dab3f910Sjsing ne_types[ne_num] = bp; 1609dab3f910Sjsing while (*sp) { 1610dab3f910Sjsing /* is there anything to escape in the type...? */ 1611dab3f910Sjsing if (*sp == '\\') { 1612dab3f910Sjsing if (*++sp) 1613dab3f910Sjsing *bp++ = *sp++; 1614dab3f910Sjsing else { 1615dab3f910Sjsing BIO_printf(bio_err, "escape character " 1616dab3f910Sjsing "at end of string\n"); 1617dab3f910Sjsing goto error; 1618dab3f910Sjsing } 1619dab3f910Sjsing } else if (*sp == '=') { 1620dab3f910Sjsing sp++; 1621dab3f910Sjsing *bp++ = '\0'; 1622dab3f910Sjsing break; 1623dab3f910Sjsing } else 1624dab3f910Sjsing *bp++ = *sp++; 1625dab3f910Sjsing } 1626dab3f910Sjsing if (!*sp) { 1627dab3f910Sjsing BIO_printf(bio_err, "end of string encountered while " 1628dab3f910Sjsing "processing type of subject name element #%d\n", 1629dab3f910Sjsing ne_num); 1630dab3f910Sjsing goto error; 1631dab3f910Sjsing } 1632dab3f910Sjsing ne_values[ne_num] = bp; 1633dab3f910Sjsing while (*sp) { 1634dab3f910Sjsing if (*sp == '\\') { 1635dab3f910Sjsing if (*++sp) 1636dab3f910Sjsing *bp++ = *sp++; 1637dab3f910Sjsing else { 1638dab3f910Sjsing BIO_printf(bio_err, "escape character " 1639dab3f910Sjsing "at end of string\n"); 1640dab3f910Sjsing goto error; 1641dab3f910Sjsing } 1642dab3f910Sjsing } else if (*sp == '/') { 1643dab3f910Sjsing sp++; 1644dab3f910Sjsing /* no multivalued RDN by default */ 1645dab3f910Sjsing mval[ne_num + 1] = 0; 1646dab3f910Sjsing break; 1647dab3f910Sjsing } else if (*sp == '+' && multirdn) { 164880772f88Smiod /* a not escaped + signals a multivalued RDN */ 1649dab3f910Sjsing sp++; 1650dab3f910Sjsing mval[ne_num + 1] = -1; 1651dab3f910Sjsing break; 1652dab3f910Sjsing } else 1653dab3f910Sjsing *bp++ = *sp++; 1654dab3f910Sjsing } 1655dab3f910Sjsing *bp++ = '\0'; 1656dab3f910Sjsing ne_num++; 1657dab3f910Sjsing } 1658dab3f910Sjsing 1659dab3f910Sjsing if ((name = X509_NAME_new()) == NULL) 1660dab3f910Sjsing goto error; 1661dab3f910Sjsing 1662dab3f910Sjsing for (i = 0; i < ne_num; i++) { 1663dab3f910Sjsing if ((nid = OBJ_txt2nid(ne_types[i])) == NID_undef) { 1664dab3f910Sjsing BIO_printf(bio_err, 1665dab3f910Sjsing "Subject Attribute %s has no known NID, skipped\n", 1666dab3f910Sjsing ne_types[i]); 1667dab3f910Sjsing continue; 1668dab3f910Sjsing } 1669dab3f910Sjsing if (!*ne_values[i]) { 1670dab3f910Sjsing BIO_printf(bio_err, "No value provided for Subject " 1671dab3f910Sjsing "Attribute %s, skipped\n", ne_types[i]); 1672dab3f910Sjsing continue; 1673dab3f910Sjsing } 1674dab3f910Sjsing if (!X509_NAME_add_entry_by_NID(name, nid, chtype, 1675dab3f910Sjsing (unsigned char *) ne_values[i], -1, -1, mval[i])) 1676dab3f910Sjsing goto error; 1677dab3f910Sjsing } 1678dab3f910Sjsing goto done; 1679dab3f910Sjsing 1680dab3f910Sjsing error: 1681dab3f910Sjsing X509_NAME_free(name); 1682dab3f910Sjsing name = NULL; 1683dab3f910Sjsing 1684dab3f910Sjsing done: 1685dab3f910Sjsing free(ne_values); 1686dab3f910Sjsing free(ne_types); 1687dab3f910Sjsing free(mval); 1688dab3f910Sjsing free(buf); 1689dab3f910Sjsing 1690dab3f910Sjsing return name; 1691dab3f910Sjsing } 1692dab3f910Sjsing 1693dab3f910Sjsing int 1694dab3f910Sjsing args_verify(char ***pargs, int *pargc, int *badarg, BIO *err, 1695dab3f910Sjsing X509_VERIFY_PARAM **pm) 1696dab3f910Sjsing { 1697dab3f910Sjsing ASN1_OBJECT *otmp = NULL; 1698dab3f910Sjsing unsigned long flags = 0; 1699dab3f910Sjsing int i; 1700dab3f910Sjsing int purpose = 0, depth = -1; 1701dab3f910Sjsing char **oldargs = *pargs; 1702dab3f910Sjsing char *arg = **pargs, *argn = (*pargs)[1]; 1703dab3f910Sjsing time_t at_time = 0; 1704dab3f910Sjsing const char *errstr = NULL; 1705dab3f910Sjsing 1706dab3f910Sjsing if (!strcmp(arg, "-policy")) { 1707dab3f910Sjsing if (!argn) 1708dab3f910Sjsing *badarg = 1; 1709dab3f910Sjsing else { 1710dab3f910Sjsing otmp = OBJ_txt2obj(argn, 0); 1711dab3f910Sjsing if (!otmp) { 1712dab3f910Sjsing BIO_printf(err, "Invalid Policy \"%s\"\n", 1713dab3f910Sjsing argn); 1714dab3f910Sjsing *badarg = 1; 1715dab3f910Sjsing } 1716dab3f910Sjsing } 1717dab3f910Sjsing (*pargs)++; 1718dab3f910Sjsing } else if (strcmp(arg, "-purpose") == 0) { 17195bbf7eacStb const X509_PURPOSE *xptmp; 1720dab3f910Sjsing if (!argn) 1721dab3f910Sjsing *badarg = 1; 1722dab3f910Sjsing else { 1723dab3f910Sjsing i = X509_PURPOSE_get_by_sname(argn); 1724dab3f910Sjsing if (i < 0) { 1725dab3f910Sjsing BIO_printf(err, "unrecognized purpose\n"); 1726dab3f910Sjsing *badarg = 1; 1727dab3f910Sjsing } else { 1728dab3f910Sjsing xptmp = X509_PURPOSE_get0(i); 1729dab3f910Sjsing purpose = X509_PURPOSE_get_id(xptmp); 1730dab3f910Sjsing } 1731dab3f910Sjsing } 1732dab3f910Sjsing (*pargs)++; 1733dab3f910Sjsing } else if (strcmp(arg, "-verify_depth") == 0) { 1734dab3f910Sjsing if (!argn) 1735dab3f910Sjsing *badarg = 1; 1736dab3f910Sjsing else { 1737dab3f910Sjsing depth = strtonum(argn, 1, INT_MAX, &errstr); 1738dab3f910Sjsing if (errstr) { 1739dab3f910Sjsing BIO_printf(err, "invalid depth %s: %s\n", 1740dab3f910Sjsing argn, errstr); 1741dab3f910Sjsing *badarg = 1; 1742dab3f910Sjsing } 1743dab3f910Sjsing } 1744dab3f910Sjsing (*pargs)++; 1745dab3f910Sjsing } else if (strcmp(arg, "-attime") == 0) { 1746dab3f910Sjsing if (!argn) 1747dab3f910Sjsing *badarg = 1; 1748dab3f910Sjsing else { 1749dab3f910Sjsing long long timestamp; 1750dab3f910Sjsing /* 1751dab3f910Sjsing * interpret the -attime argument as seconds since 1752dab3f910Sjsing * Epoch 1753dab3f910Sjsing */ 1754dab3f910Sjsing if (sscanf(argn, "%lli", ×tamp) != 1) { 1755dab3f910Sjsing BIO_printf(bio_err, 1756dab3f910Sjsing "Error parsing timestamp %s\n", 1757dab3f910Sjsing argn); 1758dab3f910Sjsing *badarg = 1; 1759dab3f910Sjsing } 1760dab3f910Sjsing /* XXX 2038 truncation */ 1761dab3f910Sjsing at_time = (time_t) timestamp; 1762dab3f910Sjsing } 1763dab3f910Sjsing (*pargs)++; 1764dab3f910Sjsing } else if (!strcmp(arg, "-ignore_critical")) 1765dab3f910Sjsing flags |= X509_V_FLAG_IGNORE_CRITICAL; 1766dab3f910Sjsing else if (!strcmp(arg, "-issuer_checks")) 1767dab3f910Sjsing flags |= X509_V_FLAG_CB_ISSUER_CHECK; 1768dab3f910Sjsing else if (!strcmp(arg, "-crl_check")) 1769dab3f910Sjsing flags |= X509_V_FLAG_CRL_CHECK; 1770dab3f910Sjsing else if (!strcmp(arg, "-crl_check_all")) 1771dab3f910Sjsing flags |= X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL; 1772dab3f910Sjsing else if (!strcmp(arg, "-policy_check")) 1773dab3f910Sjsing flags |= X509_V_FLAG_POLICY_CHECK; 1774dab3f910Sjsing else if (!strcmp(arg, "-explicit_policy")) 1775dab3f910Sjsing flags |= X509_V_FLAG_EXPLICIT_POLICY; 17766f2a58b6Stb else if (!strcmp(arg, "-legacy_verify")) 17776f2a58b6Stb flags |= X509_V_FLAG_LEGACY_VERIFY; 1778dab3f910Sjsing else if (!strcmp(arg, "-inhibit_any")) 1779dab3f910Sjsing flags |= X509_V_FLAG_INHIBIT_ANY; 1780dab3f910Sjsing else if (!strcmp(arg, "-inhibit_map")) 1781dab3f910Sjsing flags |= X509_V_FLAG_INHIBIT_MAP; 1782dab3f910Sjsing else if (!strcmp(arg, "-x509_strict")) 1783dab3f910Sjsing flags |= X509_V_FLAG_X509_STRICT; 1784dab3f910Sjsing else if (!strcmp(arg, "-extended_crl")) 1785dab3f910Sjsing flags |= X509_V_FLAG_EXTENDED_CRL_SUPPORT; 1786dab3f910Sjsing else if (!strcmp(arg, "-use_deltas")) 1787dab3f910Sjsing flags |= X509_V_FLAG_USE_DELTAS; 1788dab3f910Sjsing else if (!strcmp(arg, "-policy_print")) 1789dab3f910Sjsing flags |= X509_V_FLAG_NOTIFY_POLICY; 1790dab3f910Sjsing else if (!strcmp(arg, "-check_ss_sig")) 1791dab3f910Sjsing flags |= X509_V_FLAG_CHECK_SS_SIGNATURE; 1792dab3f910Sjsing else 1793dab3f910Sjsing return 0; 1794dab3f910Sjsing 1795dab3f910Sjsing if (*badarg) { 1796dab3f910Sjsing X509_VERIFY_PARAM_free(*pm); 1797dab3f910Sjsing *pm = NULL; 1798dab3f910Sjsing goto end; 1799dab3f910Sjsing } 1800dab3f910Sjsing if (!*pm && !(*pm = X509_VERIFY_PARAM_new())) { 1801dab3f910Sjsing *badarg = 1; 1802dab3f910Sjsing goto end; 1803dab3f910Sjsing } 18045edcce77Sbeck if (otmp) { 1805dab3f910Sjsing X509_VERIFY_PARAM_add0_policy(*pm, otmp); 18065edcce77Sbeck otmp = NULL; 18075edcce77Sbeck } 1808dab3f910Sjsing if (flags) 1809dab3f910Sjsing X509_VERIFY_PARAM_set_flags(*pm, flags); 1810dab3f910Sjsing 1811dab3f910Sjsing if (purpose) 1812dab3f910Sjsing X509_VERIFY_PARAM_set_purpose(*pm, purpose); 1813dab3f910Sjsing 1814dab3f910Sjsing if (depth >= 0) 1815dab3f910Sjsing X509_VERIFY_PARAM_set_depth(*pm, depth); 1816dab3f910Sjsing 1817dab3f910Sjsing if (at_time) 1818dab3f910Sjsing X509_VERIFY_PARAM_set_time(*pm, at_time); 1819dab3f910Sjsing 1820dab3f910Sjsing end: 1821dab3f910Sjsing (*pargs)++; 1822dab3f910Sjsing 1823dab3f910Sjsing if (pargc) 1824dab3f910Sjsing *pargc -= *pargs - oldargs; 1825dab3f910Sjsing 18265edcce77Sbeck ASN1_OBJECT_free(otmp); 1827dab3f910Sjsing return 1; 1828dab3f910Sjsing } 1829dab3f910Sjsing 1830dab3f910Sjsing /* Read whole contents of a BIO into an allocated memory buffer and 1831dab3f910Sjsing * return it. 1832dab3f910Sjsing */ 1833dab3f910Sjsing 1834dab3f910Sjsing int 1835dab3f910Sjsing bio_to_mem(unsigned char **out, int maxlen, BIO *in) 1836dab3f910Sjsing { 1837dab3f910Sjsing BIO *mem; 1838dab3f910Sjsing int len, ret; 1839dab3f910Sjsing unsigned char tbuf[1024]; 1840dab3f910Sjsing 1841dab3f910Sjsing mem = BIO_new(BIO_s_mem()); 1842dab3f910Sjsing if (!mem) 1843dab3f910Sjsing return -1; 1844dab3f910Sjsing for (;;) { 1845dab3f910Sjsing if ((maxlen != -1) && maxlen < 1024) 1846dab3f910Sjsing len = maxlen; 1847dab3f910Sjsing else 1848dab3f910Sjsing len = 1024; 1849dab3f910Sjsing len = BIO_read(in, tbuf, len); 1850dab3f910Sjsing if (len <= 0) 1851dab3f910Sjsing break; 1852dab3f910Sjsing if (BIO_write(mem, tbuf, len) != len) { 1853dab3f910Sjsing BIO_free(mem); 1854dab3f910Sjsing return -1; 1855dab3f910Sjsing } 1856dab3f910Sjsing maxlen -= len; 1857dab3f910Sjsing 1858dab3f910Sjsing if (maxlen == 0) 1859dab3f910Sjsing break; 1860dab3f910Sjsing } 1861dab3f910Sjsing ret = BIO_get_mem_data(mem, (char **) out); 1862dab3f910Sjsing BIO_set_flags(mem, BIO_FLAGS_MEM_RDONLY); 1863dab3f910Sjsing BIO_free(mem); 1864dab3f910Sjsing return ret; 1865dab3f910Sjsing } 1866dab3f910Sjsing 1867dab3f910Sjsing int 1868dab3f910Sjsing pkey_ctrl_string(EVP_PKEY_CTX *ctx, char *value) 1869dab3f910Sjsing { 1870dab3f910Sjsing int rv; 1871dab3f910Sjsing char *stmp, *vtmp = NULL; 1872dab3f910Sjsing 18738e315e4cSjsing if (value == NULL) 18748e315e4cSjsing return -1; 18758e315e4cSjsing stmp = strdup(value); 1876dab3f910Sjsing if (!stmp) 1877dab3f910Sjsing return -1; 1878dab3f910Sjsing vtmp = strchr(stmp, ':'); 1879dab3f910Sjsing if (vtmp) { 1880dab3f910Sjsing *vtmp = 0; 1881dab3f910Sjsing vtmp++; 1882dab3f910Sjsing } 1883dab3f910Sjsing rv = EVP_PKEY_CTX_ctrl_str(ctx, stmp, vtmp); 1884dab3f910Sjsing free(stmp); 1885dab3f910Sjsing 1886dab3f910Sjsing return rv; 1887dab3f910Sjsing } 1888dab3f910Sjsing 188941eb9d41Sjsing /* 189041eb9d41Sjsing * next_protos_parse parses a comma separated list of strings into a string 1891dab3f910Sjsing * in a format suitable for passing to SSL_CTX_set_next_protos_advertised. 1892dab3f910Sjsing * outlen: (output) set to the length of the resulting buffer on success. 1893dab3f910Sjsing * err: (maybe NULL) on failure, an error message line is written to this BIO. 1894*92d49c07Stb * in: a NUL terminated string like "abc,def,ghi" 1895dab3f910Sjsing * 1896dab3f910Sjsing * returns: a malloced buffer or NULL on failure. 1897dab3f910Sjsing */ 1898dab3f910Sjsing unsigned char * 1899dab3f910Sjsing next_protos_parse(unsigned short *outlen, const char *in) 1900dab3f910Sjsing { 1901dab3f910Sjsing size_t len; 1902dab3f910Sjsing unsigned char *out; 1903dab3f910Sjsing size_t i, start = 0; 1904dab3f910Sjsing 1905dab3f910Sjsing len = strlen(in); 1906dab3f910Sjsing if (len >= 65535) 1907dab3f910Sjsing return NULL; 1908dab3f910Sjsing 1909dab3f910Sjsing out = malloc(strlen(in) + 1); 1910dab3f910Sjsing if (!out) 1911dab3f910Sjsing return NULL; 1912dab3f910Sjsing 1913dab3f910Sjsing for (i = 0; i <= len; ++i) { 1914dab3f910Sjsing if (i == len || in[i] == ',') { 1915dab3f910Sjsing if (i - start > 255) { 1916dab3f910Sjsing free(out); 1917dab3f910Sjsing return NULL; 1918dab3f910Sjsing } 1919dab3f910Sjsing out[start] = i - start; 1920dab3f910Sjsing start = i + 1; 1921dab3f910Sjsing } else 1922dab3f910Sjsing out[i + 1] = in[i]; 1923dab3f910Sjsing } 1924dab3f910Sjsing 1925dab3f910Sjsing *outlen = len + 1; 1926dab3f910Sjsing return out; 1927dab3f910Sjsing } 1928dab3f910Sjsing 1929dab3f910Sjsing int 1930dab3f910Sjsing app_isdir(const char *name) 1931dab3f910Sjsing { 1932dab3f910Sjsing struct stat st; 1933dab3f910Sjsing 1934dab3f910Sjsing if (stat(name, &st) == 0) 1935dab3f910Sjsing return S_ISDIR(st.st_mode); 1936dab3f910Sjsing return -1; 1937dab3f910Sjsing } 19386b8b4364Sjsing 1939938f9cfcSjsing #define OPTION_WIDTH 18 1940938f9cfcSjsing 19416b8b4364Sjsing void 1942ea149709Sguenther options_usage(const struct option *opts) 19436b8b4364Sjsing { 1944938f9cfcSjsing const char *p, *q; 1945938f9cfcSjsing char optstr[32]; 19466b8b4364Sjsing int i; 19476b8b4364Sjsing 19486b8b4364Sjsing for (i = 0; opts[i].name != NULL; i++) { 19496b8b4364Sjsing if (opts[i].desc == NULL) 19506b8b4364Sjsing continue; 1951938f9cfcSjsing 1952938f9cfcSjsing snprintf(optstr, sizeof(optstr), "-%s %s", opts[i].name, 1953938f9cfcSjsing (opts[i].argname != NULL) ? opts[i].argname : ""); 1954938f9cfcSjsing fprintf(stderr, " %-*s", OPTION_WIDTH, optstr); 1955938f9cfcSjsing if (strlen(optstr) > OPTION_WIDTH) 1956938f9cfcSjsing fprintf(stderr, "\n %-*s", OPTION_WIDTH, ""); 1957938f9cfcSjsing 1958938f9cfcSjsing p = opts[i].desc; 1959938f9cfcSjsing while ((q = strchr(p, '\n')) != NULL) { 1960938f9cfcSjsing fprintf(stderr, " %.*s", (int)(q - p), p); 1961938f9cfcSjsing fprintf(stderr, "\n %-*s", OPTION_WIDTH, ""); 1962938f9cfcSjsing p = q + 1; 1963938f9cfcSjsing } 1964938f9cfcSjsing fprintf(stderr, " %s\n", p); 19656b8b4364Sjsing } 19666b8b4364Sjsing } 19676b8b4364Sjsing 19686b8b4364Sjsing int 1969ea149709Sguenther options_parse(int argc, char **argv, const struct option *opts, char **unnamed, 1970beba0da1Sjsing int *argsused) 19716b8b4364Sjsing { 1972644a601eSjsing const char *errstr; 1973ea149709Sguenther const struct option *opt; 1974644a601eSjsing long long val; 19756b8b4364Sjsing char *arg, *p; 1976b1649c7eSjsing int fmt, used; 1977f9a600f9Sjsing int ord = 0; 19786b8b4364Sjsing int i, j; 19796b8b4364Sjsing 198045435f71Sjsing if (unnamed != NULL) 198145435f71Sjsing *unnamed = NULL; 198245435f71Sjsing 19836b8b4364Sjsing for (i = 1; i < argc; i++) { 19846b8b4364Sjsing p = arg = argv[i]; 19856b8b4364Sjsing 198645435f71Sjsing /* Single unnamed argument (without leading hyphen). */ 19876b8b4364Sjsing if (*p++ != '-') { 1988beba0da1Sjsing if (argsused != NULL) 1989beba0da1Sjsing goto done; 19906b8b4364Sjsing if (unnamed == NULL) 19916b8b4364Sjsing goto unknown; 199245435f71Sjsing if (*unnamed != NULL) 199345435f71Sjsing goto toomany; 19946b8b4364Sjsing *unnamed = arg; 19956b8b4364Sjsing continue; 19966b8b4364Sjsing } 199745435f71Sjsing 1998024f1184Sjsing /* End of named options (single hyphen). */ 1999024f1184Sjsing if (*p == '\0') { 2000024f1184Sjsing if (++i >= argc) 2001024f1184Sjsing goto done; 2002024f1184Sjsing if (argsused != NULL) 2003024f1184Sjsing goto done; 2004024f1184Sjsing if (unnamed != NULL && i == argc - 1) { 2005024f1184Sjsing if (*unnamed != NULL) 2006024f1184Sjsing goto toomany; 2007024f1184Sjsing *unnamed = argv[i]; 2008024f1184Sjsing continue; 2009024f1184Sjsing } 20106b8b4364Sjsing goto unknown; 2011024f1184Sjsing } 20126b8b4364Sjsing 2013b1649c7eSjsing /* See if there is a matching option... */ 20146b8b4364Sjsing for (j = 0; opts[j].name != NULL; j++) { 201573bf9b78Sjsing if (strcmp(p, opts[j].name) == 0) 2016620e0cb1Sjsing break; 2017620e0cb1Sjsing } 201873bf9b78Sjsing opt = &opts[j]; 2019179b5346Sjsing if (opt->name == NULL && opt->type == 0) 2020620e0cb1Sjsing goto unknown; 20216b8b4364Sjsing 2022644a601eSjsing if (opt->type == OPTION_ARG || 20230ee7f8aeSjsing opt->type == OPTION_ARG_FORMAT || 2024ec4a4065Sjsing opt->type == OPTION_ARG_FUNC || 2025751065ffSjsing opt->type == OPTION_ARG_INT || 2026712e3e77Sguenther opt->type == OPTION_ARG_LONG || 2027712e3e77Sguenther opt->type == OPTION_ARG_TIME) { 20286b8b4364Sjsing if (++i >= argc) { 2029620e0cb1Sjsing fprintf(stderr, "missing %s argument for -%s\n", 20306b8b4364Sjsing opt->argname, opt->name); 20316b8b4364Sjsing return (1); 20326b8b4364Sjsing } 2033644a601eSjsing } 2034644a601eSjsing 2035644a601eSjsing switch (opt->type) { 2036644a601eSjsing case OPTION_ARG: 20376b8b4364Sjsing *opt->opt.arg = argv[i]; 20386b8b4364Sjsing break; 20396b8b4364Sjsing 2040b1649c7eSjsing case OPTION_ARGV_FUNC: 2041b1649c7eSjsing if (opt->opt.argvfunc(argc - i, &argv[i], &used) != 0) 2042b1649c7eSjsing return (1); 2043b1649c7eSjsing i += used - 1; 2044b1649c7eSjsing break; 2045b1649c7eSjsing 20460ee7f8aeSjsing case OPTION_ARG_FORMAT: 2047e498f05eSjsing fmt = str2fmt(argv[i]); 2048e498f05eSjsing if (fmt == FORMAT_UNDEF) { 2049620e0cb1Sjsing fprintf(stderr, "unknown %s '%s' for -%s\n", 2050e498f05eSjsing opt->argname, argv[i], opt->name); 2051e498f05eSjsing return (1); 2052e498f05eSjsing } 2053e498f05eSjsing *opt->opt.value = fmt; 20540ee7f8aeSjsing break; 20550ee7f8aeSjsing 2056ec4a4065Sjsing case OPTION_ARG_FUNC: 2057d16f2e55Sjsing if (opt->opt.argfunc(argv[i]) != 0) 2058ec4a4065Sjsing return (1); 2059ec4a4065Sjsing break; 2060ec4a4065Sjsing 2061644a601eSjsing case OPTION_ARG_INT: 2062644a601eSjsing val = strtonum(argv[i], 0, INT_MAX, &errstr); 2063644a601eSjsing if (errstr != NULL) { 2064620e0cb1Sjsing fprintf(stderr, "%s %s argument for -%s\n", 2065644a601eSjsing errstr, opt->argname, opt->name); 2066644a601eSjsing return (1); 2067644a601eSjsing } 2068644a601eSjsing *opt->opt.value = (int)val; 2069644a601eSjsing break; 2070644a601eSjsing 2071751065ffSjsing case OPTION_ARG_LONG: 2072751065ffSjsing val = strtonum(argv[i], 0, LONG_MAX, &errstr); 2073751065ffSjsing if (errstr != NULL) { 2074751065ffSjsing fprintf(stderr, "%s %s argument for -%s\n", 2075751065ffSjsing errstr, opt->argname, opt->name); 2076751065ffSjsing return (1); 2077751065ffSjsing } 2078751065ffSjsing *opt->opt.lvalue = (long)val; 2079751065ffSjsing break; 2080751065ffSjsing 2081ea1128d8Sderaadt case OPTION_ARG_TIME: 2082ea1128d8Sderaadt val = strtonum(argv[i], 0, LLONG_MAX, &errstr); 2083ea1128d8Sderaadt if (errstr != NULL) { 2084ea1128d8Sderaadt fprintf(stderr, "%s %s argument for -%s\n", 2085ea1128d8Sderaadt errstr, opt->argname, opt->name); 2086ea1128d8Sderaadt return (1); 2087ea1128d8Sderaadt } 2088ea1128d8Sderaadt *opt->opt.tvalue = val; 2089ea1128d8Sderaadt break; 2090ea1128d8Sderaadt 20910aaa00e6Sdoug case OPTION_DISCARD: 20920aaa00e6Sdoug break; 20930aaa00e6Sdoug 20940c2cbfefSjsing case OPTION_FUNC: 2095d16f2e55Sjsing if (opt->opt.func() != 0) 20960c2cbfefSjsing return (1); 20970c2cbfefSjsing break; 20980c2cbfefSjsing 20996b8b4364Sjsing case OPTION_FLAG: 21006b8b4364Sjsing *opt->opt.flag = 1; 21016b8b4364Sjsing break; 21026b8b4364Sjsing 2103f9a600f9Sjsing case OPTION_FLAG_ORD: 2104f9a600f9Sjsing *opt->opt.flag = ++ord; 2105f9a600f9Sjsing break; 2106f9a600f9Sjsing 21076b8b4364Sjsing case OPTION_VALUE: 21086b8b4364Sjsing *opt->opt.value = opt->value; 21096b8b4364Sjsing break; 21106b8b4364Sjsing 21111cb342c7Sjsing case OPTION_VALUE_AND: 21121cb342c7Sjsing *opt->opt.value &= opt->value; 21131cb342c7Sjsing break; 21141cb342c7Sjsing 21151cb342c7Sjsing case OPTION_VALUE_OR: 21161cb342c7Sjsing *opt->opt.value |= opt->value; 21171cb342c7Sjsing break; 21181cb342c7Sjsing 21196fde9eb9Sinoguchi case OPTION_UL_VALUE_OR: 21206fde9eb9Sinoguchi *opt->opt.ulvalue |= opt->ulvalue; 21216fde9eb9Sinoguchi break; 21226fde9eb9Sinoguchi 2123ac908323Sinoguchi case OPTION_ORDER: 2124ac908323Sinoguchi *opt->opt.order = ++(*opt->order); 2125ac908323Sinoguchi break; 2126ac908323Sinoguchi 21276b8b4364Sjsing default: 2128620e0cb1Sjsing fprintf(stderr, "option %s - unknown type %i\n", 21296b8b4364Sjsing opt->name, opt->type); 21306b8b4364Sjsing return (1); 21316b8b4364Sjsing } 21326b8b4364Sjsing } 21336b8b4364Sjsing 2134beba0da1Sjsing done: 2135beba0da1Sjsing if (argsused != NULL) 2136beba0da1Sjsing *argsused = i; 2137beba0da1Sjsing 21386b8b4364Sjsing return (0); 21396b8b4364Sjsing 214045435f71Sjsing toomany: 214145435f71Sjsing fprintf(stderr, "too many arguments\n"); 214245435f71Sjsing return (1); 214345435f71Sjsing 21446b8b4364Sjsing unknown: 21456b8b4364Sjsing fprintf(stderr, "unknown option '%s'\n", arg); 21466b8b4364Sjsing return (1); 21476b8b4364Sjsing } 21484071f800Sinoguchi 21494071f800Sinoguchi void 21504071f800Sinoguchi show_cipher(const OBJ_NAME *name, void *arg) 21514071f800Sinoguchi { 21526685372aSinoguchi int *n = arg; 21534071f800Sinoguchi 21544071f800Sinoguchi if (!islower((unsigned char)*name->name)) 21554071f800Sinoguchi return; 21564071f800Sinoguchi 21576685372aSinoguchi fprintf(stderr, " -%-24s%s", name->name, (++*n % 3 != 0 ? "" : "\n")); 21584071f800Sinoguchi } 2159