From beb6bb8aa010a3dedd60f733124c37899d412738 Mon Sep 17 00:00:00 2001 From: Lauri Tirkkonen Date: Mon, 3 Jul 2017 17:18:35 +0300 Subject: [PATCH] import openssl(1) (LibreSSL 2.5.4) not part of build yet. --- bin/openssl/Makefile | 30 + bin/openssl/apps.c | 2334 +++++++++++++ bin/openssl/apps.h | 323 ++ bin/openssl/apps_posix.c | 164 + bin/openssl/asn1pars.c | 482 +++ bin/openssl/ca.c | 2692 +++++++++++++++ bin/openssl/certhash.c | 688 ++++ bin/openssl/ciphers.c | 152 + bin/openssl/compat.mk | 5 + bin/openssl/crl.c | 477 +++ bin/openssl/crl2p7.c | 333 ++ bin/openssl/dgst.c | 544 +++ bin/openssl/dh.c | 300 ++ bin/openssl/dhparam.c | 499 +++ bin/openssl/dsa.c | 373 ++ bin/openssl/dsaparam.c | 371 ++ bin/openssl/ec.c | 406 +++ bin/openssl/ecparam.c | 615 ++++ bin/openssl/enc.c | 770 +++++ bin/openssl/errstr.c | 148 + bin/openssl/gendh.c | 217 ++ bin/openssl/gendsa.c | 216 ++ bin/openssl/genpkey.c | 359 ++ bin/openssl/genrsa.c | 266 ++ bin/openssl/nseq.c | 176 + bin/openssl/ocsp.c | 1220 +++++++ bin/openssl/openssl.1 | 6114 +++++++++++++++++++++++++++++++++ bin/openssl/openssl.c | 831 +++++ bin/openssl/passwd.c | 491 +++ bin/openssl/pkcs12.c | 896 +++++ bin/openssl/pkcs7.c | 289 ++ bin/openssl/pkcs8.c | 419 +++ bin/openssl/pkey.c | 220 ++ bin/openssl/pkeyparam.c | 174 + bin/openssl/pkeyutl.c | 494 +++ bin/openssl/prime.c | 199 ++ bin/openssl/progs.h | 47 + bin/openssl/rand.c | 185 + bin/openssl/req.c | 1560 +++++++++ bin/openssl/rsa.c | 449 +++ bin/openssl/rsautl.c | 332 ++ bin/openssl/s_apps.h | 151 + bin/openssl/s_cb.c | 886 +++++ bin/openssl/s_client.c | 1501 ++++++++ bin/openssl/s_server.c | 2037 +++++++++++ bin/openssl/s_socket.c | 338 ++ bin/openssl/s_time.c | 552 +++ bin/openssl/sess_id.c | 295 ++ bin/openssl/smime.c | 682 ++++ bin/openssl/speed.c | 2155 ++++++++++++ bin/openssl/spkac.c | 313 ++ bin/openssl/testdsa.h | 221 ++ bin/openssl/testrsa.h | 517 +++ bin/openssl/timeouts.h | 67 + bin/openssl/ts.c | 1090 ++++++ bin/openssl/verify.c | 324 ++ bin/openssl/version.c | 269 ++ bin/openssl/x509.c | 1150 +++++++ lib/libcrypto/compat/include/unistd.h | 52 + lib/libcrypto/compat/strtonum.c | 65 + 60 files changed, 39525 insertions(+) create mode 100644 bin/openssl/Makefile create mode 100644 bin/openssl/apps.c create mode 100644 bin/openssl/apps.h create mode 100644 bin/openssl/apps_posix.c create mode 100644 bin/openssl/asn1pars.c create mode 100644 bin/openssl/ca.c create mode 100644 bin/openssl/certhash.c create mode 100644 bin/openssl/ciphers.c create mode 100644 bin/openssl/compat.mk create mode 100644 bin/openssl/crl.c create mode 100644 bin/openssl/crl2p7.c create mode 100644 bin/openssl/dgst.c create mode 100644 bin/openssl/dh.c create mode 100644 bin/openssl/dhparam.c create mode 100644 bin/openssl/dsa.c create mode 100644 bin/openssl/dsaparam.c create mode 100644 bin/openssl/ec.c create mode 100644 bin/openssl/ecparam.c create mode 100644 bin/openssl/enc.c create mode 100644 bin/openssl/errstr.c create mode 100644 bin/openssl/gendh.c create mode 100644 bin/openssl/gendsa.c create mode 100644 bin/openssl/genpkey.c create mode 100644 bin/openssl/genrsa.c create mode 100644 bin/openssl/nseq.c create mode 100644 bin/openssl/ocsp.c create mode 100644 bin/openssl/openssl.1 create mode 100644 bin/openssl/openssl.c create mode 100644 bin/openssl/passwd.c create mode 100644 bin/openssl/pkcs12.c create mode 100644 bin/openssl/pkcs7.c create mode 100644 bin/openssl/pkcs8.c create mode 100644 bin/openssl/pkey.c create mode 100644 bin/openssl/pkeyparam.c create mode 100644 bin/openssl/pkeyutl.c create mode 100644 bin/openssl/prime.c create mode 100644 bin/openssl/progs.h create mode 100644 bin/openssl/rand.c create mode 100644 bin/openssl/req.c create mode 100644 bin/openssl/rsa.c create mode 100644 bin/openssl/rsautl.c create mode 100644 bin/openssl/s_apps.h create mode 100644 bin/openssl/s_cb.c create mode 100644 bin/openssl/s_client.c create mode 100644 bin/openssl/s_server.c create mode 100644 bin/openssl/s_socket.c create mode 100644 bin/openssl/s_time.c create mode 100644 bin/openssl/sess_id.c create mode 100644 bin/openssl/smime.c create mode 100644 bin/openssl/speed.c create mode 100644 bin/openssl/spkac.c create mode 100644 bin/openssl/testdsa.h create mode 100644 bin/openssl/testrsa.h create mode 100644 bin/openssl/timeouts.h create mode 100644 bin/openssl/ts.c create mode 100644 bin/openssl/verify.c create mode 100644 bin/openssl/version.c create mode 100644 bin/openssl/x509.c create mode 100644 lib/libcrypto/compat/include/unistd.h create mode 100644 lib/libcrypto/compat/strtonum.c diff --git a/bin/openssl/Makefile b/bin/openssl/Makefile new file mode 100644 index 0000000000..614b8b05f5 --- /dev/null +++ b/bin/openssl/Makefile @@ -0,0 +1,30 @@ +# $OpenBSD: Makefile,v 1.7 2016/09/04 18:05:34 beck Exp $ + +PROG= openssl +LDADD= -lssl -lcrypto +DPADD= ${LIBSSL} ${LIBCRYPTO} +MAN1= openssl.1 + +CFLAGS+= -Wall -Werror +CFLAGS+= -Wformat +CFLAGS+= -Wformat-security +CFLAGS+= -Wimplicit +CFLAGS+= -Wreturn-type +#CFLAGS+= -Wshadow +CFLAGS+= -Wtrigraphs +CFLAGS+= -Wuninitialized +CFLAGS+= -Wunused + +CFLAGS+= -DLIBRESSL_INTERNAL + +SRCS= apps.c apps_posix.c asn1pars.c ca.c certhash.c ciphers.c crl.c \ + crl2p7.c dgst.c dh.c dhparam.c dsa.c dsaparam.c ec.c ecparam.c enc.c \ + errstr.c gendh.c gendsa.c genpkey.c genrsa.c nseq.c ocsp.c \ + openssl.c passwd.c pkcs12.c pkcs7.c pkcs8.c pkey.c pkeyparam.c \ + pkeyutl.c prime.c rand.c req.c rsa.c rsautl.c s_cb.c s_client.c \ + s_server.c s_socket.c s_time.c sess_id.c smime.c speed.c spkac.c ts.c \ + verify.c version.c x509.c + +.include "compat.mk" + +.include diff --git a/bin/openssl/apps.c b/bin/openssl/apps.c new file mode 100644 index 0000000000..c6c992fe10 --- /dev/null +++ b/bin/openssl/apps.c @@ -0,0 +1,2334 @@ +/* $OpenBSD: apps.c,v 1.42 2017/01/21 09:29:09 deraadt Exp $ */ +/* + * Copyright (c) 2014 Joel Sing + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "apps.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +typedef struct { + const char *name; + unsigned long flag; + unsigned long mask; +} NAME_EX_TBL; + +UI_METHOD *ui_method = NULL; + +static int set_table_opts(unsigned long *flags, const char *arg, + const NAME_EX_TBL *in_tbl); +static int set_multi_opts(unsigned long *flags, const char *arg, + const NAME_EX_TBL *in_tbl); + +#if !defined(OPENSSL_NO_RC4) && !defined(OPENSSL_NO_RSA) +/* Looks like this stuff is worth moving into separate function */ +static EVP_PKEY *load_netscape_key(BIO *err, BIO *key, const char *file, + const char *key_descrip, int format); +#endif + +int +str2fmt(char *s) +{ + if (s == NULL) + return FORMAT_UNDEF; + if ((*s == 'D') || (*s == 'd')) + return (FORMAT_ASN1); + else if ((*s == 'T') || (*s == 't')) + return (FORMAT_TEXT); + else if ((*s == 'N') || (*s == 'n')) + return (FORMAT_NETSCAPE); + else if ((*s == 'S') || (*s == 's')) + return (FORMAT_SMIME); + else if ((*s == 'M') || (*s == 'm')) + return (FORMAT_MSBLOB); + else if ((*s == '1') || + (strcmp(s, "PKCS12") == 0) || (strcmp(s, "pkcs12") == 0) || + (strcmp(s, "P12") == 0) || (strcmp(s, "p12") == 0)) + return (FORMAT_PKCS12); + else if ((*s == 'P') || (*s == 'p')) { + if (s[1] == 'V' || s[1] == 'v') + return FORMAT_PVK; + else + return (FORMAT_PEM); + } else + return (FORMAT_UNDEF); +} + +void +program_name(char *in, char *out, int size) +{ + char *p; + + p = strrchr(in, '/'); + if (p != NULL) + p++; + else + p = in; + strlcpy(out, p, size); +} + +int +chopup_args(ARGS *arg, char *buf, int *argc, char **argv[]) +{ + int num, i; + char *p; + + *argc = 0; + *argv = NULL; + + i = 0; + if (arg->count == 0) { + arg->count = 20; + arg->data = reallocarray(NULL, arg->count, sizeof(char *)); + if (arg->data == NULL) + return 0; + } + for (i = 0; i < arg->count; i++) + arg->data[i] = NULL; + + num = 0; + p = buf; + for (;;) { + /* first scan over white space */ + if (!*p) + break; + while (*p && ((*p == ' ') || (*p == '\t') || (*p == '\n'))) + p++; + if (!*p) + break; + + /* The start of something good :-) */ + if (num >= arg->count) { + char **tmp_p; + int tlen = arg->count + 20; + tmp_p = reallocarray(arg->data, tlen, sizeof(char *)); + if (tmp_p == NULL) + return 0; + arg->data = tmp_p; + arg->count = tlen; + /* initialize newly allocated data */ + for (i = num; i < arg->count; i++) + arg->data[i] = NULL; + } + arg->data[num++] = p; + + /* now look for the end of this */ + if ((*p == '\'') || (*p == '\"')) { /* scan for closing + * quote */ + i = *(p++); + arg->data[num - 1]++; /* jump over quote */ + while (*p && (*p != i)) + p++; + *p = '\0'; + } else { + while (*p && ((*p != ' ') && + (*p != '\t') && (*p != '\n'))) + p++; + + if (*p == '\0') + p--; + else + *p = '\0'; + } + p++; + } + *argc = num; + *argv = arg->data; + return (1); +} + +int +dump_cert_text(BIO *out, X509 *x) +{ + char *p; + + p = X509_NAME_oneline(X509_get_subject_name(x), NULL, 0); + BIO_puts(out, "subject="); + BIO_puts(out, p); + free(p); + + p = X509_NAME_oneline(X509_get_issuer_name(x), NULL, 0); + BIO_puts(out, "\nissuer="); + BIO_puts(out, p); + BIO_puts(out, "\n"); + free(p); + + return 0; +} + +int +ui_open(UI *ui) +{ + return UI_method_get_opener(UI_OpenSSL()) (ui); +} + +int +ui_read(UI *ui, UI_STRING *uis) +{ + const char *password; + int string_type; + + if (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD && + UI_get0_user_data(ui)) { + string_type = UI_get_string_type(uis); + if (string_type == UIT_PROMPT || string_type == UIT_VERIFY) { + password = + ((PW_CB_DATA *)UI_get0_user_data(ui))->password; + if (password && password[0] != '\0') { + UI_set_result(ui, uis, password); + return 1; + } + } + } + return UI_method_get_reader(UI_OpenSSL()) (ui, uis); +} + +int +ui_write(UI *ui, UI_STRING *uis) +{ + const char *password; + int string_type; + + if (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD && + UI_get0_user_data(ui)) { + string_type = UI_get_string_type(uis); + if (string_type == UIT_PROMPT || string_type == UIT_VERIFY) { + password = + ((PW_CB_DATA *)UI_get0_user_data(ui))->password; + if (password && password[0] != '\0') + return 1; + } + } + return UI_method_get_writer(UI_OpenSSL()) (ui, uis); +} + +int +ui_close(UI *ui) +{ + return UI_method_get_closer(UI_OpenSSL()) (ui); +} + +int +password_callback(char *buf, int bufsiz, int verify, void *arg) +{ + PW_CB_DATA *cb_tmp = arg; + UI *ui = NULL; + int res = 0; + const char *prompt_info = NULL; + const char *password = NULL; + PW_CB_DATA *cb_data = (PW_CB_DATA *) cb_tmp; + + if (cb_data) { + if (cb_data->password) + password = cb_data->password; + if (cb_data->prompt_info) + prompt_info = cb_data->prompt_info; + } + if (password) { + res = strlen(password); + if (res > bufsiz) + res = bufsiz; + memcpy(buf, password, res); + return res; + } + ui = UI_new_method(ui_method); + if (ui) { + int ok = 0; + char *buff = NULL; + int ui_flags = 0; + char *prompt = NULL; + + prompt = UI_construct_prompt(ui, "pass phrase", prompt_info); + + ui_flags |= UI_INPUT_FLAG_DEFAULT_PWD; + UI_ctrl(ui, UI_CTRL_PRINT_ERRORS, 1, 0, 0); + + if (ok >= 0) + ok = UI_add_input_string(ui, prompt, ui_flags, buf, + PW_MIN_LENGTH, bufsiz - 1); + if (ok >= 0 && verify) { + buff = malloc(bufsiz); + ok = UI_add_verify_string(ui, prompt, ui_flags, buff, + PW_MIN_LENGTH, bufsiz - 1, buf); + } + if (ok >= 0) + do { + ok = UI_process(ui); + } while (ok < 0 && + UI_ctrl(ui, UI_CTRL_IS_REDOABLE, 0, 0, 0)); + + if (buff) { + explicit_bzero(buff, (unsigned int) bufsiz); + free(buff); + } + if (ok >= 0) + res = strlen(buf); + if (ok == -1) { + BIO_printf(bio_err, "User interface error\n"); + ERR_print_errors(bio_err); + explicit_bzero(buf, (unsigned int) bufsiz); + res = 0; + } + if (ok == -2) { + BIO_printf(bio_err, "aborted!\n"); + explicit_bzero(buf, (unsigned int) bufsiz); + res = 0; + } + UI_free(ui); + free(prompt); + } + return res; +} + +static char *app_get_pass(BIO *err, char *arg, int keepbio); + +int +app_passwd(BIO *err, char *arg1, char *arg2, char **pass1, char **pass2) +{ + int same; + + if (!arg2 || !arg1 || strcmp(arg1, arg2)) + same = 0; + else + same = 1; + if (arg1) { + *pass1 = app_get_pass(err, arg1, same); + if (!*pass1) + return 0; + } else if (pass1) + *pass1 = NULL; + if (arg2) { + *pass2 = app_get_pass(err, arg2, same ? 2 : 0); + if (!*pass2) + return 0; + } else if (pass2) + *pass2 = NULL; + return 1; +} + +static char * +app_get_pass(BIO *err, char *arg, int keepbio) +{ + char *tmp, tpass[APP_PASS_LEN]; + static BIO *pwdbio = NULL; + const char *errstr = NULL; + int i; + + if (!strncmp(arg, "pass:", 5)) + return strdup(arg + 5); + if (!strncmp(arg, "env:", 4)) { + tmp = getenv(arg + 4); + if (!tmp) { + BIO_printf(err, "Can't read environment variable %s\n", + arg + 4); + return NULL; + } + return strdup(tmp); + } + if (!keepbio || !pwdbio) { + if (!strncmp(arg, "file:", 5)) { + pwdbio = BIO_new_file(arg + 5, "r"); + if (!pwdbio) { + BIO_printf(err, "Can't open file %s\n", + arg + 5); + return NULL; + } + } else if (!strncmp(arg, "fd:", 3)) { + BIO *btmp; + i = strtonum(arg + 3, 0, INT_MAX, &errstr); + if (errstr) { + BIO_printf(err, + "Invalid file descriptor %s: %s\n", + arg, errstr); + return NULL; + } + pwdbio = BIO_new_fd(i, BIO_NOCLOSE); + if (!pwdbio) { + BIO_printf(err, + "Can't access file descriptor %s\n", + arg + 3); + return NULL; + } + /* + * Can't do BIO_gets on an fd BIO so add a buffering + * BIO + */ + btmp = BIO_new(BIO_f_buffer()); + pwdbio = BIO_push(btmp, pwdbio); + } else if (!strcmp(arg, "stdin")) { + pwdbio = BIO_new_fp(stdin, BIO_NOCLOSE); + if (!pwdbio) { + BIO_printf(err, "Can't open BIO for stdin\n"); + return NULL; + } + } else { + BIO_printf(err, "Invalid password argument \"%s\"\n", + arg); + return NULL; + } + } + i = BIO_gets(pwdbio, tpass, APP_PASS_LEN); + if (keepbio != 1) { + BIO_free_all(pwdbio); + pwdbio = NULL; + } + if (i <= 0) { + BIO_printf(err, "Error reading password from BIO\n"); + return NULL; + } + tmp = strchr(tpass, '\n'); + if (tmp) + *tmp = 0; + return strdup(tpass); +} + +int +add_oid_section(BIO *err, CONF *conf) +{ + char *p; + STACK_OF(CONF_VALUE) *sktmp; + CONF_VALUE *cnf; + int i; + + if (!(p = NCONF_get_string(conf, NULL, "oid_section"))) { + ERR_clear_error(); + return 1; + } + if (!(sktmp = NCONF_get_section(conf, p))) { + BIO_printf(err, "problem loading oid section %s\n", p); + return 0; + } + for (i = 0; i < sk_CONF_VALUE_num(sktmp); i++) { + cnf = sk_CONF_VALUE_value(sktmp, i); + if (OBJ_create(cnf->value, cnf->name, cnf->name) == NID_undef) { + BIO_printf(err, "problem creating object %s=%s\n", + cnf->name, cnf->value); + return 0; + } + } + return 1; +} + +static int +load_pkcs12(BIO *err, BIO *in, const char *desc, pem_password_cb *pem_cb, + void *cb_data, EVP_PKEY **pkey, X509 **cert, STACK_OF(X509) **ca) +{ + const char *pass; + char tpass[PEM_BUFSIZE]; + int len, ret = 0; + PKCS12 *p12; + + p12 = d2i_PKCS12_bio(in, NULL); + if (p12 == NULL) { + BIO_printf(err, "Error loading PKCS12 file for %s\n", desc); + goto die; + } + /* See if an empty password will do */ + if (PKCS12_verify_mac(p12, "", 0) || PKCS12_verify_mac(p12, NULL, 0)) + pass = ""; + else { + if (!pem_cb) + pem_cb = password_callback; + len = pem_cb(tpass, PEM_BUFSIZE, 0, cb_data); + if (len < 0) { + BIO_printf(err, "Passpharse callback error for %s\n", + desc); + goto die; + } + if (len < PEM_BUFSIZE) + tpass[len] = 0; + if (!PKCS12_verify_mac(p12, tpass, len)) { + BIO_printf(err, + "Mac verify error (wrong password?) in PKCS12 file for %s\n", desc); + goto die; + } + pass = tpass; + } + ret = PKCS12_parse(p12, pass, pkey, cert, ca); + +die: + if (p12) + PKCS12_free(p12); + return ret; +} + +X509 * +load_cert(BIO *err, const char *file, int format, const char *pass, + const char *cert_descrip) +{ + X509 *x = NULL; + BIO *cert; + + if ((cert = BIO_new(BIO_s_file())) == NULL) { + ERR_print_errors(err); + goto end; + } + if (file == NULL) { + setvbuf(stdin, NULL, _IONBF, 0); + BIO_set_fp(cert, stdin, BIO_NOCLOSE); + } else { + if (BIO_read_filename(cert, file) <= 0) { + BIO_printf(err, "Error opening %s %s\n", + cert_descrip, file); + ERR_print_errors(err); + goto end; + } + } + + if (format == FORMAT_ASN1) + x = d2i_X509_bio(cert, NULL); + else if (format == FORMAT_NETSCAPE) { + NETSCAPE_X509 *nx; + nx = ASN1_item_d2i_bio(&NETSCAPE_X509_it, + cert, NULL); + if (nx == NULL) + goto end; + + if ((strncmp(NETSCAPE_CERT_HDR, (char *) nx->header->data, + nx->header->length) != 0)) { + NETSCAPE_X509_free(nx); + BIO_printf(err, + "Error reading header on certificate\n"); + goto end; + } + x = nx->cert; + nx->cert = NULL; + NETSCAPE_X509_free(nx); + } else if (format == FORMAT_PEM) + x = PEM_read_bio_X509_AUX(cert, NULL, password_callback, NULL); + else if (format == FORMAT_PKCS12) { + if (!load_pkcs12(err, cert, cert_descrip, NULL, NULL, + NULL, &x, NULL)) + goto end; + } else { + BIO_printf(err, "bad input format specified for %s\n", + cert_descrip); + goto end; + } + +end: + if (x == NULL) { + BIO_printf(err, "unable to load certificate\n"); + ERR_print_errors(err); + } + BIO_free(cert); + return (x); +} + +EVP_PKEY * +load_key(BIO *err, const char *file, int format, int maybe_stdin, + const char *pass, const char *key_descrip) +{ + BIO *key = NULL; + EVP_PKEY *pkey = NULL; + PW_CB_DATA cb_data; + + cb_data.password = pass; + cb_data.prompt_info = file; + + if (file == NULL && (!maybe_stdin)) { + BIO_printf(err, "no keyfile specified\n"); + goto end; + } + key = BIO_new(BIO_s_file()); + if (key == NULL) { + ERR_print_errors(err); + goto end; + } + if (file == NULL && maybe_stdin) { + setvbuf(stdin, NULL, _IONBF, 0); + BIO_set_fp(key, stdin, BIO_NOCLOSE); + } else if (BIO_read_filename(key, file) <= 0) { + BIO_printf(err, "Error opening %s %s\n", + key_descrip, file); + ERR_print_errors(err); + goto end; + } + if (format == FORMAT_ASN1) { + pkey = d2i_PrivateKey_bio(key, NULL); + } else if (format == FORMAT_PEM) { + pkey = PEM_read_bio_PrivateKey(key, NULL, password_callback, &cb_data); + } +#if !defined(OPENSSL_NO_RC4) && !defined(OPENSSL_NO_RSA) + else if (format == FORMAT_NETSCAPE || format == FORMAT_IISSGC) + pkey = load_netscape_key(err, key, file, key_descrip, format); +#endif + else if (format == FORMAT_PKCS12) { + if (!load_pkcs12(err, key, key_descrip, password_callback, &cb_data, + &pkey, NULL, NULL)) + goto end; + } +#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DSA) && !defined (OPENSSL_NO_RC4) + else if (format == FORMAT_MSBLOB) + pkey = b2i_PrivateKey_bio(key); + else if (format == FORMAT_PVK) + pkey = b2i_PVK_bio(key, password_callback, + &cb_data); +#endif + else { + BIO_printf(err, "bad input format specified for key file\n"); + goto end; + } +end: + BIO_free(key); + if (pkey == NULL) { + BIO_printf(err, "unable to load %s\n", key_descrip); + ERR_print_errors(err); + } + return (pkey); +} + +EVP_PKEY * +load_pubkey(BIO *err, const char *file, int format, int maybe_stdin, + const char *pass, const char *key_descrip) +{ + BIO *key = NULL; + EVP_PKEY *pkey = NULL; + PW_CB_DATA cb_data; + + cb_data.password = pass; + cb_data.prompt_info = file; + + if (file == NULL && !maybe_stdin) { + BIO_printf(err, "no keyfile specified\n"); + goto end; + } + key = BIO_new(BIO_s_file()); + if (key == NULL) { + ERR_print_errors(err); + goto end; + } + if (file == NULL && maybe_stdin) { + setvbuf(stdin, NULL, _IONBF, 0); + BIO_set_fp(key, stdin, BIO_NOCLOSE); + } else if (BIO_read_filename(key, file) <= 0) { + BIO_printf(err, "Error opening %s %s\n", key_descrip, file); + ERR_print_errors(err); + goto end; + } + if (format == FORMAT_ASN1) { + pkey = d2i_PUBKEY_bio(key, NULL); + } + else if (format == FORMAT_ASN1RSA) { + RSA *rsa; + rsa = d2i_RSAPublicKey_bio(key, NULL); + if (rsa) { + pkey = EVP_PKEY_new(); + if (pkey) + EVP_PKEY_set1_RSA(pkey, rsa); + RSA_free(rsa); + } else + pkey = NULL; + } else if (format == FORMAT_PEMRSA) { + RSA *rsa; + rsa = PEM_read_bio_RSAPublicKey(key, NULL, password_callback, &cb_data); + if (rsa) { + pkey = EVP_PKEY_new(); + if (pkey) + EVP_PKEY_set1_RSA(pkey, rsa); + RSA_free(rsa); + } else + pkey = NULL; + } + else if (format == FORMAT_PEM) { + pkey = PEM_read_bio_PUBKEY(key, NULL, password_callback, &cb_data); + } +#if !defined(OPENSSL_NO_RC4) && !defined(OPENSSL_NO_RSA) + else if (format == FORMAT_NETSCAPE || format == FORMAT_IISSGC) + pkey = load_netscape_key(err, key, file, key_descrip, format); +#endif +#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DSA) + else if (format == FORMAT_MSBLOB) + pkey = b2i_PublicKey_bio(key); +#endif + else { + BIO_printf(err, "bad input format specified for key file\n"); + goto end; + } + +end: + BIO_free(key); + if (pkey == NULL) + BIO_printf(err, "unable to load %s\n", key_descrip); + return (pkey); +} + +#if !defined(OPENSSL_NO_RC4) && !defined(OPENSSL_NO_RSA) +static EVP_PKEY * +load_netscape_key(BIO *err, BIO *key, const char *file, + const char *key_descrip, int format) +{ + EVP_PKEY *pkey; + BUF_MEM *buf; + RSA *rsa; + const unsigned char *p; + int size, i; + + buf = BUF_MEM_new(); + pkey = EVP_PKEY_new(); + size = 0; + if (buf == NULL || pkey == NULL) + goto error; + for (;;) { + if (!BUF_MEM_grow_clean(buf, size + 1024 * 10)) + goto error; + i = BIO_read(key, &(buf->data[size]), 1024 * 10); + size += i; + if (i == 0) + break; + if (i < 0) { + BIO_printf(err, "Error reading %s %s", + key_descrip, file); + goto error; + } + } + p = (unsigned char *) buf->data; + rsa = d2i_RSA_NET(NULL, &p, (long) size, NULL, + (format == FORMAT_IISSGC ? 1 : 0)); + if (rsa == NULL) + goto error; + BUF_MEM_free(buf); + EVP_PKEY_set1_RSA(pkey, rsa); + return pkey; + +error: + BUF_MEM_free(buf); + EVP_PKEY_free(pkey); + return NULL; +} +#endif /* ndef OPENSSL_NO_RC4 */ + +static int +load_certs_crls(BIO *err, const char *file, int format, const char *pass, + const char *desc, STACK_OF(X509) **pcerts, + STACK_OF(X509_CRL) **pcrls) +{ + int i; + BIO *bio; + STACK_OF(X509_INFO) *xis = NULL; + X509_INFO *xi; + PW_CB_DATA cb_data; + int rv = 0; + + cb_data.password = pass; + cb_data.prompt_info = file; + + if (format != FORMAT_PEM) { + BIO_printf(err, "bad input format specified for %s\n", desc); + return 0; + } + if (file == NULL) + bio = BIO_new_fp(stdin, BIO_NOCLOSE); + else + bio = BIO_new_file(file, "r"); + + if (bio == NULL) { + BIO_printf(err, "Error opening %s %s\n", + desc, file ? file : "stdin"); + ERR_print_errors(err); + return 0; + } + xis = PEM_X509_INFO_read_bio(bio, NULL, password_callback, &cb_data); + + BIO_free(bio); + + if (pcerts) { + *pcerts = sk_X509_new_null(); + if (!*pcerts) + goto end; + } + if (pcrls) { + *pcrls = sk_X509_CRL_new_null(); + if (!*pcrls) + goto end; + } + for (i = 0; i < sk_X509_INFO_num(xis); i++) { + xi = sk_X509_INFO_value(xis, i); + if (xi->x509 && pcerts) { + if (!sk_X509_push(*pcerts, xi->x509)) + goto end; + xi->x509 = NULL; + } + if (xi->crl && pcrls) { + if (!sk_X509_CRL_push(*pcrls, xi->crl)) + goto end; + xi->crl = NULL; + } + } + + if (pcerts && sk_X509_num(*pcerts) > 0) + rv = 1; + + if (pcrls && sk_X509_CRL_num(*pcrls) > 0) + rv = 1; + +end: + if (xis) + sk_X509_INFO_pop_free(xis, X509_INFO_free); + + if (rv == 0) { + if (pcerts) { + sk_X509_pop_free(*pcerts, X509_free); + *pcerts = NULL; + } + if (pcrls) { + sk_X509_CRL_pop_free(*pcrls, X509_CRL_free); + *pcrls = NULL; + } + BIO_printf(err, "unable to load %s\n", + pcerts ? "certificates" : "CRLs"); + ERR_print_errors(err); + } + return rv; +} + +STACK_OF(X509) * +load_certs(BIO *err, const char *file, int format, const char *pass, + const char *desc) +{ + STACK_OF(X509) *certs; + + if (!load_certs_crls(err, file, format, pass, desc, &certs, NULL)) + return NULL; + return certs; +} + +STACK_OF(X509_CRL) * +load_crls(BIO *err, const char *file, int format, const char *pass, + const char *desc) +{ + STACK_OF(X509_CRL) *crls; + + if (!load_certs_crls(err, file, format, pass, desc, NULL, &crls)) + return NULL; + return crls; +} + +#define X509V3_EXT_UNKNOWN_MASK (0xfL << 16) +/* Return error for unknown extensions */ +#define X509V3_EXT_DEFAULT 0 +/* Print error for unknown extensions */ +#define X509V3_EXT_ERROR_UNKNOWN (1L << 16) +/* ASN1 parse unknown extensions */ +#define X509V3_EXT_PARSE_UNKNOWN (2L << 16) +/* BIO_dump unknown extensions */ +#define X509V3_EXT_DUMP_UNKNOWN (3L << 16) + +#define X509_FLAG_CA (X509_FLAG_NO_ISSUER | X509_FLAG_NO_PUBKEY | \ + X509_FLAG_NO_HEADER | X509_FLAG_NO_VERSION) + +int +set_cert_ex(unsigned long *flags, const char *arg) +{ + static const NAME_EX_TBL cert_tbl[] = { + {"compatible", X509_FLAG_COMPAT, 0xffffffffl}, + {"ca_default", X509_FLAG_CA, 0xffffffffl}, + {"no_header", X509_FLAG_NO_HEADER, 0}, + {"no_version", X509_FLAG_NO_VERSION, 0}, + {"no_serial", X509_FLAG_NO_SERIAL, 0}, + {"no_signame", X509_FLAG_NO_SIGNAME, 0}, + {"no_validity", X509_FLAG_NO_VALIDITY, 0}, + {"no_subject", X509_FLAG_NO_SUBJECT, 0}, + {"no_issuer", X509_FLAG_NO_ISSUER, 0}, + {"no_pubkey", X509_FLAG_NO_PUBKEY, 0}, + {"no_extensions", X509_FLAG_NO_EXTENSIONS, 0}, + {"no_sigdump", X509_FLAG_NO_SIGDUMP, 0}, + {"no_aux", X509_FLAG_NO_AUX, 0}, + {"no_attributes", X509_FLAG_NO_ATTRIBUTES, 0}, + {"ext_default", X509V3_EXT_DEFAULT, X509V3_EXT_UNKNOWN_MASK}, + {"ext_error", X509V3_EXT_ERROR_UNKNOWN, X509V3_EXT_UNKNOWN_MASK}, + {"ext_parse", X509V3_EXT_PARSE_UNKNOWN, X509V3_EXT_UNKNOWN_MASK}, + {"ext_dump", X509V3_EXT_DUMP_UNKNOWN, X509V3_EXT_UNKNOWN_MASK}, + {NULL, 0, 0} + }; + return set_multi_opts(flags, arg, cert_tbl); +} + +int +set_name_ex(unsigned long *flags, const char *arg) +{ + static const NAME_EX_TBL ex_tbl[] = { + {"esc_2253", ASN1_STRFLGS_ESC_2253, 0}, + {"esc_ctrl", ASN1_STRFLGS_ESC_CTRL, 0}, + {"esc_msb", ASN1_STRFLGS_ESC_MSB, 0}, + {"use_quote", ASN1_STRFLGS_ESC_QUOTE, 0}, + {"utf8", ASN1_STRFLGS_UTF8_CONVERT, 0}, + {"ignore_type", ASN1_STRFLGS_IGNORE_TYPE, 0}, + {"show_type", ASN1_STRFLGS_SHOW_TYPE, 0}, + {"dump_all", ASN1_STRFLGS_DUMP_ALL, 0}, + {"dump_nostr", ASN1_STRFLGS_DUMP_UNKNOWN, 0}, + {"dump_der", ASN1_STRFLGS_DUMP_DER, 0}, + {"compat", XN_FLAG_COMPAT, 0xffffffffL}, + {"sep_comma_plus", XN_FLAG_SEP_COMMA_PLUS, XN_FLAG_SEP_MASK}, + {"sep_comma_plus_space", XN_FLAG_SEP_CPLUS_SPC, XN_FLAG_SEP_MASK}, + {"sep_semi_plus_space", XN_FLAG_SEP_SPLUS_SPC, XN_FLAG_SEP_MASK}, + {"sep_multiline", XN_FLAG_SEP_MULTILINE, XN_FLAG_SEP_MASK}, + {"dn_rev", XN_FLAG_DN_REV, 0}, + {"nofname", XN_FLAG_FN_NONE, XN_FLAG_FN_MASK}, + {"sname", XN_FLAG_FN_SN, XN_FLAG_FN_MASK}, + {"lname", XN_FLAG_FN_LN, XN_FLAG_FN_MASK}, + {"align", XN_FLAG_FN_ALIGN, 0}, + {"oid", XN_FLAG_FN_OID, XN_FLAG_FN_MASK}, + {"space_eq", XN_FLAG_SPC_EQ, 0}, + {"dump_unknown", XN_FLAG_DUMP_UNKNOWN_FIELDS, 0}, + {"RFC2253", XN_FLAG_RFC2253, 0xffffffffL}, + {"oneline", XN_FLAG_ONELINE, 0xffffffffL}, + {"multiline", XN_FLAG_MULTILINE, 0xffffffffL}, + {"ca_default", XN_FLAG_MULTILINE, 0xffffffffL}, + {NULL, 0, 0} + }; + return set_multi_opts(flags, arg, ex_tbl); +} + +int +set_ext_copy(int *copy_type, const char *arg) +{ + if (!strcasecmp(arg, "none")) + *copy_type = EXT_COPY_NONE; + else if (!strcasecmp(arg, "copy")) + *copy_type = EXT_COPY_ADD; + else if (!strcasecmp(arg, "copyall")) + *copy_type = EXT_COPY_ALL; + else + return 0; + return 1; +} + +int +copy_extensions(X509 *x, X509_REQ *req, int copy_type) +{ + STACK_OF(X509_EXTENSION) *exts = NULL; + X509_EXTENSION *ext, *tmpext; + ASN1_OBJECT *obj; + int i, idx, ret = 0; + + if (!x || !req || (copy_type == EXT_COPY_NONE)) + return 1; + exts = X509_REQ_get_extensions(req); + + for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) { + ext = sk_X509_EXTENSION_value(exts, i); + obj = X509_EXTENSION_get_object(ext); + idx = X509_get_ext_by_OBJ(x, obj, -1); + /* Does extension exist? */ + if (idx != -1) { + /* If normal copy don't override existing extension */ + if (copy_type == EXT_COPY_ADD) + continue; + /* Delete all extensions of same type */ + do { + tmpext = X509_get_ext(x, idx); + X509_delete_ext(x, idx); + X509_EXTENSION_free(tmpext); + idx = X509_get_ext_by_OBJ(x, obj, -1); + } while (idx != -1); + } + if (!X509_add_ext(x, ext, -1)) + goto end; + } + + ret = 1; + +end: + sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); + + return ret; +} + +static int +set_multi_opts(unsigned long *flags, const char *arg, + const NAME_EX_TBL *in_tbl) +{ + STACK_OF(CONF_VALUE) *vals; + CONF_VALUE *val; + int i, ret = 1; + + if (!arg) + return 0; + vals = X509V3_parse_list(arg); + for (i = 0; i < sk_CONF_VALUE_num(vals); i++) { + val = sk_CONF_VALUE_value(vals, i); + if (!set_table_opts(flags, val->name, in_tbl)) + ret = 0; + } + sk_CONF_VALUE_pop_free(vals, X509V3_conf_free); + return ret; +} + +static int +set_table_opts(unsigned long *flags, const char *arg, + const NAME_EX_TBL *in_tbl) +{ + char c; + const NAME_EX_TBL *ptbl; + + c = arg[0]; + if (c == '-') { + c = 0; + arg++; + } else if (c == '+') { + c = 1; + arg++; + } else + c = 1; + + for (ptbl = in_tbl; ptbl->name; ptbl++) { + if (!strcasecmp(arg, ptbl->name)) { + *flags &= ~ptbl->mask; + if (c) + *flags |= ptbl->flag; + else + *flags &= ~ptbl->flag; + return 1; + } + } + return 0; +} + +void +print_name(BIO *out, const char *title, X509_NAME *nm, unsigned long lflags) +{ + char *buf; + char mline = 0; + int indent = 0; + + if (title) + BIO_puts(out, title); + if ((lflags & XN_FLAG_SEP_MASK) == XN_FLAG_SEP_MULTILINE) { + mline = 1; + indent = 4; + } + if (lflags == XN_FLAG_COMPAT) { + buf = X509_NAME_oneline(nm, 0, 0); + BIO_puts(out, buf); + BIO_puts(out, "\n"); + free(buf); + } else { + if (mline) + BIO_puts(out, "\n"); + X509_NAME_print_ex(out, nm, indent, lflags); + BIO_puts(out, "\n"); + } +} + +X509_STORE * +setup_verify(BIO *bp, char *CAfile, char *CApath) +{ + X509_STORE *store; + X509_LOOKUP *lookup; + + if (!(store = X509_STORE_new())) + goto end; + lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); + if (lookup == NULL) + goto end; + if (CAfile) { + if (!X509_LOOKUP_load_file(lookup, CAfile, X509_FILETYPE_PEM)) { + BIO_printf(bp, "Error loading file %s\n", CAfile); + goto end; + } + } else + X509_LOOKUP_load_file(lookup, NULL, X509_FILETYPE_DEFAULT); + + lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir()); + if (lookup == NULL) + goto end; + if (CApath) { + if (!X509_LOOKUP_add_dir(lookup, CApath, X509_FILETYPE_PEM)) { + BIO_printf(bp, "Error loading directory %s\n", CApath); + goto end; + } + } else + X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT); + + ERR_clear_error(); + return store; + +end: + X509_STORE_free(store); + return NULL; +} + +int +load_config(BIO *err, CONF *cnf) +{ + static int load_config_called = 0; + + if (load_config_called) + return 1; + load_config_called = 1; + if (cnf == NULL) + cnf = config; + if (cnf == NULL) + return 1; + + OPENSSL_load_builtin_modules(); + + if (CONF_modules_load(cnf, NULL, 0) <= 0) { + BIO_printf(err, "Error configuring OpenSSL\n"); + ERR_print_errors(err); + return 0; + } + return 1; +} + +char * +make_config_name() +{ + const char *t = X509_get_default_cert_area(); + char *p; + + if (asprintf(&p, "%s/openssl.cnf", t) == -1) + return NULL; + return p; +} + +static unsigned long +index_serial_hash(const OPENSSL_CSTRING *a) +{ + const char *n; + + n = a[DB_serial]; + while (*n == '0') + n++; + return (lh_strhash(n)); +} + +static int +index_serial_cmp(const OPENSSL_CSTRING *a, const OPENSSL_CSTRING *b) +{ + const char *aa, *bb; + + for (aa = a[DB_serial]; *aa == '0'; aa++) + ; + for (bb = b[DB_serial]; *bb == '0'; bb++) + ; + return (strcmp(aa, bb)); +} + +static int +index_name_qual(char **a) +{ + return (a[0][0] == 'V'); +} + +static unsigned long +index_name_hash(const OPENSSL_CSTRING *a) +{ + return (lh_strhash(a[DB_name])); +} + +int +index_name_cmp(const OPENSSL_CSTRING *a, const OPENSSL_CSTRING *b) +{ + return (strcmp(a[DB_name], b[DB_name])); +} + +static IMPLEMENT_LHASH_HASH_FN(index_serial, OPENSSL_CSTRING) +static IMPLEMENT_LHASH_COMP_FN(index_serial, OPENSSL_CSTRING) +static IMPLEMENT_LHASH_HASH_FN(index_name, OPENSSL_CSTRING) +static IMPLEMENT_LHASH_COMP_FN(index_name, OPENSSL_CSTRING) + +BIGNUM * +load_serial(char *serialfile, int create, ASN1_INTEGER **retai) +{ + BIO *in = NULL; + BIGNUM *ret = NULL; + char buf[1024]; + ASN1_INTEGER *ai = NULL; + + ai = ASN1_INTEGER_new(); + if (ai == NULL) + goto err; + + if ((in = BIO_new(BIO_s_file())) == NULL) { + ERR_print_errors(bio_err); + goto err; + } + if (BIO_read_filename(in, serialfile) <= 0) { + if (!create) { + perror(serialfile); + goto err; + } else { + ret = BN_new(); + if (ret == NULL || !rand_serial(ret, ai)) + BIO_printf(bio_err, "Out of memory\n"); + } + } else { + if (!a2i_ASN1_INTEGER(in, ai, buf, sizeof buf)) { + BIO_printf(bio_err, "unable to load number from %s\n", + serialfile); + goto err; + } + ret = ASN1_INTEGER_to_BN(ai, NULL); + if (ret == NULL) { + BIO_printf(bio_err, + "error converting number from bin to BIGNUM\n"); + goto err; + } + } + + if (ret && retai) { + *retai = ai; + ai = NULL; + } + +err: + if (in != NULL) + BIO_free(in); + if (ai != NULL) + ASN1_INTEGER_free(ai); + return (ret); +} + +int +save_serial(char *serialfile, char *suffix, BIGNUM *serial, + ASN1_INTEGER **retai) +{ + char serialpath[PATH_MAX]; + BIO *out = NULL; + int ret = 0, n; + ASN1_INTEGER *ai = NULL; + + if (suffix == NULL) + n = strlcpy(serialpath, serialfile, sizeof serialpath); + else + n = snprintf(serialpath, sizeof serialpath, "%s.%s", + serialfile, suffix); + if (n == -1 || n >= sizeof(serialpath)) { + BIO_printf(bio_err, "serial too long\n"); + goto err; + } + out = BIO_new(BIO_s_file()); + if (out == NULL) { + ERR_print_errors(bio_err); + goto err; + } + if (BIO_write_filename(out, serialpath) <= 0) { + perror(serialfile); + goto err; + } + if ((ai = BN_to_ASN1_INTEGER(serial, NULL)) == NULL) { + BIO_printf(bio_err, + "error converting serial to ASN.1 format\n"); + goto err; + } + i2a_ASN1_INTEGER(out, ai); + BIO_puts(out, "\n"); + ret = 1; + if (retai) { + *retai = ai; + ai = NULL; + } + +err: + if (out != NULL) + BIO_free_all(out); + if (ai != NULL) + ASN1_INTEGER_free(ai); + return (ret); +} + +int +rotate_serial(char *serialfile, char *new_suffix, char *old_suffix) +{ + char opath[PATH_MAX], npath[PATH_MAX]; + + if (snprintf(npath, sizeof npath, "%s.%s", serialfile, + new_suffix) >= sizeof npath) { + BIO_printf(bio_err, "file name too long\n"); + goto err; + } + + if (snprintf(opath, sizeof opath, "%s.%s", serialfile, + old_suffix) >= sizeof opath) { + BIO_printf(bio_err, "file name too long\n"); + goto err; + } + + if (rename(serialfile, opath) < 0 && + errno != ENOENT && errno != ENOTDIR) { + BIO_printf(bio_err, "unable to rename %s to %s\n", + serialfile, opath); + perror("reason"); + goto err; + } + + + if (rename(npath, serialfile) < 0) { + BIO_printf(bio_err, "unable to rename %s to %s\n", + npath, serialfile); + perror("reason"); + if (rename(opath, serialfile) < 0) { + BIO_printf(bio_err, "unable to rename %s to %s\n", + opath, serialfile); + perror("reason"); + } + goto err; + } + return 1; + +err: + return 0; +} + +int +rand_serial(BIGNUM *b, ASN1_INTEGER *ai) +{ + BIGNUM *btmp; + int ret = 0; + + if (b) + btmp = b; + else + btmp = BN_new(); + + if (!btmp) + return 0; + + if (!BN_pseudo_rand(btmp, SERIAL_RAND_BITS, 0, 0)) + goto error; + if (ai && !BN_to_ASN1_INTEGER(btmp, ai)) + goto error; + + ret = 1; + +error: + if (!b) + BN_free(btmp); + + return ret; +} + +CA_DB * +load_index(char *dbfile, DB_ATTR *db_attr) +{ + CA_DB *retdb = NULL; + TXT_DB *tmpdb = NULL; + BIO *in = BIO_new(BIO_s_file()); + CONF *dbattr_conf = NULL; + char attrpath[PATH_MAX]; + long errorline = -1; + + if (in == NULL) { + ERR_print_errors(bio_err); + goto err; + } + if (BIO_read_filename(in, dbfile) <= 0) { + perror(dbfile); + BIO_printf(bio_err, "unable to open '%s'\n", dbfile); + goto err; + } + if ((tmpdb = TXT_DB_read(in, DB_NUMBER)) == NULL) + goto err; + + if (snprintf(attrpath, sizeof attrpath, "%s.attr", dbfile) + >= sizeof attrpath) { + BIO_printf(bio_err, "attr filename too long\n"); + goto err; + } + + dbattr_conf = NCONF_new(NULL); + if (NCONF_load(dbattr_conf, attrpath, &errorline) <= 0) { + if (errorline > 0) { + BIO_printf(bio_err, + "error on line %ld of db attribute file '%s'\n", + errorline, attrpath); + goto err; + } else { + NCONF_free(dbattr_conf); + dbattr_conf = NULL; + } + } + if ((retdb = malloc(sizeof(CA_DB))) == NULL) { + fprintf(stderr, "Out of memory\n"); + goto err; + } + retdb->db = tmpdb; + tmpdb = NULL; + if (db_attr) + retdb->attributes = *db_attr; + else { + retdb->attributes.unique_subject = 1; + } + + if (dbattr_conf) { + char *p = NCONF_get_string(dbattr_conf, NULL, "unique_subject"); + if (p) { + retdb->attributes.unique_subject = parse_yesno(p, 1); + } + } + +err: + if (dbattr_conf) + NCONF_free(dbattr_conf); + if (tmpdb) + TXT_DB_free(tmpdb); + if (in) + BIO_free_all(in); + return retdb; +} + +int +index_index(CA_DB *db) +{ + if (!TXT_DB_create_index(db->db, DB_serial, NULL, + LHASH_HASH_FN(index_serial), LHASH_COMP_FN(index_serial))) { + BIO_printf(bio_err, + "error creating serial number index:(%ld,%ld,%ld)\n", + db->db->error, db->db->arg1, db->db->arg2); + return 0; + } + if (db->attributes.unique_subject && + !TXT_DB_create_index(db->db, DB_name, index_name_qual, + LHASH_HASH_FN(index_name), LHASH_COMP_FN(index_name))) { + BIO_printf(bio_err, "error creating name index:(%ld,%ld,%ld)\n", + db->db->error, db->db->arg1, db->db->arg2); + return 0; + } + return 1; +} + +int +save_index(const char *file, const char *suffix, CA_DB *db) +{ + char attrpath[PATH_MAX], dbfile[PATH_MAX]; + BIO *out = BIO_new(BIO_s_file()); + int j; + + if (out == NULL) { + ERR_print_errors(bio_err); + goto err; + } + if (snprintf(attrpath, sizeof attrpath, "%s.attr.%s", + file, suffix) >= sizeof attrpath) { + BIO_printf(bio_err, "file name too long\n"); + goto err; + } + if (snprintf(dbfile, sizeof dbfile, "%s.%s", + file, suffix) >= sizeof dbfile) { + BIO_printf(bio_err, "file name too long\n"); + goto err; + } + + if (BIO_write_filename(out, dbfile) <= 0) { + perror(dbfile); + BIO_printf(bio_err, "unable to open '%s'\n", dbfile); + goto err; + } + j = TXT_DB_write(out, db->db); + if (j <= 0) + goto err; + + BIO_free(out); + + out = BIO_new(BIO_s_file()); + + if (BIO_write_filename(out, attrpath) <= 0) { + perror(attrpath); + BIO_printf(bio_err, "unable to open '%s'\n", attrpath); + goto err; + } + BIO_printf(out, "unique_subject = %s\n", + db->attributes.unique_subject ? "yes" : "no"); + BIO_free(out); + + return 1; + +err: + return 0; +} + +int +rotate_index(const char *dbfile, const char *new_suffix, const char *old_suffix) +{ + char attrpath[PATH_MAX], nattrpath[PATH_MAX], oattrpath[PATH_MAX]; + char dbpath[PATH_MAX], odbpath[PATH_MAX]; + + if (snprintf(attrpath, sizeof attrpath, "%s.attr", + dbfile) >= sizeof attrpath) { + BIO_printf(bio_err, "file name too long\n"); + goto err; + } + if (snprintf(nattrpath, sizeof nattrpath, "%s.attr.%s", + dbfile, new_suffix) >= sizeof nattrpath) { + BIO_printf(bio_err, "file name too long\n"); + goto err; + } + if (snprintf(oattrpath, sizeof oattrpath, "%s.attr.%s", + dbfile, old_suffix) >= sizeof oattrpath) { + BIO_printf(bio_err, "file name too long\n"); + goto err; + } + if (snprintf(dbpath, sizeof dbpath, "%s.%s", + dbfile, new_suffix) >= sizeof dbpath) { + BIO_printf(bio_err, "file name too long\n"); + goto err; + } + if (snprintf(odbpath, sizeof odbpath, "%s.%s", + dbfile, old_suffix) >= sizeof odbpath) { + BIO_printf(bio_err, "file name too long\n"); + goto err; + } + + if (rename(dbfile, odbpath) < 0 && errno != ENOENT && errno != ENOTDIR) { + BIO_printf(bio_err, "unable to rename %s to %s\n", + dbfile, odbpath); + perror("reason"); + goto err; + } + + if (rename(dbpath, dbfile) < 0) { + BIO_printf(bio_err, "unable to rename %s to %s\n", + dbpath, dbfile); + perror("reason"); + if (rename(odbpath, dbfile) < 0) { + BIO_printf(bio_err, "unable to rename %s to %s\n", + odbpath, dbfile); + perror("reason"); + } + goto err; + } + + if (rename(attrpath, oattrpath) < 0 && errno != ENOENT && errno != ENOTDIR) { + BIO_printf(bio_err, "unable to rename %s to %s\n", + attrpath, oattrpath); + perror("reason"); + if (rename(dbfile, dbpath) < 0) { + BIO_printf(bio_err, "unable to rename %s to %s\n", + dbfile, dbpath); + perror("reason"); + } + if (rename(odbpath, dbfile) < 0) { + BIO_printf(bio_err, "unable to rename %s to %s\n", + odbpath, dbfile); + perror("reason"); + } + goto err; + } + + if (rename(nattrpath, attrpath) < 0) { + BIO_printf(bio_err, "unable to rename %s to %s\n", + nattrpath, attrpath); + perror("reason"); + if (rename(oattrpath, attrpath) < 0) { + BIO_printf(bio_err, "unable to rename %s to %s\n", + oattrpath, attrpath); + perror("reason"); + } + if (rename(dbfile, dbpath) < 0) { + BIO_printf(bio_err, "unable to rename %s to %s\n", + dbfile, dbpath); + perror("reason"); + } + if (rename(odbpath, dbfile) < 0) { + BIO_printf(bio_err, "unable to rename %s to %s\n", + odbpath, dbfile); + perror("reason"); + } + goto err; + } + return 1; + +err: + return 0; +} + +void +free_index(CA_DB *db) +{ + if (db) { + if (db->db) + TXT_DB_free(db->db); + free(db); + } +} + +int +parse_yesno(const char *str, int def) +{ + int ret = def; + + if (str) { + switch (*str) { + case 'f': /* false */ + case 'F': /* FALSE */ + case 'n': /* no */ + case 'N': /* NO */ + case '0': /* 0 */ + ret = 0; + break; + case 't': /* true */ + case 'T': /* TRUE */ + case 'y': /* yes */ + case 'Y': /* YES */ + case '1': /* 1 */ + ret = 1; + break; + default: + ret = def; + break; + } + } + return ret; +} + +/* + * subject is expected to be in the format /type0=value0/type1=value1/type2=... + * where characters may be escaped by \ + */ +X509_NAME * +parse_name(char *subject, long chtype, int multirdn) +{ + X509_NAME *name = NULL; + size_t buflen, max_ne; + char **ne_types, **ne_values; + char *buf, *bp, *sp; + int i, nid, ne_num = 0; + int *mval; + + /* + * Buffer to copy the types and values into. Due to escaping the + * copy can only become shorter. + */ + buflen = strlen(subject) + 1; + buf = malloc(buflen); + + /* Maximum number of name elements. */ + max_ne = buflen / 2 + 1; + ne_types = reallocarray(NULL, max_ne, sizeof(char *)); + ne_values = reallocarray(NULL, max_ne, sizeof(char *)); + mval = reallocarray(NULL, max_ne, sizeof(int)); + + if (buf == NULL || ne_types == NULL || ne_values == NULL || + mval == NULL) { + BIO_printf(bio_err, "malloc error\n"); + goto error; + } + + bp = buf; + sp = subject; + + if (*subject != '/') { + BIO_printf(bio_err, "Subject does not start with '/'.\n"); + goto error; + } + + /* Skip leading '/'. */ + sp++; + + /* No multivalued RDN by default. */ + mval[ne_num] = 0; + + while (*sp) { + /* Collect type. */ + ne_types[ne_num] = bp; + while (*sp) { + /* is there anything to escape in the type...? */ + if (*sp == '\\') { + if (*++sp) + *bp++ = *sp++; + else { + BIO_printf(bio_err, "escape character " + "at end of string\n"); + goto error; + } + } else if (*sp == '=') { + sp++; + *bp++ = '\0'; + break; + } else + *bp++ = *sp++; + } + if (!*sp) { + BIO_printf(bio_err, "end of string encountered while " + "processing type of subject name element #%d\n", + ne_num); + goto error; + } + ne_values[ne_num] = bp; + while (*sp) { + if (*sp == '\\') { + if (*++sp) + *bp++ = *sp++; + else { + BIO_printf(bio_err, "escape character " + "at end of string\n"); + goto error; + } + } else if (*sp == '/') { + sp++; + /* no multivalued RDN by default */ + mval[ne_num + 1] = 0; + break; + } else if (*sp == '+' && multirdn) { + /* a not escaped + signals a multivalued RDN */ + sp++; + mval[ne_num + 1] = -1; + break; + } else + *bp++ = *sp++; + } + *bp++ = '\0'; + ne_num++; + } + + if ((name = X509_NAME_new()) == NULL) + goto error; + + for (i = 0; i < ne_num; i++) { + if ((nid = OBJ_txt2nid(ne_types[i])) == NID_undef) { + BIO_printf(bio_err, + "Subject Attribute %s has no known NID, skipped\n", + ne_types[i]); + continue; + } + if (!*ne_values[i]) { + BIO_printf(bio_err, "No value provided for Subject " + "Attribute %s, skipped\n", ne_types[i]); + continue; + } + if (!X509_NAME_add_entry_by_NID(name, nid, chtype, + (unsigned char *) ne_values[i], -1, -1, mval[i])) + goto error; + } + goto done; + +error: + X509_NAME_free(name); + name = NULL; + +done: + free(ne_values); + free(ne_types); + free(mval); + free(buf); + + return name; +} + +int +args_verify(char ***pargs, int *pargc, int *badarg, BIO *err, + X509_VERIFY_PARAM **pm) +{ + ASN1_OBJECT *otmp = NULL; + unsigned long flags = 0; + int i; + int purpose = 0, depth = -1; + char **oldargs = *pargs; + char *arg = **pargs, *argn = (*pargs)[1]; + time_t at_time = 0; + const char *errstr = NULL; + + if (!strcmp(arg, "-policy")) { + if (!argn) + *badarg = 1; + else { + otmp = OBJ_txt2obj(argn, 0); + if (!otmp) { + BIO_printf(err, "Invalid Policy \"%s\"\n", + argn); + *badarg = 1; + } + } + (*pargs)++; + } else if (strcmp(arg, "-purpose") == 0) { + X509_PURPOSE *xptmp; + if (!argn) + *badarg = 1; + else { + i = X509_PURPOSE_get_by_sname(argn); + if (i < 0) { + BIO_printf(err, "unrecognized purpose\n"); + *badarg = 1; + } else { + xptmp = X509_PURPOSE_get0(i); + purpose = X509_PURPOSE_get_id(xptmp); + } + } + (*pargs)++; + } else if (strcmp(arg, "-verify_depth") == 0) { + if (!argn) + *badarg = 1; + else { + depth = strtonum(argn, 1, INT_MAX, &errstr); + if (errstr) { + BIO_printf(err, "invalid depth %s: %s\n", + argn, errstr); + *badarg = 1; + } + } + (*pargs)++; + } else if (strcmp(arg, "-attime") == 0) { + if (!argn) + *badarg = 1; + else { + long long timestamp; + /* + * interpret the -attime argument as seconds since + * Epoch + */ + if (sscanf(argn, "%lli", ×tamp) != 1) { + BIO_printf(bio_err, + "Error parsing timestamp %s\n", + argn); + *badarg = 1; + } + /* XXX 2038 truncation */ + at_time = (time_t) timestamp; + } + (*pargs)++; + } else if (!strcmp(arg, "-ignore_critical")) + flags |= X509_V_FLAG_IGNORE_CRITICAL; + else if (!strcmp(arg, "-issuer_checks")) + flags |= X509_V_FLAG_CB_ISSUER_CHECK; + else if (!strcmp(arg, "-crl_check")) + flags |= X509_V_FLAG_CRL_CHECK; + else if (!strcmp(arg, "-crl_check_all")) + flags |= X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL; + else if (!strcmp(arg, "-policy_check")) + flags |= X509_V_FLAG_POLICY_CHECK; + else if (!strcmp(arg, "-explicit_policy")) + flags |= X509_V_FLAG_EXPLICIT_POLICY; + else if (!strcmp(arg, "-inhibit_any")) + flags |= X509_V_FLAG_INHIBIT_ANY; + else if (!strcmp(arg, "-inhibit_map")) + flags |= X509_V_FLAG_INHIBIT_MAP; + else if (!strcmp(arg, "-x509_strict")) + flags |= X509_V_FLAG_X509_STRICT; + else if (!strcmp(arg, "-extended_crl")) + flags |= X509_V_FLAG_EXTENDED_CRL_SUPPORT; + else if (!strcmp(arg, "-use_deltas")) + flags |= X509_V_FLAG_USE_DELTAS; + else if (!strcmp(arg, "-policy_print")) + flags |= X509_V_FLAG_NOTIFY_POLICY; + else if (!strcmp(arg, "-check_ss_sig")) + flags |= X509_V_FLAG_CHECK_SS_SIGNATURE; + else + return 0; + + if (*badarg) { + if (*pm) + X509_VERIFY_PARAM_free(*pm); + *pm = NULL; + goto end; + } + if (!*pm && !(*pm = X509_VERIFY_PARAM_new())) { + *badarg = 1; + goto end; + } + if (otmp) { + X509_VERIFY_PARAM_add0_policy(*pm, otmp); + otmp = NULL; + } + if (flags) + X509_VERIFY_PARAM_set_flags(*pm, flags); + + if (purpose) + X509_VERIFY_PARAM_set_purpose(*pm, purpose); + + if (depth >= 0) + X509_VERIFY_PARAM_set_depth(*pm, depth); + + if (at_time) + X509_VERIFY_PARAM_set_time(*pm, at_time); + +end: + (*pargs)++; + + if (pargc) + *pargc -= *pargs - oldargs; + + ASN1_OBJECT_free(otmp); + return 1; +} + +/* Read whole contents of a BIO into an allocated memory buffer and + * return it. + */ + +int +bio_to_mem(unsigned char **out, int maxlen, BIO *in) +{ + BIO *mem; + int len, ret; + unsigned char tbuf[1024]; + + mem = BIO_new(BIO_s_mem()); + if (!mem) + return -1; + for (;;) { + if ((maxlen != -1) && maxlen < 1024) + len = maxlen; + else + len = 1024; + len = BIO_read(in, tbuf, len); + if (len <= 0) + break; + if (BIO_write(mem, tbuf, len) != len) { + BIO_free(mem); + return -1; + } + maxlen -= len; + + if (maxlen == 0) + break; + } + ret = BIO_get_mem_data(mem, (char **) out); + BIO_set_flags(mem, BIO_FLAGS_MEM_RDONLY); + BIO_free(mem); + return ret; +} + +int +pkey_ctrl_string(EVP_PKEY_CTX *ctx, char *value) +{ + int rv; + char *stmp, *vtmp = NULL; + + if (value == NULL) + return -1; + stmp = strdup(value); + if (!stmp) + return -1; + vtmp = strchr(stmp, ':'); + if (vtmp) { + *vtmp = 0; + vtmp++; + } + rv = EVP_PKEY_CTX_ctrl_str(ctx, stmp, vtmp); + free(stmp); + + return rv; +} + +static void +nodes_print(BIO *out, const char *name, STACK_OF(X509_POLICY_NODE) *nodes) +{ + X509_POLICY_NODE *node; + int i; + + BIO_printf(out, "%s Policies:", name); + if (nodes) { + BIO_puts(out, "\n"); + for (i = 0; i < sk_X509_POLICY_NODE_num(nodes); i++) { + node = sk_X509_POLICY_NODE_value(nodes, i); + X509_POLICY_NODE_print(out, node, 2); + } + } else + BIO_puts(out, " \n"); +} + +void +policies_print(BIO *out, X509_STORE_CTX *ctx) +{ + X509_POLICY_TREE *tree; + int explicit_policy; + int free_out = 0; + + if (out == NULL) { + out = BIO_new_fp(stderr, BIO_NOCLOSE); + free_out = 1; + } + tree = X509_STORE_CTX_get0_policy_tree(ctx); + explicit_policy = X509_STORE_CTX_get_explicit_policy(ctx); + + BIO_printf(out, "Require explicit Policy: %s\n", + explicit_policy ? "True" : "False"); + + nodes_print(out, "Authority", X509_policy_tree_get0_policies(tree)); + nodes_print(out, "User", X509_policy_tree_get0_user_policies(tree)); + if (free_out) + BIO_free(out); +} + +/* next_protos_parse parses a comma separated list of strings into a string + * in a format suitable for passing to SSL_CTX_set_next_protos_advertised. + * outlen: (output) set to the length of the resulting buffer on success. + * err: (maybe NULL) on failure, an error message line is written to this BIO. + * in: a NUL termianted string like "abc,def,ghi" + * + * returns: a malloced buffer or NULL on failure. + */ +unsigned char * +next_protos_parse(unsigned short *outlen, const char *in) +{ + size_t len; + unsigned char *out; + size_t i, start = 0; + + len = strlen(in); + if (len >= 65535) + return NULL; + + out = malloc(strlen(in) + 1); + if (!out) + return NULL; + + for (i = 0; i <= len; ++i) { + if (i == len || in[i] == ',') { + if (i - start > 255) { + free(out); + return NULL; + } + out[start] = i - start; + start = i + 1; + } else + out[i + 1] = in[i]; + } + + *outlen = len + 1; + return out; +} + +int +app_isdir(const char *name) +{ + struct stat st; + + if (stat(name, &st) == 0) + return S_ISDIR(st.st_mode); + return -1; +} + +#define OPTION_WIDTH 18 + +void +options_usage(struct option *opts) +{ + const char *p, *q; + char optstr[32]; + int i; + + for (i = 0; opts[i].name != NULL; i++) { + if (opts[i].desc == NULL) + continue; + + snprintf(optstr, sizeof(optstr), "-%s %s", opts[i].name, + (opts[i].argname != NULL) ? opts[i].argname : ""); + fprintf(stderr, " %-*s", OPTION_WIDTH, optstr); + if (strlen(optstr) > OPTION_WIDTH) + fprintf(stderr, "\n %-*s", OPTION_WIDTH, ""); + + p = opts[i].desc; + while ((q = strchr(p, '\n')) != NULL) { + fprintf(stderr, " %.*s", (int)(q - p), p); + fprintf(stderr, "\n %-*s", OPTION_WIDTH, ""); + p = q + 1; + } + fprintf(stderr, " %s\n", p); + } +} + +int +options_parse(int argc, char **argv, struct option *opts, char **unnamed, + int *argsused) +{ + const char *errstr; + struct option *opt; + long long val; + char *arg, *p; + int fmt, used; + int ord = 0; + int i, j; + + if (unnamed != NULL) + *unnamed = NULL; + + for (i = 1; i < argc; i++) { + p = arg = argv[i]; + + /* Single unnamed argument (without leading hyphen). */ + if (*p++ != '-') { + if (argsused != NULL) + goto done; + if (unnamed == NULL) + goto unknown; + if (*unnamed != NULL) + goto toomany; + *unnamed = arg; + continue; + } + + /* End of named options (single hyphen). */ + if (*p == '\0') { + if (++i >= argc) + goto done; + if (argsused != NULL) + goto done; + if (unnamed != NULL && i == argc - 1) { + if (*unnamed != NULL) + goto toomany; + *unnamed = argv[i]; + continue; + } + goto unknown; + } + + /* See if there is a matching option... */ + for (j = 0; opts[j].name != NULL; j++) { + if (strcmp(p, opts[j].name) == 0) + break; + } + opt = &opts[j]; + if (opt->name == NULL && opt->type == 0) + goto unknown; + + if (opt->type == OPTION_ARG || + opt->type == OPTION_ARG_FORMAT || + opt->type == OPTION_ARG_FUNC || + opt->type == OPTION_ARG_INT || + opt->type == OPTION_ARG_LONG || + opt->type == OPTION_ARG_TIME) { + if (++i >= argc) { + fprintf(stderr, "missing %s argument for -%s\n", + opt->argname, opt->name); + return (1); + } + } + + switch (opt->type) { + case OPTION_ARG: + *opt->opt.arg = argv[i]; + break; + + case OPTION_ARGV_FUNC: + if (opt->opt.argvfunc(argc - i, &argv[i], &used) != 0) + return (1); + i += used - 1; + break; + + case OPTION_ARG_FORMAT: + fmt = str2fmt(argv[i]); + if (fmt == FORMAT_UNDEF) { + fprintf(stderr, "unknown %s '%s' for -%s\n", + opt->argname, argv[i], opt->name); + return (1); + } + *opt->opt.value = fmt; + break; + + case OPTION_ARG_FUNC: + if (opt->opt.argfunc(argv[i]) != 0) + return (1); + break; + + case OPTION_ARG_INT: + val = strtonum(argv[i], 0, INT_MAX, &errstr); + if (errstr != NULL) { + fprintf(stderr, "%s %s argument for -%s\n", + errstr, opt->argname, opt->name); + return (1); + } + *opt->opt.value = (int)val; + break; + + case OPTION_ARG_LONG: + val = strtonum(argv[i], 0, LONG_MAX, &errstr); + if (errstr != NULL) { + fprintf(stderr, "%s %s argument for -%s\n", + errstr, opt->argname, opt->name); + return (1); + } + *opt->opt.lvalue = (long)val; + break; + + case OPTION_ARG_TIME: + val = strtonum(argv[i], 0, LLONG_MAX, &errstr); + if (errstr != NULL) { + fprintf(stderr, "%s %s argument for -%s\n", + errstr, opt->argname, opt->name); + return (1); + } + *opt->opt.tvalue = val; + break; + + case OPTION_DISCARD: + break; + + case OPTION_FUNC: + if (opt->opt.func() != 0) + return (1); + break; + + case OPTION_FLAG: + *opt->opt.flag = 1; + break; + + case OPTION_FLAG_ORD: + *opt->opt.flag = ++ord; + break; + + case OPTION_VALUE: + *opt->opt.value = opt->value; + break; + + case OPTION_VALUE_AND: + *opt->opt.value &= opt->value; + break; + + case OPTION_VALUE_OR: + *opt->opt.value |= opt->value; + break; + + default: + fprintf(stderr, "option %s - unknown type %i\n", + opt->name, opt->type); + return (1); + } + } + +done: + if (argsused != NULL) + *argsused = i; + + return (0); + +toomany: + fprintf(stderr, "too many arguments\n"); + return (1); + +unknown: + fprintf(stderr, "unknown option '%s'\n", arg); + return (1); +} diff --git a/bin/openssl/apps.h b/bin/openssl/apps.h new file mode 100644 index 0000000000..4276e533f7 --- /dev/null +++ b/bin/openssl/apps.h @@ -0,0 +1,323 @@ +/* $OpenBSD: apps.h,v 1.19 2016/08/30 14:34:59 deraadt Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#ifndef HEADER_APPS_H +#define HEADER_APPS_H + +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifndef OPENSSL_NO_OCSP +#include +#endif + +#include +extern int single_execution; + +extern CONF *config; +extern char *default_config_file; +extern BIO *bio_err; + +typedef struct args_st { + char **data; + int count; +} ARGS; + +#define PW_MIN_LENGTH 4 +typedef struct pw_cb_data { + const void *password; + const char *prompt_info; +} PW_CB_DATA; + +int password_callback(char *buf, int bufsiz, int verify, void *cb_data); + +int setup_ui(void); +void destroy_ui(void); + +extern UI_METHOD *ui_method; +int ui_open(UI *ui); +int ui_read(UI *ui, UI_STRING *uis); +int ui_write(UI *ui, UI_STRING *uis); +int ui_close(UI *ui); + +int should_retry(int i); +int args_from_file(char *file, int *argc, char **argv[]); +int str2fmt(char *s); +void program_name(char *in, char *out, int size); +int chopup_args(ARGS *arg, char *buf, int *argc, char **argv[]); +#ifdef HEADER_X509_H +int dump_cert_text(BIO *out, X509 *x); +void print_name(BIO *out, const char *title, X509_NAME *nm, + unsigned long lflags); +#endif +int set_cert_ex(unsigned long *flags, const char *arg); +int set_name_ex(unsigned long *flags, const char *arg); +int set_ext_copy(int *copy_type, const char *arg); +int copy_extensions(X509 *x, X509_REQ *req, int copy_type); +int app_passwd(BIO *err, char *arg1, char *arg2, char **pass1, char **pass2); +int add_oid_section(BIO *err, CONF *conf); +X509 *load_cert(BIO *err, const char *file, int format, + const char *pass, const char *cert_descrip); +EVP_PKEY *load_key(BIO *err, const char *file, int format, int maybe_stdin, + const char *pass, const char *key_descrip); +EVP_PKEY *load_pubkey(BIO *err, const char *file, int format, int maybe_stdin, + const char *pass, const char *key_descrip); +STACK_OF(X509) *load_certs(BIO *err, const char *file, int format, + const char *pass, const char *cert_descrip); +STACK_OF(X509_CRL) *load_crls(BIO *err, const char *file, int format, + const char *pass, const char *cert_descrip); +X509_STORE *setup_verify(BIO *bp, char *CAfile, char *CApath); + +#ifndef OPENSSL_NO_OCSP +OCSP_RESPONSE *process_responder(BIO *err, OCSP_REQUEST *req, + char *host, char *path, char *port, int use_ssl, + STACK_OF(CONF_VALUE) *headers, int req_timeout); +#endif + +int load_config(BIO *err, CONF *cnf); +char *make_config_name(void); + +/* Functions defined in ca.c and also used in ocsp.c */ +int unpack_revinfo(ASN1_TIME **prevtm, int *preason, ASN1_OBJECT **phold, + ASN1_GENERALIZEDTIME **pinvtm, const char *str); + +#define DB_type 0 +#define DB_exp_date 1 +#define DB_rev_date 2 +#define DB_serial 3 /* index - unique */ +#define DB_file 4 +#define DB_name 5 /* index - unique when active and not disabled */ +#define DB_NUMBER 6 + +#define DB_TYPE_REV 'R' +#define DB_TYPE_EXP 'E' +#define DB_TYPE_VAL 'V' + +typedef struct db_attr_st { + int unique_subject; +} DB_ATTR; +typedef struct ca_db_st { + DB_ATTR attributes; + TXT_DB *db; +} CA_DB; + +BIGNUM *load_serial(char *serialfile, int create, ASN1_INTEGER **retai); +int save_serial(char *serialfile, char *suffix, BIGNUM *serial, + ASN1_INTEGER **retai); +int rotate_serial(char *serialfile, char *new_suffix, char *old_suffix); +int rand_serial(BIGNUM *b, ASN1_INTEGER *ai); +CA_DB *load_index(char *dbfile, DB_ATTR *dbattr); +int index_index(CA_DB *db); +int save_index(const char *dbfile, const char *suffix, CA_DB *db); +int rotate_index(const char *dbfile, const char *new_suffix, + const char *old_suffix); +void free_index(CA_DB *db); +#define index_name_cmp_noconst(a, b) \ + index_name_cmp((const OPENSSL_CSTRING *)CHECKED_PTR_OF(OPENSSL_STRING, a), \ + (const OPENSSL_CSTRING *)CHECKED_PTR_OF(OPENSSL_STRING, b)) +int index_name_cmp(const OPENSSL_CSTRING *a, const OPENSSL_CSTRING *b); +int parse_yesno(const char *str, int def); + +X509_NAME *parse_name(char *str, long chtype, int multirdn); +int args_verify(char ***pargs, int *pargc, int *badarg, BIO *err, + X509_VERIFY_PARAM **pm); +void policies_print(BIO *out, X509_STORE_CTX *ctx); +int bio_to_mem(unsigned char **out, int maxlen, BIO *in); +int pkey_ctrl_string(EVP_PKEY_CTX *ctx, char *value); +int init_gen_str(BIO *err, EVP_PKEY_CTX **pctx, const char *algname, + int do_param); +int do_X509_sign(BIO *err, X509 *x, EVP_PKEY *pkey, const EVP_MD *md, + STACK_OF(OPENSSL_STRING) *sigopts); +int do_X509_REQ_sign(BIO *err, X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md, + STACK_OF(OPENSSL_STRING) *sigopts); +int do_X509_CRL_sign(BIO *err, X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md, + STACK_OF(OPENSSL_STRING) *sigopts); + +unsigned char *next_protos_parse(unsigned short *outlen, const char *in); + +#define FORMAT_UNDEF 0 +#define FORMAT_ASN1 1 +#define FORMAT_TEXT 2 +#define FORMAT_PEM 3 +#define FORMAT_NETSCAPE 4 +#define FORMAT_PKCS12 5 +#define FORMAT_SMIME 6 + +#define FORMAT_IISSGC 8 /* XXX this stupid macro helps us to avoid + * adding yet another param to load_*key() */ +#define FORMAT_PEMRSA 9 /* PEM RSAPubicKey format */ +#define FORMAT_ASN1RSA 10 /* DER RSAPubicKey format */ +#define FORMAT_MSBLOB 11 /* MS Key blob format */ +#define FORMAT_PVK 12 /* MS PVK file format */ + +#define EXT_COPY_NONE 0 +#define EXT_COPY_ADD 1 +#define EXT_COPY_ALL 2 + +#define NETSCAPE_CERT_HDR "certificate" + +#define APP_PASS_LEN 1024 + +#define SERIAL_RAND_BITS 64 + +int app_isdir(const char *); + +#define TM_START 0 +#define TM_STOP 1 +double app_tminterval (int stop, int usertime); + +#define OPENSSL_NO_SSL_INTERN + +struct option { + const char *name; + const char *argname; + const char *desc; + enum { + OPTION_ARG, + OPTION_ARGV_FUNC, + OPTION_ARG_FORMAT, + OPTION_ARG_FUNC, + OPTION_ARG_INT, + OPTION_ARG_LONG, + OPTION_ARG_TIME, + OPTION_DISCARD, + OPTION_FUNC, + OPTION_FLAG, + OPTION_FLAG_ORD, + OPTION_VALUE, + OPTION_VALUE_AND, + OPTION_VALUE_OR, + } type; + union { + char **arg; + int (*argfunc)(char *arg); + int (*argvfunc)(int argc, char **argv, int *argsused); + int *flag; + int (*func)(void); + long *lvalue; + int *value; + time_t *tvalue; + } opt; + const int value; +}; + +void options_usage(struct option *opts); +int options_parse(int argc, char **argv, struct option *opts, char **unnamed, + int *argsused); + +#endif diff --git a/bin/openssl/apps_posix.c b/bin/openssl/apps_posix.c new file mode 100644 index 0000000000..67cd465088 --- /dev/null +++ b/bin/openssl/apps_posix.c @@ -0,0 +1,164 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +/* + * Functions that need to be overridden by non-POSIX operating systems. + */ + +#include + +#include + +#include "apps.h" + +double +app_tminterval(int stop, int usertime) +{ + double ret = 0; + struct tms rus; + clock_t now = times(&rus); + static clock_t tmstart; + + if (usertime) + now = rus.tms_utime; + + if (stop == TM_START) + tmstart = now; + else { + long int tck = sysconf(_SC_CLK_TCK); + ret = (now - tmstart) / (double) tck; + } + + return (ret); +} + +int +setup_ui(void) +{ + ui_method = UI_create_method("OpenSSL application user interface"); + UI_method_set_opener(ui_method, ui_open); + UI_method_set_reader(ui_method, ui_read); + UI_method_set_writer(ui_method, ui_write); + UI_method_set_closer(ui_method, ui_close); + return 0; +} + +void +destroy_ui(void) +{ + if (ui_method) { + UI_destroy_method(ui_method); + ui_method = NULL; + } +} diff --git a/bin/openssl/asn1pars.c b/bin/openssl/asn1pars.c new file mode 100644 index 0000000000..fe66b35937 --- /dev/null +++ b/bin/openssl/asn1pars.c @@ -0,0 +1,482 @@ +/* $OpenBSD: asn1pars.c,v 1.7 2017/01/20 08:57:11 deraadt Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +/* A nice addition from Dr Stephen Henson to + * add the -strparse option which parses nested binary structures + */ + +#include +#include +#include +#include + +#include "apps.h" +#include "progs.h" + +#include +#include +#include +#include + +static struct { + char *derfile; + int dump; + char *genconf; + char *genstr; + int indent; + char *infile; + int informat; + unsigned int length; + int noout; + int offset; + char *oidfile; + STACK_OF(OPENSSL_STRING) *osk; +} asn1pars_config; + +static int +asn1pars_opt_dlimit(char *arg) +{ + const char *errstr; + + asn1pars_config.dump = strtonum(arg, 1, INT_MAX, &errstr); + if (errstr) { + fprintf(stderr, "-dlimit must be from 1 to INT_MAX: %s\n", + errstr); + return (-1); + } + return (0); +} + +static int +asn1pars_opt_length(char *arg) +{ + const char *errstr; + + asn1pars_config.length = strtonum(arg, 1, UINT_MAX, &errstr); + if (errstr) { + fprintf(stderr, "-length must be from 1 to UINT_MAX: %s\n", + errstr); + return (-1); + } + return (0); +} + +static int +asn1pars_opt_strparse(char *arg) +{ + if (sk_OPENSSL_STRING_push(asn1pars_config.osk, arg) == 0) { + fprintf(stderr, "-strparse cannot add argument\n"); + return (-1); + } + return (0); +} + +static struct option asn1pars_options[] = { + { + .name = "dump", + .desc = "Dump unknown data in hex form", + .type = OPTION_VALUE, + .value = -1, + .opt.value = &asn1pars_config.dump, + }, + { + .name = "dlimit", + .argname = "num", + .desc = "Dump the first num bytes of unknown data in hex form", + .type = OPTION_ARG_FUNC, + .opt.argfunc = asn1pars_opt_dlimit, + }, + { + .name = "genconf", + .argname = "file", + .desc = "File to generate ASN.1 structure from", + .type = OPTION_ARG, + .opt.arg = &asn1pars_config.genconf, + }, + { + .name = "genstr", + .argname = "string", + .desc = "String to generate ASN.1 structure from", + .type = OPTION_ARG, + .opt.arg = &asn1pars_config.genstr, + }, + { + .name = "i", + .desc = "Indent output according to depth of structures", + .type = OPTION_FLAG, + .opt.flag = &asn1pars_config.indent, + }, + { + .name = "in", + .argname = "file", + .desc = "The input file (default stdin)", + .type = OPTION_ARG, + .opt.arg = &asn1pars_config.infile, + }, + { + .name = "inform", + .argname = "fmt", + .desc = "Input format (DER, TXT or PEM (default))", + .type = OPTION_ARG_FORMAT, + .opt.value = &asn1pars_config.informat, + }, + { + .name = "length", + .argname = "num", + .desc = "Number of bytes to parse (default until EOF)", + .type = OPTION_ARG_FUNC, + .opt.argfunc = asn1pars_opt_length, + }, + { + .name = "noout", + .desc = "Do not produce any output", + .type = OPTION_FLAG, + .opt.flag = &asn1pars_config.noout, + }, + { + .name = "offset", + .argname = "num", + .desc = "Offset to begin parsing", + .type = OPTION_ARG_INT, + .opt.value = &asn1pars_config.offset, + }, + { + .name = "oid", + .argname = "file", + .desc = "File containing additional object identifiers (OIDs)", + .type = OPTION_ARG, + .opt.arg = &asn1pars_config.oidfile, + }, + { + .name = "out", + .argname = "file", + .desc = "Output file in DER format", + .type = OPTION_ARG, + .opt.arg = &asn1pars_config.derfile, + }, + { + .name = "strparse", + .argname = "offset", + .desc = "Parse the content octets of ASN.1 object starting at" + " offset", + .type = OPTION_ARG_FUNC, + .opt.argfunc = asn1pars_opt_strparse, + }, + { NULL }, +}; + +static void +asn1pars_usage() +{ + fprintf(stderr, + "usage: asn1parse [-i] [-dlimit num] [-dump] [-genconf file] " + "[-genstr string]\n" + " [-in file] [-inform fmt] [-length num] [-noout] [-offset num] " + "[-oid file]\n" + " [-out file] [-strparse offset]\n\n"); + options_usage(asn1pars_options); +} + +static int do_generate(BIO *bio, char *genstr, char *genconf, BUF_MEM *buf); + +int +asn1parse_main(int argc, char **argv) +{ + int i, j, ret = 1; + long num, tmplen; + BIO *in = NULL, *out = NULL, *b64 = NULL, *derout = NULL; + char *str = NULL; + const char *errstr = NULL; + unsigned char *tmpbuf; + const unsigned char *ctmpbuf; + BUF_MEM *buf = NULL; + ASN1_TYPE *at = NULL; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + memset(&asn1pars_config, 0, sizeof(asn1pars_config)); + + asn1pars_config.informat = FORMAT_PEM; + if ((asn1pars_config.osk = sk_OPENSSL_STRING_new_null()) == NULL) { + BIO_printf(bio_err, "Memory allocation failure\n"); + goto end; + } + + if (options_parse(argc, argv, asn1pars_options, NULL, NULL) != 0) { + asn1pars_usage(); + return (1); + } + + in = BIO_new(BIO_s_file()); + out = BIO_new(BIO_s_file()); + if ((in == NULL) || (out == NULL)) { + ERR_print_errors(bio_err); + goto end; + } + BIO_set_fp(out, stdout, BIO_NOCLOSE | BIO_FP_TEXT); + + if (asn1pars_config.oidfile != NULL) { + if (BIO_read_filename(in, asn1pars_config.oidfile) <= 0) { + BIO_printf(bio_err, "problems opening %s\n", + asn1pars_config.oidfile); + ERR_print_errors(bio_err); + goto end; + } + OBJ_create_objects(in); + } + if (asn1pars_config.infile == NULL) + BIO_set_fp(in, stdin, BIO_NOCLOSE); + else { + if (BIO_read_filename(in, asn1pars_config.infile) <= 0) { + perror(asn1pars_config.infile); + goto end; + } + } + + if (asn1pars_config.derfile) { + if (!(derout = BIO_new_file(asn1pars_config.derfile, "wb"))) { + BIO_printf(bio_err, "problems opening %s\n", + asn1pars_config.derfile); + ERR_print_errors(bio_err); + goto end; + } + } + if ((buf = BUF_MEM_new()) == NULL) + goto end; + if (!BUF_MEM_grow(buf, BUFSIZ * 8)) + goto end; /* Pre-allocate :-) */ + + if (asn1pars_config.genstr || asn1pars_config.genconf) { + num = do_generate(bio_err, asn1pars_config.genstr, + asn1pars_config.genconf, buf); + if (num < 0) { + ERR_print_errors(bio_err); + goto end; + } + } else { + + if (asn1pars_config.informat == FORMAT_PEM) { + BIO *tmp; + + if ((b64 = BIO_new(BIO_f_base64())) == NULL) + goto end; + BIO_push(b64, in); + tmp = in; + in = b64; + b64 = tmp; + } + num = 0; + for (;;) { + if (!BUF_MEM_grow(buf, (int) num + BUFSIZ)) + goto end; + i = BIO_read(in, &(buf->data[num]), BUFSIZ); + if (i <= 0) + break; + num += i; + } + } + str = buf->data; + + /* If any structs to parse go through in sequence */ + + if (sk_OPENSSL_STRING_num(asn1pars_config.osk)) { + tmpbuf = (unsigned char *) str; + tmplen = num; + for (i = 0; i < sk_OPENSSL_STRING_num(asn1pars_config.osk); + i++) { + ASN1_TYPE *atmp; + int typ; + j = strtonum( + sk_OPENSSL_STRING_value(asn1pars_config.osk, i), + 1, INT_MAX, &errstr); + if (errstr) { + BIO_printf(bio_err, + "'%s' is an invalid number: %s\n", + sk_OPENSSL_STRING_value(asn1pars_config.osk, + i), errstr); + continue; + } + tmpbuf += j; + tmplen -= j; + atmp = at; + ctmpbuf = tmpbuf; + at = d2i_ASN1_TYPE(NULL, &ctmpbuf, tmplen); + ASN1_TYPE_free(atmp); + if (!at) { + BIO_printf(bio_err, "Error parsing structure\n"); + ERR_print_errors(bio_err); + goto end; + } + typ = ASN1_TYPE_get(at); + if ((typ == V_ASN1_OBJECT) || + (typ == V_ASN1_NULL)) { + BIO_printf(bio_err, "Can't parse %s type\n", + typ == V_ASN1_NULL ? "NULL" : "OBJECT"); + ERR_print_errors(bio_err); + goto end; + } + /* hmm... this is a little evil but it works */ + tmpbuf = at->value.asn1_string->data; + tmplen = at->value.asn1_string->length; + } + str = (char *) tmpbuf; + num = tmplen; + } + if (asn1pars_config.offset >= num) { + BIO_printf(bio_err, "Error: offset too large\n"); + goto end; + } + num -= asn1pars_config.offset; + + if ((asn1pars_config.length == 0) || + ((long)asn1pars_config.length > num)) + asn1pars_config.length = (unsigned int) num; + if (derout) { + if (BIO_write(derout, str + asn1pars_config.offset, + asn1pars_config.length) != (int)asn1pars_config.length) { + BIO_printf(bio_err, "Error writing output\n"); + ERR_print_errors(bio_err); + goto end; + } + } + if (!asn1pars_config.noout && + !ASN1_parse_dump(out, + (unsigned char *)&(str[asn1pars_config.offset]), + asn1pars_config.length, asn1pars_config.indent, + asn1pars_config.dump)) { + ERR_print_errors(bio_err); + goto end; + } + ret = 0; +end: + BIO_free(derout); + BIO_free(in); + BIO_free_all(out); + BIO_free(b64); + if (ret != 0) + ERR_print_errors(bio_err); + BUF_MEM_free(buf); + if (at != NULL) + ASN1_TYPE_free(at); + sk_OPENSSL_STRING_free(asn1pars_config.osk); + OBJ_cleanup(); + + return (ret); +} + +static int +do_generate(BIO * bio, char *genstr, char *genconf, BUF_MEM * buf) +{ + CONF *cnf = NULL; + int len; + long errline; + unsigned char *p; + ASN1_TYPE *atyp = NULL; + + if (genconf) { + cnf = NCONF_new(NULL); + if (!NCONF_load(cnf, genconf, &errline)) + goto conferr; + if (!genstr) + genstr = NCONF_get_string(cnf, "default", "asn1"); + if (!genstr) { + BIO_printf(bio, "Can't find 'asn1' in '%s'\n", genconf); + goto err; + } + } + atyp = ASN1_generate_nconf(genstr, cnf); + NCONF_free(cnf); + cnf = NULL; + + if (!atyp) + return -1; + + len = i2d_ASN1_TYPE(atyp, NULL); + if (len <= 0) + goto err; + + if (!BUF_MEM_grow(buf, len)) + goto err; + + p = (unsigned char *) buf->data; + + i2d_ASN1_TYPE(atyp, &p); + + ASN1_TYPE_free(atyp); + return len; + +conferr: + + if (errline > 0) + BIO_printf(bio, "Error on line %ld of config file '%s'\n", + errline, genconf); + else + BIO_printf(bio, "Error loading config file '%s'\n", genconf); + +err: + NCONF_free(cnf); + ASN1_TYPE_free(atyp); + + return -1; + +} diff --git a/bin/openssl/ca.c b/bin/openssl/ca.c new file mode 100644 index 0000000000..a3e779da33 --- /dev/null +++ b/bin/openssl/ca.c @@ -0,0 +1,2692 @@ +/* $OpenBSD: ca.c,v 1.23 2017/01/20 08:57:11 deraadt Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +/* The PPKI stuff has been donated by Jeff Barber */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "apps.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BASE_SECTION "ca" + +#define ENV_DEFAULT_CA "default_ca" + +#define STRING_MASK "string_mask" +#define UTF8_IN "utf8" + +#define ENV_NEW_CERTS_DIR "new_certs_dir" +#define ENV_CERTIFICATE "certificate" +#define ENV_SERIAL "serial" +#define ENV_CRLNUMBER "crlnumber" +#define ENV_PRIVATE_KEY "private_key" +#define ENV_DEFAULT_DAYS "default_days" +#define ENV_DEFAULT_STARTDATE "default_startdate" +#define ENV_DEFAULT_ENDDATE "default_enddate" +#define ENV_DEFAULT_CRL_DAYS "default_crl_days" +#define ENV_DEFAULT_CRL_HOURS "default_crl_hours" +#define ENV_DEFAULT_MD "default_md" +#define ENV_DEFAULT_EMAIL_DN "email_in_dn" +#define ENV_PRESERVE "preserve" +#define ENV_POLICY "policy" +#define ENV_EXTENSIONS "x509_extensions" +#define ENV_CRLEXT "crl_extensions" +#define ENV_MSIE_HACK "msie_hack" +#define ENV_NAMEOPT "name_opt" +#define ENV_CERTOPT "cert_opt" +#define ENV_EXTCOPY "copy_extensions" +#define ENV_UNIQUE_SUBJECT "unique_subject" + +#define ENV_DATABASE "database" + +/* Additional revocation information types */ + +#define REV_NONE 0 /* No addditional information */ +#define REV_CRL_REASON 1 /* Value is CRL reason code */ +#define REV_HOLD 2 /* Value is hold instruction */ +#define REV_KEY_COMPROMISE 3 /* Value is cert key compromise time */ +#define REV_CA_COMPROMISE 4 /* Value is CA key compromise time */ + +static const char *ca_usage[] = { + "usage: ca args\n", + "\n", + " -verbose - Talk a lot while doing things\n", + " -config file - A config file\n", + " -name arg - The particular CA definition to use\n", + " -gencrl - Generate a new CRL\n", + " -crldays days - Days is when the next CRL is due\n", + " -crlhours hours - Hours is when the next CRL is due\n", + " -startdate YYMMDDHHMMSSZ - certificate validity notBefore\n", + " -enddate YYMMDDHHMMSSZ - certificate validity notAfter (overrides -days)\n", + " -days arg - number of days to certify the certificate for\n", + " -md arg - md to use, one of md5 or sha1\n", + " -policy arg - The CA 'policy' to support\n", + " -keyfile arg - private key file\n", + " -keyform arg - private key file format (PEM)\n", + " -key arg - key to decode the private key if it is encrypted\n", + " -cert file - The CA certificate\n", + " -selfsign - sign a certificate with the key associated with it\n", + " -in file - The input PEM encoded certificate request(s)\n", + " -out file - Where to put the output file(s)\n", + " -outdir dir - Where to put output certificates\n", + " -infiles .... - The last argument, requests to process\n", + " -spkac file - File contains DN and signed public key and challenge\n", + " -ss_cert file - File contains a self signed cert to sign\n", + " -preserveDN - Don't re-order the DN\n", + " -noemailDN - Don't add the EMAIL field into certificate' subject\n", + " -batch - Don't ask questions\n", + " -msie_hack - msie modifications to handle all those universal strings\n", + " -revoke file - Revoke a certificate (given in file)\n", + " -subj arg - Use arg instead of request's subject\n", + " -utf8 - input characters are UTF8 (default ASCII)\n", + " -multivalue-rdn - enable support for multivalued RDNs\n", + " -extensions .. - Extension section (override value in config file)\n", + " -extfile file - Configuration file with X509v3 extentions to add\n", + " -crlexts .. - CRL extension section (override value in config file)\n", + " -status serial - Shows certificate status given the serial number\n", + " -updatedb - Updates db for expired certificates\n", + NULL +}; + +static void lookup_fail(const char *name, const char *tag); +static int certify(X509 ** xret, char *infile, EVP_PKEY * pkey, X509 * x509, + const EVP_MD * dgst, STACK_OF(OPENSSL_STRING) * sigopts, + STACK_OF(CONF_VALUE) * policy, CA_DB * db, BIGNUM * serial, char *subj, + unsigned long chtype, int multirdn, int email_dn, char *startdate, + char *enddate, long days, int batch, char *ext_sect, CONF * conf, + int verbose, unsigned long certopt, unsigned long nameopt, + int default_op, int ext_copy, int selfsign); +static int certify_cert(X509 ** xret, char *infile, EVP_PKEY * pkey, + X509 * x509, const EVP_MD * dgst, STACK_OF(OPENSSL_STRING) * sigopts, + STACK_OF(CONF_VALUE) * policy, CA_DB * db, BIGNUM * serial, char *subj, + unsigned long chtype, int multirdn, int email_dn, char *startdate, + char *enddate, long days, int batch, char *ext_sect, CONF * conf, + int verbose, unsigned long certopt, unsigned long nameopt, int default_op, + int ext_copy); +static int certify_spkac(X509 ** xret, char *infile, EVP_PKEY * pkey, + X509 * x509, const EVP_MD * dgst, STACK_OF(OPENSSL_STRING) * sigopts, + STACK_OF(CONF_VALUE) * policy, CA_DB * db, BIGNUM * serial, char *subj, + unsigned long chtype, int multirdn, int email_dn, char *startdate, + char *enddate, long days, char *ext_sect, CONF * conf, int verbose, + unsigned long certopt, unsigned long nameopt, int default_op, int ext_copy); +static void write_new_certificate(BIO * bp, X509 * x, int output_der, + int notext); +static int do_body(X509 ** xret, EVP_PKEY * pkey, X509 * x509, + const EVP_MD * dgst, STACK_OF(OPENSSL_STRING) * sigopts, + STACK_OF(CONF_VALUE) * policy, CA_DB * db, BIGNUM * serial, char *subj, + unsigned long chtype, int multirdn, int email_dn, char *startdate, + char *enddate, long days, int batch, int verbose, X509_REQ * req, + char *ext_sect, CONF * conf, unsigned long certopt, unsigned long nameopt, + int default_op, int ext_copy, int selfsign); +static int do_revoke(X509 * x509, CA_DB * db, int ext, char *extval); +static int get_certificate_status(const char *ser_status, CA_DB * db); +static int do_updatedb(CA_DB * db); +static int check_time_format(const char *str); +static char * bin2hex(unsigned char *, size_t); +char *make_revocation_str(int rev_type, char *rev_arg); +int make_revoked(X509_REVOKED * rev, const char *str); +int old_entry_print(BIO * bp, ASN1_OBJECT * obj, ASN1_STRING * str); +static CONF *conf = NULL; +static CONF *extconf = NULL; +static char *section = NULL; + +static int preserve = 0; +static int msie_hack = 0; + + +int +ca_main(int argc, char **argv) +{ + char *key = NULL, *passargin = NULL; + int create_ser = 0; + int free_key = 0; + int total = 0; + int total_done = 0; + int badops = 0; + int ret = 1; + int email_dn = 1; + int req = 0; + int verbose = 0; + int gencrl = 0; + int dorevoke = 0; + int doupdatedb = 0; + long crldays = 0; + long crlhours = 0; + long crlsec = 0; + long errorline = -1; + char *configfile = NULL; + char *md = NULL; + char *policy = NULL; + char *keyfile = NULL; + char *certfile = NULL; + int keyform = FORMAT_PEM; + char *infile = NULL; + char *spkac_file = NULL; + char *ss_cert_file = NULL; + char *ser_status = NULL; + EVP_PKEY *pkey = NULL; + int output_der = 0; + char *outfile = NULL; + char *outdir = NULL; + char *serialfile = NULL; + char *crlnumberfile = NULL; + char *extensions = NULL; + char *extfile = NULL; + char *subj = NULL; + unsigned long chtype = MBSTRING_ASC; + int multirdn = 0; + char *tmp_email_dn = NULL; + char *crl_ext = NULL; + int rev_type = REV_NONE; + char *rev_arg = NULL; + BIGNUM *serial = NULL; + BIGNUM *crlnumber = NULL; + char *startdate = NULL; + char *enddate = NULL; + long days = 0; + int batch = 0; + int notext = 0; + unsigned long nameopt = 0, certopt = 0; + int default_op = 1; + int ext_copy = EXT_COPY_NONE; + int selfsign = 0; + X509 *x509 = NULL, *x509p = NULL; + X509 *x = NULL; + BIO *in = NULL, *out = NULL, *Sout = NULL, *Cout = NULL; + char *dbfile = NULL; + CA_DB *db = NULL; + X509_CRL *crl = NULL; + X509_REVOKED *r = NULL; + ASN1_TIME *tmptm; + ASN1_INTEGER *tmpser; + char *f; + const char *p; + char *const * pp; + int i, j; + const EVP_MD *dgst = NULL; + STACK_OF(CONF_VALUE) * attribs = NULL; + STACK_OF(X509) * cert_sk = NULL; + STACK_OF(OPENSSL_STRING) * sigopts = NULL; + char *tofree = NULL; + const char *errstr = NULL; + DB_ATTR db_attr; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + conf = NULL; + key = NULL; + section = NULL; + + preserve = 0; + msie_hack = 0; + + argc--; + argv++; + while (argc >= 1) { + if (strcmp(*argv, "-verbose") == 0) + verbose = 1; + else if (strcmp(*argv, "-config") == 0) { + if (--argc < 1) + goto bad; + configfile = *(++argv); + } else if (strcmp(*argv, "-name") == 0) { + if (--argc < 1) + goto bad; + section = *(++argv); + } else if (strcmp(*argv, "-subj") == 0) { + if (--argc < 1) + goto bad; + subj = *(++argv); + /* preserve=1; */ + } else if (strcmp(*argv, "-utf8") == 0) + chtype = MBSTRING_UTF8; + else if (strcmp(*argv, "-create_serial") == 0) + create_ser = 1; + else if (strcmp(*argv, "-multivalue-rdn") == 0) + multirdn = 1; + else if (strcmp(*argv, "-startdate") == 0) { + if (--argc < 1) + goto bad; + startdate = *(++argv); + } else if (strcmp(*argv, "-enddate") == 0) { + if (--argc < 1) + goto bad; + enddate = *(++argv); + } else if (strcmp(*argv, "-days") == 0) { + if (--argc < 1) + goto bad; + days = strtonum(*(++argv), 0, LONG_MAX, &errstr); + if (errstr) + goto bad; + } else if (strcmp(*argv, "-md") == 0) { + if (--argc < 1) + goto bad; + md = *(++argv); + } else if (strcmp(*argv, "-policy") == 0) { + if (--argc < 1) + goto bad; + policy = *(++argv); + } else if (strcmp(*argv, "-keyfile") == 0) { + if (--argc < 1) + goto bad; + keyfile = *(++argv); + } else if (strcmp(*argv, "-keyform") == 0) { + if (--argc < 1) + goto bad; + keyform = str2fmt(*(++argv)); + } else if (strcmp(*argv, "-passin") == 0) { + if (--argc < 1) + goto bad; + passargin = *(++argv); + } else if (strcmp(*argv, "-key") == 0) { + if (--argc < 1) + goto bad; + key = *(++argv); + } else if (strcmp(*argv, "-cert") == 0) { + if (--argc < 1) + goto bad; + certfile = *(++argv); + } else if (strcmp(*argv, "-selfsign") == 0) + selfsign = 1; + else if (strcmp(*argv, "-in") == 0) { + if (--argc < 1) + goto bad; + infile = *(++argv); + req = 1; + } else if (strcmp(*argv, "-out") == 0) { + if (--argc < 1) + goto bad; + outfile = *(++argv); + } else if (strcmp(*argv, "-outdir") == 0) { + if (--argc < 1) + goto bad; + outdir = *(++argv); + } else if (strcmp(*argv, "-sigopt") == 0) { + if (--argc < 1) + goto bad; + if (!sigopts) + sigopts = sk_OPENSSL_STRING_new_null(); + if (!sigopts || + !sk_OPENSSL_STRING_push(sigopts, *(++argv))) + goto bad; + } else if (strcmp(*argv, "-notext") == 0) + notext = 1; + else if (strcmp(*argv, "-batch") == 0) + batch = 1; + else if (strcmp(*argv, "-preserveDN") == 0) + preserve = 1; + else if (strcmp(*argv, "-noemailDN") == 0) + email_dn = 0; + else if (strcmp(*argv, "-gencrl") == 0) + gencrl = 1; + else if (strcmp(*argv, "-msie_hack") == 0) + msie_hack = 1; + else if (strcmp(*argv, "-crldays") == 0) { + if (--argc < 1) + goto bad; + crldays = strtonum(*(++argv), 0, LONG_MAX, &errstr); + if (errstr) + goto bad; + } else if (strcmp(*argv, "-crlhours") == 0) { + if (--argc < 1) + goto bad; + crlhours = strtonum(*(++argv), 0, LONG_MAX, &errstr); + if (errstr) + goto bad; + } else if (strcmp(*argv, "-crlsec") == 0) { + if (--argc < 1) + goto bad; + crlsec = strtonum(*(++argv), 0, LONG_MAX, &errstr); + if (errstr) + goto bad; + } else if (strcmp(*argv, "-infiles") == 0) { + argc--; + argv++; + req = 1; + break; + } else if (strcmp(*argv, "-ss_cert") == 0) { + if (--argc < 1) + goto bad; + ss_cert_file = *(++argv); + req = 1; + } else if (strcmp(*argv, "-spkac") == 0) { + if (--argc < 1) + goto bad; + spkac_file = *(++argv); + req = 1; + } else if (strcmp(*argv, "-revoke") == 0) { + if (--argc < 1) + goto bad; + infile = *(++argv); + dorevoke = 1; + } else if (strcmp(*argv, "-extensions") == 0) { + if (--argc < 1) + goto bad; + extensions = *(++argv); + } else if (strcmp(*argv, "-extfile") == 0) { + if (--argc < 1) + goto bad; + extfile = *(++argv); + } else if (strcmp(*argv, "-status") == 0) { + if (--argc < 1) + goto bad; + ser_status = *(++argv); + } else if (strcmp(*argv, "-updatedb") == 0) { + doupdatedb = 1; + } else if (strcmp(*argv, "-crlexts") == 0) { + if (--argc < 1) + goto bad; + crl_ext = *(++argv); + } else if (strcmp(*argv, "-crl_reason") == 0) { + if (--argc < 1) + goto bad; + rev_arg = *(++argv); + rev_type = REV_CRL_REASON; + } else if (strcmp(*argv, "-crl_hold") == 0) { + if (--argc < 1) + goto bad; + rev_arg = *(++argv); + rev_type = REV_HOLD; + } else if (strcmp(*argv, "-crl_compromise") == 0) { + if (--argc < 1) + goto bad; + rev_arg = *(++argv); + rev_type = REV_KEY_COMPROMISE; + } else if (strcmp(*argv, "-crl_CA_compromise") == 0) { + if (--argc < 1) + goto bad; + rev_arg = *(++argv); + rev_type = REV_CA_COMPROMISE; + } + else { +bad: + if (errstr) + BIO_printf(bio_err, "invalid argument %s: %s\n", + *argv, errstr); + else + BIO_printf(bio_err, "unknown option %s\n", *argv); + badops = 1; + break; + } + argc--; + argv++; + } + + if (badops) { + const char **pp2; + + for (pp2 = ca_usage; (*pp2 != NULL); pp2++) + BIO_printf(bio_err, "%s", *pp2); + goto err; + } + + /*****************************************************************/ + tofree = NULL; + if (configfile == NULL) + configfile = getenv("OPENSSL_CONF"); + if (configfile == NULL) { + if ((tofree = make_config_name()) == NULL) { + BIO_printf(bio_err, "error making config file name\n"); + goto err; + } + configfile = tofree; + } + BIO_printf(bio_err, "Using configuration from %s\n", configfile); + conf = NCONF_new(NULL); + if (NCONF_load(conf, configfile, &errorline) <= 0) { + if (errorline <= 0) + BIO_printf(bio_err, + "error loading the config file '%s'\n", + configfile); + else + BIO_printf(bio_err, + "error on line %ld of config file '%s'\n", + errorline, configfile); + goto err; + } + free(tofree); + tofree = NULL; + + /* Lets get the config section we are using */ + if (section == NULL) { + section = NCONF_get_string(conf, BASE_SECTION, ENV_DEFAULT_CA); + if (section == NULL) { + lookup_fail(BASE_SECTION, ENV_DEFAULT_CA); + goto err; + } + } + if (conf != NULL) { + p = NCONF_get_string(conf, NULL, "oid_file"); + if (p == NULL) + ERR_clear_error(); + if (p != NULL) { + BIO *oid_bio; + + oid_bio = BIO_new_file(p, "r"); + if (oid_bio == NULL) { + /* + BIO_printf(bio_err, + "problems opening %s for extra oid's\n", p); + ERR_print_errors(bio_err); + */ + ERR_clear_error(); + } else { + OBJ_create_objects(oid_bio); + BIO_free(oid_bio); + } + } + if (!add_oid_section(bio_err, conf)) { + ERR_print_errors(bio_err); + goto err; + } + } + f = NCONF_get_string(conf, section, STRING_MASK); + if (!f) + ERR_clear_error(); + + if (f && !ASN1_STRING_set_default_mask_asc(f)) { + BIO_printf(bio_err, + "Invalid global string mask setting %s\n", f); + goto err; + } + if (chtype != MBSTRING_UTF8) { + f = NCONF_get_string(conf, section, UTF8_IN); + if (!f) + ERR_clear_error(); + else if (!strcmp(f, "yes")) + chtype = MBSTRING_UTF8; + } + db_attr.unique_subject = 1; + p = NCONF_get_string(conf, section, ENV_UNIQUE_SUBJECT); + if (p) { + db_attr.unique_subject = parse_yesno(p, 1); + } else + ERR_clear_error(); + + in = BIO_new(BIO_s_file()); + out = BIO_new(BIO_s_file()); + Sout = BIO_new(BIO_s_file()); + Cout = BIO_new(BIO_s_file()); + if ((in == NULL) || (out == NULL) || (Sout == NULL) || (Cout == NULL)) { + ERR_print_errors(bio_err); + goto err; + } + /*****************************************************************/ + /* report status of cert with serial number given on command line */ + if (ser_status) { + if ((dbfile = NCONF_get_string(conf, section, + ENV_DATABASE)) == NULL) { + lookup_fail(section, ENV_DATABASE); + goto err; + } + db = load_index(dbfile, &db_attr); + if (db == NULL) + goto err; + + if (!index_index(db)) + goto err; + + if (get_certificate_status(ser_status, db) != 1) + BIO_printf(bio_err, "Error verifying serial %s!\n", + ser_status); + goto err; + } + /*****************************************************************/ + /* we definitely need a private key, so let's get it */ + + if ((keyfile == NULL) && ((keyfile = NCONF_get_string(conf, + section, ENV_PRIVATE_KEY)) == NULL)) { + lookup_fail(section, ENV_PRIVATE_KEY); + goto err; + } + if (!key) { + free_key = 1; + if (!app_passwd(bio_err, passargin, NULL, &key, NULL)) { + BIO_printf(bio_err, "Error getting password\n"); + goto err; + } + } + pkey = load_key(bio_err, keyfile, keyform, 0, key, "CA private key"); + if (key) + explicit_bzero(key, strlen(key)); + if (pkey == NULL) { + /* load_key() has already printed an appropriate message */ + goto err; + } + /*****************************************************************/ + /* we need a certificate */ + if (!selfsign || spkac_file || ss_cert_file || gencrl) { + if ((certfile == NULL) && + ((certfile = NCONF_get_string(conf, + section, ENV_CERTIFICATE)) == NULL)) { + lookup_fail(section, ENV_CERTIFICATE); + goto err; + } + x509 = load_cert(bio_err, certfile, FORMAT_PEM, NULL, + "CA certificate"); + if (x509 == NULL) + goto err; + + if (!X509_check_private_key(x509, pkey)) { + BIO_printf(bio_err, + "CA certificate and CA private key do not match\n"); + goto err; + } + } + if (!selfsign) + x509p = x509; + + f = NCONF_get_string(conf, BASE_SECTION, ENV_PRESERVE); + if (f == NULL) + ERR_clear_error(); + if ((f != NULL) && ((*f == 'y') || (*f == 'Y'))) + preserve = 1; + f = NCONF_get_string(conf, BASE_SECTION, ENV_MSIE_HACK); + if (f == NULL) + ERR_clear_error(); + if ((f != NULL) && ((*f == 'y') || (*f == 'Y'))) + msie_hack = 1; + + f = NCONF_get_string(conf, section, ENV_NAMEOPT); + + if (f) { + if (!set_name_ex(&nameopt, f)) { + BIO_printf(bio_err, + "Invalid name options: \"%s\"\n", f); + goto err; + } + default_op = 0; + } else + ERR_clear_error(); + + f = NCONF_get_string(conf, section, ENV_CERTOPT); + + if (f) { + if (!set_cert_ex(&certopt, f)) { + BIO_printf(bio_err, + "Invalid certificate options: \"%s\"\n", f); + goto err; + } + default_op = 0; + } else + ERR_clear_error(); + + f = NCONF_get_string(conf, section, ENV_EXTCOPY); + + if (f) { + if (!set_ext_copy(&ext_copy, f)) { + BIO_printf(bio_err, + "Invalid extension copy option: \"%s\"\n", f); + goto err; + } + } else + ERR_clear_error(); + + /*****************************************************************/ + /* lookup where to write new certificates */ + if (outdir == NULL && req) { + if ((outdir = NCONF_get_string(conf, section, + ENV_NEW_CERTS_DIR)) == NULL) { + BIO_printf(bio_err, "output directory %s not defined\n", + ENV_NEW_CERTS_DIR); + goto err; + } + } + /*****************************************************************/ + /* we need to load the database file */ + if ((dbfile = NCONF_get_string(conf, section, ENV_DATABASE)) == NULL) { + lookup_fail(section, ENV_DATABASE); + goto err; + } + db = load_index(dbfile, &db_attr); + if (db == NULL) + goto err; + + /* Lets check some fields */ + for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) { + pp = sk_OPENSSL_PSTRING_value(db->db->data, i); + if ((pp[DB_type][0] != DB_TYPE_REV) && + (pp[DB_rev_date][0] != '\0')) { + BIO_printf(bio_err, "entry %d: not revoked yet, but has a revocation date\n", i + 1); + goto err; + } + if ((pp[DB_type][0] == DB_TYPE_REV) && + !make_revoked(NULL, pp[DB_rev_date])) { + BIO_printf(bio_err, " in entry %d\n", i + 1); + goto err; + } + if (!check_time_format((char *) pp[DB_exp_date])) { + BIO_printf(bio_err, "entry %d: invalid expiry date\n", + i + 1); + goto err; + } + p = pp[DB_serial]; + j = strlen(p); + if (*p == '-') { + p++; + j--; + } + if ((j & 1) || (j < 2)) { + BIO_printf(bio_err, + "entry %d: bad serial number length (%d)\n", + i + 1, j); + goto err; + } + while (*p) { + if (!(((*p >= '0') && (*p <= '9')) || + ((*p >= 'A') && (*p <= 'F')) || + ((*p >= 'a') && (*p <= 'f')))) { + BIO_printf(bio_err, "entry %d: bad serial number characters, char pos %ld, char is '%c'\n", i + 1, (long) (p - pp[DB_serial]), *p); + goto err; + } + p++; + } + } + if (verbose) { + BIO_set_fp(out, stdout, BIO_NOCLOSE | BIO_FP_TEXT); /* cannot fail */ + TXT_DB_write(out, db->db); + BIO_printf(bio_err, "%d entries loaded from the database\n", + sk_OPENSSL_PSTRING_num(db->db->data)); + BIO_printf(bio_err, "generating index\n"); + } + if (!index_index(db)) + goto err; + + /*****************************************************************/ + /* Update the db file for expired certificates */ + if (doupdatedb) { + if (verbose) + BIO_printf(bio_err, "Updating %s ...\n", dbfile); + + i = do_updatedb(db); + if (i == -1) { + BIO_printf(bio_err, "Malloc failure\n"); + goto err; + } else if (i == 0) { + if (verbose) + BIO_printf(bio_err, + "No entries found to mark expired\n"); + } else { + if (!save_index(dbfile, "new", db)) + goto err; + + if (!rotate_index(dbfile, "new", "old")) + goto err; + + if (verbose) + BIO_printf(bio_err, + "Done. %d entries marked as expired\n", i); + } + } + /*****************************************************************/ + /* Read extentions config file */ + if (extfile) { + extconf = NCONF_new(NULL); + if (NCONF_load(extconf, extfile, &errorline) <= 0) { + if (errorline <= 0) + BIO_printf(bio_err, + "ERROR: loading the config file '%s'\n", + extfile); + else + BIO_printf(bio_err, + "ERROR: on line %ld of config file '%s'\n", + errorline, extfile); + ret = 1; + goto err; + } + if (verbose) + BIO_printf(bio_err, + "Successfully loaded extensions file %s\n", + extfile); + + /* We can have sections in the ext file */ + if (!extensions && !(extensions = NCONF_get_string(extconf, + "default", "extensions"))) + extensions = "default"; + } + /*****************************************************************/ + if (req || gencrl) { + if (outfile != NULL) { + if (BIO_write_filename(Sout, outfile) <= 0) { + perror(outfile); + goto err; + } + } else { + BIO_set_fp(Sout, stdout, BIO_NOCLOSE | BIO_FP_TEXT); + } + } + if ((md == NULL) && ((md = NCONF_get_string(conf, section, + ENV_DEFAULT_MD)) == NULL)) { + lookup_fail(section, ENV_DEFAULT_MD); + goto err; + } + if (!strcmp(md, "default")) { + int def_nid; + if (EVP_PKEY_get_default_digest_nid(pkey, &def_nid) <= 0) { + BIO_puts(bio_err, "no default digest\n"); + goto err; + } + md = (char *) OBJ_nid2sn(def_nid); + } + if ((dgst = EVP_get_digestbyname(md)) == NULL) { + BIO_printf(bio_err, + "%s is an unsupported message digest type\n", md); + goto err; + } + if (req) { + if ((email_dn == 1) && ((tmp_email_dn = NCONF_get_string(conf, + section, ENV_DEFAULT_EMAIL_DN)) != NULL)) { + if (strcmp(tmp_email_dn, "no") == 0) + email_dn = 0; + } + if (verbose) + BIO_printf(bio_err, "message digest is %s\n", + OBJ_nid2ln(dgst->type)); + if ((policy == NULL) && ((policy = NCONF_get_string(conf, + section, ENV_POLICY)) == NULL)) { + lookup_fail(section, ENV_POLICY); + goto err; + } + if (verbose) + BIO_printf(bio_err, "policy is %s\n", policy); + + if ((serialfile = NCONF_get_string(conf, section, + ENV_SERIAL)) == NULL) { + lookup_fail(section, ENV_SERIAL); + goto err; + } + if (!extconf) { + /* + * no '-extfile' option, so we look for extensions in + * the main configuration file + */ + if (!extensions) { + extensions = NCONF_get_string(conf, section, + ENV_EXTENSIONS); + if (!extensions) + ERR_clear_error(); + } + if (extensions) { + /* Check syntax of file */ + X509V3_CTX ctx; + X509V3_set_ctx_test(&ctx); + X509V3_set_nconf(&ctx, conf); + if (!X509V3_EXT_add_nconf(conf, &ctx, + extensions, NULL)) { + BIO_printf(bio_err, + "Error Loading extension section %s\n", + extensions); + ret = 1; + goto err; + } + } + } + if (startdate == NULL) { + startdate = NCONF_get_string(conf, section, + ENV_DEFAULT_STARTDATE); + if (startdate == NULL) + ERR_clear_error(); + } + if (startdate && !ASN1_TIME_set_string(NULL, startdate)) { + BIO_printf(bio_err, "start date is invalid, it should be YYMMDDHHMMSSZ or YYYYMMDDHHMMSSZ\n"); + goto err; + } + if (startdate == NULL) + startdate = "today"; + + if (enddate == NULL) { + enddate = NCONF_get_string(conf, section, + ENV_DEFAULT_ENDDATE); + if (enddate == NULL) + ERR_clear_error(); + } + if (enddate && !ASN1_TIME_set_string(NULL, enddate)) { + BIO_printf(bio_err, "end date is invalid, it should be YYMMDDHHMMSSZ or YYYYMMDDHHMMSSZ\n"); + goto err; + } + if (days == 0) { + if (!NCONF_get_number(conf, section, + ENV_DEFAULT_DAYS, &days)) + days = 0; + } + if (!enddate && (days == 0)) { + BIO_printf(bio_err, + "cannot lookup how many days to certify for\n"); + goto err; + } + if ((serial = load_serial(serialfile, create_ser, NULL)) == + NULL) { + BIO_printf(bio_err, + "error while loading serial number\n"); + goto err; + } + if (verbose) { + if (BN_is_zero(serial)) + BIO_printf(bio_err, + "next serial number is 00\n"); + else { + if ((f = BN_bn2hex(serial)) == NULL) + goto err; + BIO_printf(bio_err, + "next serial number is %s\n", f); + free(f); + } + } + if ((attribs = NCONF_get_section(conf, policy)) == NULL) { + BIO_printf(bio_err, + "unable to find 'section' for %s\n", policy); + goto err; + } + if ((cert_sk = sk_X509_new_null()) == NULL) { + BIO_printf(bio_err, "Memory allocation failure\n"); + goto err; + } + if (spkac_file != NULL) { + total++; + j = certify_spkac(&x, spkac_file, pkey, x509, dgst, + sigopts, attribs, db, serial, subj, chtype, + multirdn, email_dn, startdate, enddate, days, + extensions, conf, verbose, certopt, nameopt, + default_op, ext_copy); + if (j < 0) + goto err; + if (j > 0) { + total_done++; + BIO_printf(bio_err, "\n"); + if (!BN_add_word(serial, 1)) + goto err; + if (!sk_X509_push(cert_sk, x)) { + BIO_printf(bio_err, + "Memory allocation failure\n"); + goto err; + } + if (outfile) { + output_der = 1; + batch = 1; + } + } + } + if (ss_cert_file != NULL) { + total++; + j = certify_cert(&x, ss_cert_file, pkey, x509, dgst, + sigopts, attribs, db, serial, subj, chtype, + multirdn, email_dn, startdate, enddate, days, batch, + extensions, conf, verbose, certopt, nameopt, + default_op, ext_copy); + if (j < 0) + goto err; + if (j > 0) { + total_done++; + BIO_printf(bio_err, "\n"); + if (!BN_add_word(serial, 1)) + goto err; + if (!sk_X509_push(cert_sk, x)) { + BIO_printf(bio_err, + "Memory allocation failure\n"); + goto err; + } + } + } + if (infile != NULL) { + total++; + j = certify(&x, infile, pkey, x509p, dgst, sigopts, + attribs, db, serial, subj, chtype, multirdn, + email_dn, startdate, enddate, days, batch, + extensions, conf, verbose, certopt, nameopt, + default_op, ext_copy, selfsign); + if (j < 0) + goto err; + if (j > 0) { + total_done++; + BIO_printf(bio_err, "\n"); + if (!BN_add_word(serial, 1)) + goto err; + if (!sk_X509_push(cert_sk, x)) { + BIO_printf(bio_err, + "Memory allocation failure\n"); + goto err; + } + } + } + for (i = 0; i < argc; i++) { + total++; + j = certify(&x, argv[i], pkey, x509p, dgst, sigopts, + attribs, db, serial, subj, chtype, multirdn, + email_dn, startdate, enddate, days, batch, + extensions, conf, verbose, certopt, nameopt, + default_op, ext_copy, selfsign); + if (j < 0) + goto err; + if (j > 0) { + total_done++; + BIO_printf(bio_err, "\n"); + if (!BN_add_word(serial, 1)) + goto err; + if (!sk_X509_push(cert_sk, x)) { + BIO_printf(bio_err, + "Memory allocation failure\n"); + goto err; + } + } + } + /* + * we have a stack of newly certified certificates and a data + * base and serial number that need updating + */ + + if (sk_X509_num(cert_sk) > 0) { + if (!batch) { + char answer[10]; + + BIO_printf(bio_err, "\n%d out of %d certificate requests certified, commit? [y/n]", total_done, total); + (void) BIO_flush(bio_err); + if (!fgets(answer, sizeof answer - 1, stdin)) { + BIO_printf(bio_err, "CERTIFICATION CANCELED: I/O error\n"); + ret = 0; + goto err; + } + if ((answer[0] != 'y') && (answer[0] != 'Y')) { + BIO_printf(bio_err, "CERTIFICATION CANCELED\n"); + ret = 0; + goto err; + } + } + BIO_printf(bio_err, "Write out database with %d new entries\n", sk_X509_num(cert_sk)); + + if (!save_serial(serialfile, "new", serial, NULL)) + goto err; + + if (!save_index(dbfile, "new", db)) + goto err; + } + if (verbose) + BIO_printf(bio_err, "writing new certificates\n"); + for (i = 0; i < sk_X509_num(cert_sk); i++) { + int k; + char *serialstr; + unsigned char *data; + char pempath[PATH_MAX]; + + x = sk_X509_value(cert_sk, i); + + j = x->cert_info->serialNumber->length; + data = (unsigned char *)x->cert_info->serialNumber->data; + if (j > 0) + serialstr = bin2hex(data, j); + else + serialstr = strdup("00"); + if (serialstr) { + k = snprintf(pempath, sizeof(pempath), + "%s/%s.pem", outdir, serialstr); + free(serialstr); + if (k == -1 || k >= sizeof(pempath)) { + BIO_printf(bio_err, + "certificate file name too long\n"); + goto err; + } + } else { + BIO_printf(bio_err, + "memory allocation failed\n"); + goto err; + } + if (verbose) + BIO_printf(bio_err, "writing %s\n", pempath); + + if (BIO_write_filename(Cout, pempath) <= 0) { + perror(pempath); + goto err; + } + write_new_certificate(Cout, x, 0, notext); + write_new_certificate(Sout, x, output_der, notext); + } + + if (sk_X509_num(cert_sk)) { + /* Rename the database and the serial file */ + if (!rotate_serial(serialfile, "new", "old")) + goto err; + + if (!rotate_index(dbfile, "new", "old")) + goto err; + + BIO_printf(bio_err, "Data Base Updated\n"); + } + } + /*****************************************************************/ + if (gencrl) { + int crl_v2 = 0; + if (!crl_ext) { + crl_ext = NCONF_get_string(conf, section, ENV_CRLEXT); + if (!crl_ext) + ERR_clear_error(); + } + if (crl_ext) { + /* Check syntax of file */ + X509V3_CTX ctx; + X509V3_set_ctx_test(&ctx); + X509V3_set_nconf(&ctx, conf); + if (!X509V3_EXT_add_nconf(conf, &ctx, crl_ext, NULL)) { + BIO_printf(bio_err, + "Error Loading CRL extension section %s\n", + crl_ext); + ret = 1; + goto err; + } + } + if ((crlnumberfile = NCONF_get_string(conf, section, + ENV_CRLNUMBER)) != NULL) + if ((crlnumber = load_serial(crlnumberfile, 0, + NULL)) == NULL) { + BIO_printf(bio_err, + "error while loading CRL number\n"); + goto err; + } + if (!crldays && !crlhours && !crlsec) { + if (!NCONF_get_number(conf, section, + ENV_DEFAULT_CRL_DAYS, &crldays)) + crldays = 0; + if (!NCONF_get_number(conf, section, + ENV_DEFAULT_CRL_HOURS, &crlhours)) + crlhours = 0; + ERR_clear_error(); + } + if ((crldays == 0) && (crlhours == 0) && (crlsec == 0)) { + BIO_printf(bio_err, "cannot lookup how long until the next CRL is issued\n"); + goto err; + } + if (verbose) + BIO_printf(bio_err, "making CRL\n"); + if ((crl = X509_CRL_new()) == NULL) + goto err; + if (!X509_CRL_set_issuer_name(crl, X509_get_subject_name(x509))) + goto err; + + tmptm = ASN1_TIME_new(); + if (!tmptm) + goto err; + X509_gmtime_adj(tmptm, 0); + X509_CRL_set_lastUpdate(crl, tmptm); + if (!X509_time_adj_ex(tmptm, crldays, + crlhours * 60 * 60 + crlsec, NULL)) { + BIO_puts(bio_err, "error setting CRL nextUpdate\n"); + goto err; + } + X509_CRL_set_nextUpdate(crl, tmptm); + + ASN1_TIME_free(tmptm); + + for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) { + pp = sk_OPENSSL_PSTRING_value(db->db->data, i); + if (pp[DB_type][0] == DB_TYPE_REV) { + if ((r = X509_REVOKED_new()) == NULL) + goto err; + j = make_revoked(r, pp[DB_rev_date]); + if (!j) + goto err; + if (j == 2) + crl_v2 = 1; + if (!BN_hex2bn(&serial, pp[DB_serial])) + goto err; + tmpser = BN_to_ASN1_INTEGER(serial, NULL); + BN_free(serial); + serial = NULL; + if (!tmpser) + goto err; + X509_REVOKED_set_serialNumber(r, tmpser); + ASN1_INTEGER_free(tmpser); + X509_CRL_add0_revoked(crl, r); + } + } + + /* + * sort the data so it will be written in serial number order + */ + X509_CRL_sort(crl); + + /* we now have a CRL */ + if (verbose) + BIO_printf(bio_err, "signing CRL\n"); + + /* Add any extensions asked for */ + + if (crl_ext || crlnumberfile != NULL) { + X509V3_CTX crlctx; + X509V3_set_ctx(&crlctx, x509, NULL, NULL, crl, 0); + X509V3_set_nconf(&crlctx, conf); + + if (crl_ext) + if (!X509V3_EXT_CRL_add_nconf(conf, &crlctx, + crl_ext, crl)) + goto err; + if (crlnumberfile != NULL) { + tmpser = BN_to_ASN1_INTEGER(crlnumber, NULL); + if (!tmpser) + goto err; + X509_CRL_add1_ext_i2d(crl, NID_crl_number, + tmpser, 0, 0); + ASN1_INTEGER_free(tmpser); + crl_v2 = 1; + if (!BN_add_word(crlnumber, 1)) + goto err; + } + } + if (crl_ext || crl_v2) { + if (!X509_CRL_set_version(crl, 1)) + goto err; /* version 2 CRL */ + } + if (crlnumberfile != NULL) /* we have a CRL number that + * need updating */ + if (!save_serial(crlnumberfile, "new", crlnumber, NULL)) + goto err; + + if (crlnumber) { + BN_free(crlnumber); + crlnumber = NULL; + } + if (!do_X509_CRL_sign(bio_err, crl, pkey, dgst, sigopts)) + goto err; + + PEM_write_bio_X509_CRL(Sout, crl); + + if (crlnumberfile != NULL) /* Rename the crlnumber file */ + if (!rotate_serial(crlnumberfile, "new", "old")) + goto err; + + } + /*****************************************************************/ + if (dorevoke) { + if (infile == NULL) { + BIO_printf(bio_err, "no input files\n"); + goto err; + } else { + X509 *revcert; + revcert = load_cert(bio_err, infile, FORMAT_PEM, + NULL, infile); + if (revcert == NULL) + goto err; + j = do_revoke(revcert, db, rev_type, rev_arg); + if (j <= 0) + goto err; + X509_free(revcert); + + if (!save_index(dbfile, "new", db)) + goto err; + + if (!rotate_index(dbfile, "new", "old")) + goto err; + + BIO_printf(bio_err, "Data Base Updated\n"); + } + } + /*****************************************************************/ + ret = 0; + +err: + free(tofree); + + BIO_free_all(Cout); + BIO_free_all(Sout); + BIO_free_all(out); + BIO_free_all(in); + + if (cert_sk) + sk_X509_pop_free(cert_sk, X509_free); + + if (ret) + ERR_print_errors(bio_err); + if (free_key && key) + free(key); + BN_free(serial); + BN_free(crlnumber); + free_index(db); + if (sigopts) + sk_OPENSSL_STRING_free(sigopts); + EVP_PKEY_free(pkey); + if (x509) + X509_free(x509); + X509_CRL_free(crl); + NCONF_free(conf); + NCONF_free(extconf); + OBJ_cleanup(); + + return (ret); +} + +static void +lookup_fail(const char *name, const char *tag) +{ + BIO_printf(bio_err, "variable lookup failed for %s::%s\n", name, tag); +} + +static int +certify(X509 ** xret, char *infile, EVP_PKEY * pkey, X509 * x509, + const EVP_MD * dgst, STACK_OF(OPENSSL_STRING) * sigopts, + STACK_OF(CONF_VALUE) * policy, CA_DB * db, BIGNUM * serial, char *subj, + unsigned long chtype, int multirdn, int email_dn, char *startdate, + char *enddate, long days, int batch, char *ext_sect, CONF * lconf, + int verbose, unsigned long certopt, unsigned long nameopt, int default_op, + int ext_copy, int selfsign) +{ + X509_REQ *req = NULL; + BIO *in = NULL; + EVP_PKEY *pktmp = NULL; + int ok = -1, i; + + in = BIO_new(BIO_s_file()); + + if (BIO_read_filename(in, infile) <= 0) { + perror(infile); + goto err; + } + if ((req = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL)) == NULL) { + BIO_printf(bio_err, "Error reading certificate request in %s\n", + infile); + goto err; + } + if (verbose) + X509_REQ_print(bio_err, req); + + BIO_printf(bio_err, "Check that the request matches the signature\n"); + + if (selfsign && !X509_REQ_check_private_key(req, pkey)) { + BIO_printf(bio_err, + "Certificate request and CA private key do not match\n"); + ok = 0; + goto err; + } + if ((pktmp = X509_REQ_get_pubkey(req)) == NULL) { + BIO_printf(bio_err, "error unpacking public key\n"); + goto err; + } + i = X509_REQ_verify(req, pktmp); + EVP_PKEY_free(pktmp); + if (i < 0) { + ok = 0; + BIO_printf(bio_err, "Signature verification problems....\n"); + goto err; + } + if (i == 0) { + ok = 0; + BIO_printf(bio_err, + "Signature did not match the certificate request\n"); + goto err; + } else + BIO_printf(bio_err, "Signature ok\n"); + + ok = do_body(xret, pkey, x509, dgst, sigopts, policy, db, serial, + subj, chtype, multirdn, email_dn, startdate, enddate, days, batch, + verbose, req, ext_sect, lconf, certopt, nameopt, default_op, + ext_copy, selfsign); + +err: + if (req != NULL) + X509_REQ_free(req); + if (in != NULL) + BIO_free(in); + return (ok); +} + +static int +certify_cert(X509 ** xret, char *infile, EVP_PKEY * pkey, X509 * x509, + const EVP_MD * dgst, STACK_OF(OPENSSL_STRING) * sigopts, + STACK_OF(CONF_VALUE) * policy, CA_DB * db, BIGNUM * serial, char *subj, + unsigned long chtype, int multirdn, int email_dn, char *startdate, + char *enddate, long days, int batch, char *ext_sect, CONF * lconf, + int verbose, unsigned long certopt, unsigned long nameopt, int default_op, + int ext_copy) +{ + X509 *req = NULL; + X509_REQ *rreq = NULL; + EVP_PKEY *pktmp = NULL; + int ok = -1, i; + + if ((req = load_cert(bio_err, infile, FORMAT_PEM, NULL, + infile)) == NULL) + goto err; + if (verbose) + X509_print(bio_err, req); + + BIO_printf(bio_err, "Check that the request matches the signature\n"); + + if ((pktmp = X509_get_pubkey(req)) == NULL) { + BIO_printf(bio_err, "error unpacking public key\n"); + goto err; + } + i = X509_verify(req, pktmp); + EVP_PKEY_free(pktmp); + if (i < 0) { + ok = 0; + BIO_printf(bio_err, "Signature verification problems....\n"); + goto err; + } + if (i == 0) { + ok = 0; + BIO_printf(bio_err, + "Signature did not match the certificate\n"); + goto err; + } else + BIO_printf(bio_err, "Signature ok\n"); + + if ((rreq = X509_to_X509_REQ(req, NULL, EVP_md5())) == NULL) + goto err; + + ok = do_body(xret, pkey, x509, dgst, sigopts, policy, db, serial, + subj, chtype, multirdn, email_dn, startdate, enddate, days, batch, + verbose, rreq, ext_sect, lconf, certopt, nameopt, default_op, + ext_copy, 0); + +err: + if (rreq != NULL) + X509_REQ_free(rreq); + if (req != NULL) + X509_free(req); + return (ok); +} + +static int +do_body(X509 ** xret, EVP_PKEY * pkey, X509 * x509, const EVP_MD * dgst, + STACK_OF(OPENSSL_STRING) * sigopts, STACK_OF(CONF_VALUE) * policy, + CA_DB * db, BIGNUM * serial, char *subj, unsigned long chtype, int multirdn, + int email_dn, char *startdate, char *enddate, long days, int batch, + int verbose, X509_REQ * req, char *ext_sect, CONF * lconf, + unsigned long certopt, unsigned long nameopt, int default_op, + int ext_copy, int selfsign) +{ + X509_NAME *name = NULL, *CAname = NULL, *subject = NULL, *dn_subject = NULL; + ASN1_UTCTIME *tm, *tmptm; + ASN1_STRING *str, *str2; + ASN1_OBJECT *obj; + X509 *ret = NULL; + X509_CINF *ci; + X509_NAME_ENTRY *ne; + X509_NAME_ENTRY *tne, *push; + EVP_PKEY *pktmp; + int ok = -1, i, j, last, nid; + const char *p; + CONF_VALUE *cv; + OPENSSL_STRING row[DB_NUMBER]; + OPENSSL_STRING *irow = NULL; + OPENSSL_STRING *rrow = NULL; + + tmptm = ASN1_UTCTIME_new(); + if (tmptm == NULL) { + BIO_printf(bio_err, "malloc error\n"); + return (0); + } + for (i = 0; i < DB_NUMBER; i++) + row[i] = NULL; + + if (subj) { + X509_NAME *n = parse_name(subj, chtype, multirdn); + + if (!n) { + ERR_print_errors(bio_err); + goto err; + } + X509_REQ_set_subject_name(req, n); + req->req_info->enc.modified = 1; + X509_NAME_free(n); + } + if (default_op) + BIO_printf(bio_err, + "The Subject's Distinguished Name is as follows\n"); + + name = X509_REQ_get_subject_name(req); + for (i = 0; i < X509_NAME_entry_count(name); i++) { + ne = X509_NAME_get_entry(name, i); + str = X509_NAME_ENTRY_get_data(ne); + obj = X509_NAME_ENTRY_get_object(ne); + + if (msie_hack) { + /* assume all type should be strings */ + nid = OBJ_obj2nid(ne->object); + + if (str->type == V_ASN1_UNIVERSALSTRING) + ASN1_UNIVERSALSTRING_to_string(str); + + if ((str->type == V_ASN1_IA5STRING) && + (nid != NID_pkcs9_emailAddress)) + str->type = V_ASN1_T61STRING; + + if ((nid == NID_pkcs9_emailAddress) && + (str->type == V_ASN1_PRINTABLESTRING)) + str->type = V_ASN1_IA5STRING; + } + /* If no EMAIL is wanted in the subject */ + if ((OBJ_obj2nid(obj) == NID_pkcs9_emailAddress) && (!email_dn)) + continue; + + /* check some things */ + if ((OBJ_obj2nid(obj) == NID_pkcs9_emailAddress) && + (str->type != V_ASN1_IA5STRING)) { + BIO_printf(bio_err, "\nemailAddress type needs to be of type IA5STRING\n"); + goto err; + } + if ((str->type != V_ASN1_BMPSTRING) && + (str->type != V_ASN1_UTF8STRING)) { + j = ASN1_PRINTABLE_type(str->data, str->length); + if (((j == V_ASN1_T61STRING) && + (str->type != V_ASN1_T61STRING)) || + ((j == V_ASN1_IA5STRING) && + (str->type == V_ASN1_PRINTABLESTRING))) { + BIO_printf(bio_err, "\nThe string contains characters that are illegal for the ASN.1 type\n"); + goto err; + } + } + if (default_op) + old_entry_print(bio_err, obj, str); + } + + /* Ok, now we check the 'policy' stuff. */ + if ((subject = X509_NAME_new()) == NULL) { + BIO_printf(bio_err, "Memory allocation failure\n"); + goto err; + } + /* take a copy of the issuer name before we mess with it. */ + if (selfsign) + CAname = X509_NAME_dup(name); + else + CAname = X509_NAME_dup(x509->cert_info->subject); + if (CAname == NULL) + goto err; + str = str2 = NULL; + + for (i = 0; i < sk_CONF_VALUE_num(policy); i++) { + cv = sk_CONF_VALUE_value(policy, i); /* get the object id */ + if ((j = OBJ_txt2nid(cv->name)) == NID_undef) { + BIO_printf(bio_err, "%s:unknown object type in 'policy' configuration\n", cv->name); + goto err; + } + obj = OBJ_nid2obj(j); + + last = -1; + for (;;) { + /* lookup the object in the supplied name list */ + j = X509_NAME_get_index_by_OBJ(name, obj, last); + if (j < 0) { + if (last != -1) + break; + tne = NULL; + } else { + tne = X509_NAME_get_entry(name, j); + } + last = j; + + /* depending on the 'policy', decide what to do. */ + push = NULL; + if (strcmp(cv->value, "optional") == 0) { + if (tne != NULL) + push = tne; + } else if (strcmp(cv->value, "supplied") == 0) { + if (tne == NULL) { + BIO_printf(bio_err, "The %s field needed to be supplied and was missing\n", cv->name); + goto err; + } else + push = tne; + } else if (strcmp(cv->value, "match") == 0) { + int last2; + + if (tne == NULL) { + BIO_printf(bio_err, "The mandatory %s field was missing\n", cv->name); + goto err; + } + last2 = -1; + +again2: + j = X509_NAME_get_index_by_OBJ(CAname, obj, last2); + if ((j < 0) && (last2 == -1)) { + BIO_printf(bio_err, "The %s field does not exist in the CA certificate,\nthe 'policy' is misconfigured\n", cv->name); + goto err; + } + if (j >= 0) { + push = X509_NAME_get_entry(CAname, j); + str = X509_NAME_ENTRY_get_data(tne); + str2 = X509_NAME_ENTRY_get_data(push); + last2 = j; + if (ASN1_STRING_cmp(str, str2) != 0) + goto again2; + } + if (j < 0) { + BIO_printf(bio_err, "The %s field needed to be the same in the\nCA certificate (%s) and the request (%s)\n", cv->name, ((str2 == NULL) ? "NULL" : (char *) str2->data), ((str == NULL) ? "NULL" : (char *) str->data)); + goto err; + } + } else { + BIO_printf(bio_err, "%s:invalid type in 'policy' configuration\n", cv->value); + goto err; + } + + if (push != NULL) { + if (!X509_NAME_add_entry(subject, push, + -1, 0)) { + if (push != NULL) + X509_NAME_ENTRY_free(push); + BIO_printf(bio_err, + "Memory allocation failure\n"); + goto err; + } + } + if (j < 0) + break; + } + } + + if (preserve) { + X509_NAME_free(subject); + /* subject=X509_NAME_dup(X509_REQ_get_subject_name(req)); */ + subject = X509_NAME_dup(name); + if (subject == NULL) + goto err; + } + if (verbose) + BIO_printf(bio_err, "The subject name appears to be ok, checking data base for clashes\n"); + + /* Build the correct Subject if no email is wanted in the subject */ + /* + * and add it later on because of the method extensions are added + * (altName) + */ + + if (email_dn) + dn_subject = subject; + else { + X509_NAME_ENTRY *tmpne; + /* + * Its best to dup the subject DN and then delete any email + * addresses because this retains its structure. + */ + if (!(dn_subject = X509_NAME_dup(subject))) { + BIO_printf(bio_err, "Memory allocation failure\n"); + goto err; + } + while ((i = X509_NAME_get_index_by_NID(dn_subject, + NID_pkcs9_emailAddress, -1)) >= 0) { + tmpne = X509_NAME_get_entry(dn_subject, i); + X509_NAME_delete_entry(dn_subject, i); + X509_NAME_ENTRY_free(tmpne); + } + } + + if (BN_is_zero(serial)) + row[DB_serial] = strdup("00"); + else + row[DB_serial] = BN_bn2hex(serial); + if (row[DB_serial] == NULL) { + BIO_printf(bio_err, "Memory allocation failure\n"); + goto err; + } + if (db->attributes.unique_subject) { + OPENSSL_STRING *crow = row; + + rrow = TXT_DB_get_by_index(db->db, DB_name, crow); + if (rrow != NULL) { + BIO_printf(bio_err, + "ERROR:There is already a certificate for %s\n", + row[DB_name]); + } + } + if (rrow == NULL) { + rrow = TXT_DB_get_by_index(db->db, DB_serial, row); + if (rrow != NULL) { + BIO_printf(bio_err, + "ERROR:Serial number %s has already been issued,\n", + row[DB_serial]); + BIO_printf(bio_err, " check the database/serial_file for corruption\n"); + } + } + if (rrow != NULL) { + BIO_printf(bio_err, + "The matching entry has the following details\n"); + if (rrow[DB_type][0] == 'E') + p = "Expired"; + else if (rrow[DB_type][0] == 'R') + p = "Revoked"; + else if (rrow[DB_type][0] == 'V') + p = "Valid"; + else + p = "\ninvalid type, Data base error\n"; + BIO_printf(bio_err, "Type :%s\n", p); + if (rrow[DB_type][0] == 'R') { + p = rrow[DB_exp_date]; + if (p == NULL) + p = "undef"; + BIO_printf(bio_err, "Was revoked on:%s\n", p); + } + p = rrow[DB_exp_date]; + if (p == NULL) + p = "undef"; + BIO_printf(bio_err, "Expires on :%s\n", p); + p = rrow[DB_serial]; + if (p == NULL) + p = "undef"; + BIO_printf(bio_err, "Serial Number :%s\n", p); + p = rrow[DB_file]; + if (p == NULL) + p = "undef"; + BIO_printf(bio_err, "File name :%s\n", p); + p = rrow[DB_name]; + if (p == NULL) + p = "undef"; + BIO_printf(bio_err, "Subject Name :%s\n", p); + ok = -1; /* This is now a 'bad' error. */ + goto err; + } + /* We are now totally happy, lets make and sign the certificate */ + if (verbose) + BIO_printf(bio_err, "Everything appears to be ok, creating and signing the certificate\n"); + + if ((ret = X509_new()) == NULL) + goto err; + ci = ret->cert_info; + +#ifdef X509_V3 + /* Make it an X509 v3 certificate. */ + if (!X509_set_version(ret, 2)) + goto err; +#endif + if (ci->serialNumber == NULL) + goto err; + if (BN_to_ASN1_INTEGER(serial, ci->serialNumber) == NULL) + goto err; + if (selfsign) { + if (!X509_set_issuer_name(ret, subject)) + goto err; + } else { + if (!X509_set_issuer_name(ret, X509_get_subject_name(x509))) + goto err; + } + + if (strcmp(startdate, "today") == 0) + X509_gmtime_adj(X509_get_notBefore(ret), 0); + else + ASN1_TIME_set_string(X509_get_notBefore(ret), startdate); + + if (enddate == NULL) + X509_time_adj_ex(X509_get_notAfter(ret), days, 0, NULL); + else + ASN1_TIME_set_string(X509_get_notAfter(ret), enddate); + + if (!X509_set_subject_name(ret, subject)) + goto err; + + pktmp = X509_REQ_get_pubkey(req); + i = X509_set_pubkey(ret, pktmp); + EVP_PKEY_free(pktmp); + if (!i) + goto err; + + /* Lets add the extensions, if there are any */ + if (ext_sect) { + X509V3_CTX ctx; + if (ci->version == NULL) + if ((ci->version = ASN1_INTEGER_new()) == NULL) + goto err; + ASN1_INTEGER_set(ci->version, 2); /* version 3 certificate */ + + /* + * Free the current entries if any, there should not be any I + * believe + */ + if (ci->extensions != NULL) + sk_X509_EXTENSION_pop_free(ci->extensions, + X509_EXTENSION_free); + + ci->extensions = NULL; + + /* Initialize the context structure */ + if (selfsign) + X509V3_set_ctx(&ctx, ret, ret, req, NULL, 0); + else + X509V3_set_ctx(&ctx, x509, ret, req, NULL, 0); + + if (extconf) { + if (verbose) + BIO_printf(bio_err, + "Extra configuration file found\n"); + + /* Use the extconf configuration db LHASH */ + X509V3_set_nconf(&ctx, extconf); + + /* Test the structure (needed?) */ + /* X509V3_set_ctx_test(&ctx); */ + + /* Adds exts contained in the configuration file */ + if (!X509V3_EXT_add_nconf(extconf, &ctx, + ext_sect, ret)) { + BIO_printf(bio_err, + "ERROR: adding extensions in section %s\n", + ext_sect); + ERR_print_errors(bio_err); + goto err; + } + if (verbose) + BIO_printf(bio_err, "Successfully added extensions from file.\n"); + } else if (ext_sect) { + /* We found extensions to be set from config file */ + X509V3_set_nconf(&ctx, lconf); + + if (!X509V3_EXT_add_nconf(lconf, &ctx, ext_sect, ret)) { + BIO_printf(bio_err, + "ERROR: adding extensions in section %s\n", + ext_sect); + ERR_print_errors(bio_err); + goto err; + } + if (verbose) + BIO_printf(bio_err, "Successfully added extensions from config\n"); + } + } + /* Copy extensions from request (if any) */ + + if (!copy_extensions(ret, req, ext_copy)) { + BIO_printf(bio_err, "ERROR: adding extensions from request\n"); + ERR_print_errors(bio_err); + goto err; + } + /* Set the right value for the noemailDN option */ + if (email_dn == 0) { + if (!X509_set_subject_name(ret, dn_subject)) + goto err; + } + if (!default_op) { + BIO_printf(bio_err, "Certificate Details:\n"); + /* + * Never print signature details because signature not + * present + */ + certopt |= X509_FLAG_NO_SIGDUMP | X509_FLAG_NO_SIGNAME; + X509_print_ex(bio_err, ret, nameopt, certopt); + } + BIO_printf(bio_err, "Certificate is to be certified until "); + ASN1_TIME_print(bio_err, X509_get_notAfter(ret)); + if (days) + BIO_printf(bio_err, " (%ld days)", days); + BIO_printf(bio_err, "\n"); + + if (!batch) { + char answer[25]; + + BIO_printf(bio_err, "Sign the certificate? [y/n]:"); + (void) BIO_flush(bio_err); + if (!fgets(answer, sizeof(answer) - 1, stdin)) { + BIO_printf(bio_err, + "CERTIFICATE WILL NOT BE CERTIFIED: I/O error\n"); + ok = 0; + goto err; + } + if (!((answer[0] == 'y') || (answer[0] == 'Y'))) { + BIO_printf(bio_err, + "CERTIFICATE WILL NOT BE CERTIFIED\n"); + ok = 0; + goto err; + } + } + pktmp = X509_get_pubkey(ret); + if (EVP_PKEY_missing_parameters(pktmp) && + !EVP_PKEY_missing_parameters(pkey)) + EVP_PKEY_copy_parameters(pktmp, pkey); + EVP_PKEY_free(pktmp); + + if (!do_X509_sign(bio_err, ret, pkey, dgst, sigopts)) + goto err; + + /* We now just add it to the database */ + row[DB_type] = malloc(2); + + tm = X509_get_notAfter(ret); + row[DB_exp_date] = malloc(tm->length + 1); + if (row[DB_type] == NULL || row[DB_exp_date] == NULL) { + BIO_printf(bio_err, "Memory allocation failure\n"); + goto err; + } + + memcpy(row[DB_exp_date], tm->data, tm->length); + row[DB_exp_date][tm->length] = '\0'; + + row[DB_rev_date] = NULL; + + /* row[DB_serial] done already */ + row[DB_file] = malloc(8); + row[DB_name] = X509_NAME_oneline(X509_get_subject_name(ret), NULL, 0); + + if ((row[DB_type] == NULL) || (row[DB_file] == NULL) || + (row[DB_name] == NULL)) { + BIO_printf(bio_err, "Memory allocation failure\n"); + goto err; + } + (void) strlcpy(row[DB_file], "unknown", 8); + row[DB_type][0] = 'V'; + row[DB_type][1] = '\0'; + + if ((irow = reallocarray(NULL, DB_NUMBER + 1, sizeof(char *))) == + NULL) { + BIO_printf(bio_err, "Memory allocation failure\n"); + goto err; + } + for (i = 0; i < DB_NUMBER; i++) { + irow[i] = row[i]; + row[i] = NULL; + } + irow[DB_NUMBER] = NULL; + + if (!TXT_DB_insert(db->db, irow)) { + BIO_printf(bio_err, "failed to update database\n"); + BIO_printf(bio_err, "TXT_DB error number %ld\n", db->db->error); + goto err; + } + ok = 1; +err: + for (i = 0; i < DB_NUMBER; i++) + free(row[i]); + + if (CAname != NULL) + X509_NAME_free(CAname); + if (subject != NULL) + X509_NAME_free(subject); + if ((dn_subject != NULL) && !email_dn) + X509_NAME_free(dn_subject); + if (tmptm != NULL) + ASN1_UTCTIME_free(tmptm); + if (ok <= 0) { + if (ret != NULL) + X509_free(ret); + ret = NULL; + } else + *xret = ret; + return (ok); +} + +static void +write_new_certificate(BIO * bp, X509 * x, int output_der, int notext) +{ + if (output_der) { + (void) i2d_X509_bio(bp, x); + return; + } + if (!notext) + X509_print(bp, x); + PEM_write_bio_X509(bp, x); +} + +static int +certify_spkac(X509 ** xret, char *infile, EVP_PKEY * pkey, X509 * x509, + const EVP_MD * dgst, STACK_OF(OPENSSL_STRING) * sigopts, + STACK_OF(CONF_VALUE) * policy, CA_DB * db, BIGNUM * serial, char *subj, + unsigned long chtype, int multirdn, int email_dn, char *startdate, + char *enddate, long days, char *ext_sect, CONF * lconf, int verbose, + unsigned long certopt, unsigned long nameopt, int default_op, int ext_copy) +{ + STACK_OF(CONF_VALUE) * sk = NULL; + LHASH_OF(CONF_VALUE) * parms = NULL; + X509_REQ *req = NULL; + CONF_VALUE *cv = NULL; + NETSCAPE_SPKI *spki = NULL; + X509_REQ_INFO *ri; + char *type, *buf; + EVP_PKEY *pktmp = NULL; + X509_NAME *n = NULL; + int ok = -1, i, j; + long errline; + int nid; + + /* + * Load input file into a hash table. (This is just an easy + * way to read and parse the file, then put it into a convenient + * STACK format). + */ + parms = CONF_load(NULL, infile, &errline); + if (parms == NULL) { + BIO_printf(bio_err, "error on line %ld of %s\n", + errline, infile); + ERR_print_errors(bio_err); + goto err; + } + sk = CONF_get_section(parms, "default"); + if (sk_CONF_VALUE_num(sk) == 0) { + BIO_printf(bio_err, "no name/value pairs found in %s\n", + infile); + CONF_free(parms); + goto err; + } + /* + * Now create a dummy X509 request structure. We don't actually + * have an X509 request, but we have many of the components + * (a public key, various DN components). The idea is that we + * put these components into the right X509 request structure + * and we can use the same code as if you had a real X509 request. + */ + req = X509_REQ_new(); + if (req == NULL) { + ERR_print_errors(bio_err); + goto err; + } + /* + * Build up the subject name set. + */ + ri = req->req_info; + n = ri->subject; + + for (i = 0;; i++) { + if (sk_CONF_VALUE_num(sk) <= i) + break; + + cv = sk_CONF_VALUE_value(sk, i); + type = cv->name; + /* + * Skip past any leading X. X: X, etc to allow for multiple + * instances + */ + for (buf = cv->name; *buf; buf++) { + if ((*buf == ':') || (*buf == ',') || (*buf == '.')) { + buf++; + if (*buf) + type = buf; + break; + } + } + + buf = cv->value; + if ((nid = OBJ_txt2nid(type)) == NID_undef) { + if (strcmp(type, "SPKAC") == 0) { + spki = NETSCAPE_SPKI_b64_decode(cv->value, -1); + if (spki == NULL) { + BIO_printf(bio_err, "unable to load Netscape SPKAC structure\n"); + ERR_print_errors(bio_err); + goto err; + } + } + continue; + } + if (!X509_NAME_add_entry_by_NID(n, nid, chtype, + (unsigned char *)buf, -1, -1, 0)) + goto err; + } + if (spki == NULL) { + BIO_printf(bio_err, + "Netscape SPKAC structure not found in %s\n", infile); + goto err; + } + /* + * Now extract the key from the SPKI structure. + */ + + BIO_printf(bio_err, + "Check that the SPKAC request matches the signature\n"); + + if ((pktmp = NETSCAPE_SPKI_get_pubkey(spki)) == NULL) { + BIO_printf(bio_err, "error unpacking SPKAC public key\n"); + goto err; + } + j = NETSCAPE_SPKI_verify(spki, pktmp); + if (j <= 0) { + BIO_printf(bio_err, + "signature verification failed on SPKAC public key\n"); + goto err; + } + BIO_printf(bio_err, "Signature ok\n"); + + X509_REQ_set_pubkey(req, pktmp); + EVP_PKEY_free(pktmp); + ok = do_body(xret, pkey, x509, dgst, sigopts, policy, db, serial, + subj, chtype, multirdn, email_dn, startdate, enddate, days, 1, + verbose, req, ext_sect, lconf, certopt, nameopt, default_op, + ext_copy, 0); + +err: + if (req != NULL) + X509_REQ_free(req); + if (parms != NULL) + CONF_free(parms); + if (spki != NULL) + NETSCAPE_SPKI_free(spki); + + return (ok); +} + +static int +check_time_format(const char *str) +{ + return ASN1_TIME_set_string(NULL, str); +} + +static int +do_revoke(X509 * x509, CA_DB * db, int type, char *value) +{ + ASN1_UTCTIME *tm = NULL; + char *row[DB_NUMBER], **rrow, **irow; + char *rev_str = NULL; + BIGNUM *bn = NULL; + int ok = -1, i; + + for (i = 0; i < DB_NUMBER; i++) + row[i] = NULL; + row[DB_name] = X509_NAME_oneline(X509_get_subject_name(x509), NULL, 0); + bn = ASN1_INTEGER_to_BN(X509_get_serialNumber(x509), NULL); + if (!bn) + goto err; + if (BN_is_zero(bn)) + row[DB_serial] = strdup("00"); + else + row[DB_serial] = BN_bn2hex(bn); + BN_free(bn); + if ((row[DB_name] == NULL) || (row[DB_serial] == NULL)) { + BIO_printf(bio_err, "Memory allocation failure\n"); + goto err; + } + /* + * We have to lookup by serial number because name lookup skips + * revoked certs + */ + rrow = TXT_DB_get_by_index(db->db, DB_serial, row); + if (rrow == NULL) { + BIO_printf(bio_err, + "Adding Entry with serial number %s to DB for %s\n", + row[DB_serial], row[DB_name]); + + /* We now just add it to the database */ + row[DB_type] = malloc(2); + + tm = X509_get_notAfter(x509); + row[DB_exp_date] = malloc(tm->length + 1); + if (row[DB_type] == NULL || row[DB_exp_date] == NULL) { + BIO_printf(bio_err, "Memory allocation failure\n"); + goto err; + } + memcpy(row[DB_exp_date], tm->data, tm->length); + row[DB_exp_date][tm->length] = '\0'; + + row[DB_rev_date] = NULL; + + /* row[DB_serial] done already */ + row[DB_file] = malloc(8); + + /* row[DB_name] done already */ + + if ((row[DB_type] == NULL) || (row[DB_file] == NULL)) { + BIO_printf(bio_err, "Memory allocation failure\n"); + goto err; + } + (void) strlcpy(row[DB_file], "unknown", 8); + row[DB_type][0] = 'V'; + row[DB_type][1] = '\0'; + + if ((irow = reallocarray(NULL, sizeof(char *), + (DB_NUMBER + 1))) == NULL) { + BIO_printf(bio_err, "Memory allocation failure\n"); + goto err; + } + for (i = 0; i < DB_NUMBER; i++) { + irow[i] = row[i]; + row[i] = NULL; + } + irow[DB_NUMBER] = NULL; + + if (!TXT_DB_insert(db->db, irow)) { + BIO_printf(bio_err, "failed to update database\n"); + BIO_printf(bio_err, "TXT_DB error number %ld\n", + db->db->error); + goto err; + } + /* Revoke Certificate */ + ok = do_revoke(x509, db, type, value); + + goto err; + + } else if (index_name_cmp_noconst(row, rrow)) { + BIO_printf(bio_err, "ERROR:name does not match %s\n", + row[DB_name]); + goto err; + } else if (rrow[DB_type][0] == 'R') { + BIO_printf(bio_err, "ERROR:Already revoked, serial number %s\n", + row[DB_serial]); + goto err; + } else { + BIO_printf(bio_err, "Revoking Certificate %s.\n", + rrow[DB_serial]); + rev_str = make_revocation_str(type, value); + if (!rev_str) { + BIO_printf(bio_err, "Error in revocation arguments\n"); + goto err; + } + rrow[DB_type][0] = 'R'; + rrow[DB_type][1] = '\0'; + rrow[DB_rev_date] = rev_str; + } + ok = 1; + +err: + for (i = 0; i < DB_NUMBER; i++) + free(row[i]); + + return (ok); +} + +static int +get_certificate_status(const char *serial, CA_DB * db) +{ + char *row[DB_NUMBER], **rrow; + int ok = -1, i; + + /* Free Resources */ + for (i = 0; i < DB_NUMBER; i++) + row[i] = NULL; + + /* Malloc needed char spaces */ + row[DB_serial] = malloc(strlen(serial) + 2); + if (row[DB_serial] == NULL) { + BIO_printf(bio_err, "Malloc failure\n"); + goto err; + } + if (strlen(serial) % 2) { + /* Set the first char to 0 */ ; + row[DB_serial][0] = '0'; + + /* Copy String from serial to row[DB_serial] */ + memcpy(row[DB_serial] + 1, serial, strlen(serial)); + row[DB_serial][strlen(serial) + 1] = '\0'; + } else { + /* Copy String from serial to row[DB_serial] */ + memcpy(row[DB_serial], serial, strlen(serial)); + row[DB_serial][strlen(serial)] = '\0'; + } + + /* Make it Upper Case */ + for (i = 0; row[DB_serial][i] != '\0'; i++) + row[DB_serial][i] = toupper((unsigned char) row[DB_serial][i]); + + + ok = 1; + + /* Search for the certificate */ + rrow = TXT_DB_get_by_index(db->db, DB_serial, row); + if (rrow == NULL) { + BIO_printf(bio_err, "Serial %s not present in db.\n", + row[DB_serial]); + ok = -1; + goto err; + } else if (rrow[DB_type][0] == 'V') { + BIO_printf(bio_err, "%s=Valid (%c)\n", + row[DB_serial], rrow[DB_type][0]); + goto err; + } else if (rrow[DB_type][0] == 'R') { + BIO_printf(bio_err, "%s=Revoked (%c)\n", + row[DB_serial], rrow[DB_type][0]); + goto err; + } else if (rrow[DB_type][0] == 'E') { + BIO_printf(bio_err, "%s=Expired (%c)\n", + row[DB_serial], rrow[DB_type][0]); + goto err; + } else if (rrow[DB_type][0] == 'S') { + BIO_printf(bio_err, "%s=Suspended (%c)\n", + row[DB_serial], rrow[DB_type][0]); + goto err; + } else { + BIO_printf(bio_err, "%s=Unknown (%c).\n", + row[DB_serial], rrow[DB_type][0]); + ok = -1; + } + +err: + for (i = 0; i < DB_NUMBER; i++) + free(row[i]); + + return (ok); +} + +static int +do_updatedb(CA_DB * db) +{ + ASN1_UTCTIME *a_tm = NULL; + int i, cnt = 0; + int db_y2k, a_y2k; /* flags = 1 if y >= 2000 */ + char **rrow, *a_tm_s; + + a_tm = ASN1_UTCTIME_new(); + + /* get actual time and make a string */ + a_tm = X509_gmtime_adj(a_tm, 0); + a_tm_s = malloc(a_tm->length + 1); + if (a_tm_s == NULL) { + cnt = -1; + goto err; + } + memcpy(a_tm_s, a_tm->data, a_tm->length); + a_tm_s[a_tm->length] = '\0'; + + if (strncmp(a_tm_s, "49", 2) <= 0) + a_y2k = 1; + else + a_y2k = 0; + + for (i = 0; i < sk_OPENSSL_PSTRING_num(db->db->data); i++) { + rrow = sk_OPENSSL_PSTRING_value(db->db->data, i); + + if (rrow[DB_type][0] == 'V') { + /* ignore entries that are not valid */ + if (strncmp(rrow[DB_exp_date], "49", 2) <= 0) + db_y2k = 1; + else + db_y2k = 0; + + if (db_y2k == a_y2k) { + /* all on the same y2k side */ + if (strcmp(rrow[DB_exp_date], a_tm_s) <= 0) { + rrow[DB_type][0] = 'E'; + rrow[DB_type][1] = '\0'; + cnt++; + + BIO_printf(bio_err, "%s=Expired\n", + rrow[DB_serial]); + } + } else if (db_y2k < a_y2k) { + rrow[DB_type][0] = 'E'; + rrow[DB_type][1] = '\0'; + cnt++; + + BIO_printf(bio_err, "%s=Expired\n", + rrow[DB_serial]); + } + } + } + +err: + ASN1_UTCTIME_free(a_tm); + free(a_tm_s); + + return (cnt); +} + +static const char *crl_reasons[] = { + /* CRL reason strings */ + "unspecified", + "keyCompromise", + "CACompromise", + "affiliationChanged", + "superseded", + "cessationOfOperation", + "certificateHold", + "removeFromCRL", + /* Additional pseudo reasons */ + "holdInstruction", + "keyTime", + "CAkeyTime" +}; + +#define NUM_REASONS (sizeof(crl_reasons) / sizeof(char *)) + +/* Given revocation information convert to a DB string. + * The format of the string is: + * revtime[,reason,extra]. Where 'revtime' is the + * revocation time (the current time). 'reason' is the + * optional CRL reason and 'extra' is any additional + * argument + */ + +char * +make_revocation_str(int rev_type, char *rev_arg) +{ + char *other = NULL, *str; + const char *reason = NULL; + ASN1_OBJECT *otmp; + ASN1_UTCTIME *revtm = NULL; + int i; + switch (rev_type) { + case REV_NONE: + break; + + case REV_CRL_REASON: + for (i = 0; i < 8; i++) { + if (!strcasecmp(rev_arg, crl_reasons[i])) { + reason = crl_reasons[i]; + break; + } + } + if (reason == NULL) { + BIO_printf(bio_err, "Unknown CRL reason %s\n", rev_arg); + return NULL; + } + break; + + case REV_HOLD: + /* Argument is an OID */ + + otmp = OBJ_txt2obj(rev_arg, 0); + ASN1_OBJECT_free(otmp); + + if (otmp == NULL) { + BIO_printf(bio_err, + "Invalid object identifier %s\n", rev_arg); + return NULL; + } + reason = "holdInstruction"; + other = rev_arg; + break; + + case REV_KEY_COMPROMISE: + case REV_CA_COMPROMISE: + + /* Argument is the key compromise time */ + if (!ASN1_GENERALIZEDTIME_set_string(NULL, rev_arg)) { + BIO_printf(bio_err, + "Invalid time format %s. Need YYYYMMDDHHMMSSZ\n", + rev_arg); + return NULL; + } + other = rev_arg; + if (rev_type == REV_KEY_COMPROMISE) + reason = "keyTime"; + else + reason = "CAkeyTime"; + + break; + + } + + revtm = X509_gmtime_adj(NULL, 0); + if (asprintf(&str, "%s%s%s%s%s", revtm->data, + reason ? "," : "", reason ? reason : "", + other ? "," : "", other ? other : "") == -1) + str = NULL; + ASN1_UTCTIME_free(revtm); + return str; +} + +/* Convert revocation field to X509_REVOKED entry + * return code: + * 0 error + * 1 OK + * 2 OK and some extensions added (i.e. V2 CRL) + */ + +int +make_revoked(X509_REVOKED * rev, const char *str) +{ + char *tmp = NULL; + int reason_code = -1; + int i, ret = 0; + ASN1_OBJECT *hold = NULL; + ASN1_GENERALIZEDTIME *comp_time = NULL; + ASN1_ENUMERATED *rtmp = NULL; + + ASN1_TIME *revDate = NULL; + + i = unpack_revinfo(&revDate, &reason_code, &hold, &comp_time, str); + + if (i == 0) + goto err; + + if (rev && !X509_REVOKED_set_revocationDate(rev, revDate)) + goto err; + + if (rev && (reason_code != OCSP_REVOKED_STATUS_NOSTATUS)) { + rtmp = ASN1_ENUMERATED_new(); + if (!rtmp || !ASN1_ENUMERATED_set(rtmp, reason_code)) + goto err; + if (!X509_REVOKED_add1_ext_i2d(rev, NID_crl_reason, rtmp, 0, 0)) + goto err; + } + if (rev && comp_time) { + if (!X509_REVOKED_add1_ext_i2d(rev, NID_invalidity_date, + comp_time, 0, 0)) + goto err; + } + if (rev && hold) { + if (!X509_REVOKED_add1_ext_i2d(rev, NID_hold_instruction_code, + hold, 0, 0)) + goto err; + } + if (reason_code != OCSP_REVOKED_STATUS_NOSTATUS) + ret = 2; + else + ret = 1; + +err: + free(tmp); + + ASN1_OBJECT_free(hold); + ASN1_GENERALIZEDTIME_free(comp_time); + ASN1_ENUMERATED_free(rtmp); + ASN1_TIME_free(revDate); + + return ret; +} + +int +old_entry_print(BIO * bp, ASN1_OBJECT * obj, ASN1_STRING * str) +{ + char buf[25], *pbuf, *p; + int j; + + j = i2a_ASN1_OBJECT(bp, obj); + pbuf = buf; + for (j = 22 - j; j > 0; j--) + *(pbuf++) = ' '; + *(pbuf++) = ':'; + *(pbuf++) = '\0'; + BIO_puts(bp, buf); + + if (str->type == V_ASN1_PRINTABLESTRING) + BIO_printf(bp, "PRINTABLE:'"); + else if (str->type == V_ASN1_T61STRING) + BIO_printf(bp, "T61STRING:'"); + else if (str->type == V_ASN1_IA5STRING) + BIO_printf(bp, "IA5STRING:'"); + else if (str->type == V_ASN1_UNIVERSALSTRING) + BIO_printf(bp, "UNIVERSALSTRING:'"); + else + BIO_printf(bp, "ASN.1 %2d:'", str->type); + + p = (char *) str->data; + for (j = str->length; j > 0; j--) { + if ((*p >= ' ') && (*p <= '~')) + BIO_printf(bp, "%c", *p); + else if (*p & 0x80) + BIO_printf(bp, "\\0x%02X", *p); + else if ((unsigned char) *p == 0xf7) + BIO_printf(bp, "^?"); + else + BIO_printf(bp, "^%c", *p + '@'); + p++; + } + BIO_printf(bp, "'\n"); + return 1; +} + +int +unpack_revinfo(ASN1_TIME ** prevtm, int *preason, ASN1_OBJECT ** phold, + ASN1_GENERALIZEDTIME ** pinvtm, const char *str) +{ + char *tmp = NULL; + char *rtime_str, *reason_str = NULL, *arg_str = NULL, *p; + int reason_code = -1; + int ret = 0; + unsigned int i; + ASN1_OBJECT *hold = NULL; + ASN1_GENERALIZEDTIME *comp_time = NULL; + + if ((tmp = strdup(str)) == NULL) { + BIO_printf(bio_err, "malloc failed\n"); + goto err; + } + p = strchr(tmp, ','); + rtime_str = tmp; + + if (p) { + *p = '\0'; + p++; + reason_str = p; + p = strchr(p, ','); + if (p) { + *p = '\0'; + arg_str = p + 1; + } + } + if (prevtm) { + *prevtm = ASN1_UTCTIME_new(); + if (!ASN1_UTCTIME_set_string(*prevtm, rtime_str)) { + BIO_printf(bio_err, "invalid revocation date %s\n", + rtime_str); + goto err; + } + } + if (reason_str) { + for (i = 0; i < NUM_REASONS; i++) { + if (!strcasecmp(reason_str, crl_reasons[i])) { + reason_code = i; + break; + } + } + if (reason_code == OCSP_REVOKED_STATUS_NOSTATUS) { + BIO_printf(bio_err, "invalid reason code %s\n", + reason_str); + goto err; + } + if (reason_code == 7) + reason_code = OCSP_REVOKED_STATUS_REMOVEFROMCRL; + else if (reason_code == 8) { /* Hold instruction */ + if (!arg_str) { + BIO_printf(bio_err, + "missing hold instruction\n"); + goto err; + } + reason_code = OCSP_REVOKED_STATUS_CERTIFICATEHOLD; + hold = OBJ_txt2obj(arg_str, 0); + + if (!hold) { + BIO_printf(bio_err, + "invalid object identifier %s\n", arg_str); + goto err; + } + if (phold) + *phold = hold; + } else if ((reason_code == 9) || (reason_code == 10)) { + if (!arg_str) { + BIO_printf(bio_err, + "missing compromised time\n"); + goto err; + } + comp_time = ASN1_GENERALIZEDTIME_new(); + if (!ASN1_GENERALIZEDTIME_set_string(comp_time, + arg_str)) { + BIO_printf(bio_err, + "invalid compromised time %s\n", arg_str); + goto err; + } + if (reason_code == 9) + reason_code = OCSP_REVOKED_STATUS_KEYCOMPROMISE; + else + reason_code = OCSP_REVOKED_STATUS_CACOMPROMISE; + } + } + if (preason) + *preason = reason_code; + if (pinvtm) + *pinvtm = comp_time; + else + ASN1_GENERALIZEDTIME_free(comp_time); + + ret = 1; + +err: + free(tmp); + + if (!phold) + ASN1_OBJECT_free(hold); + if (!pinvtm) + ASN1_GENERALIZEDTIME_free(comp_time); + + return ret; +} + +static char * +bin2hex(unsigned char * data, size_t len) +{ + char *ret = NULL; + char hex[] = "0123456789ABCDEF"; + int i; + + if ((ret = malloc(len * 2 + 1))) { + for (i = 0; i < len; i++) { + ret[i * 2 + 0] = hex[data[i] >> 4]; + ret[i * 2 + 1] = hex[data[i] & 0x0F]; + } + ret[len * 2] = '\0'; + } + return ret; +} diff --git a/bin/openssl/certhash.c b/bin/openssl/certhash.c new file mode 100644 index 0000000000..fdd719ea48 --- /dev/null +++ b/bin/openssl/certhash.c @@ -0,0 +1,688 @@ +/* + * Copyright (c) 2014, 2015 Joel Sing + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "apps.h" + +static struct { + int dryrun; + int verbose; +} certhash_config; + +struct option certhash_options[] = { + { + .name = "n", + .desc = "Perform a dry-run - do not make any changes", + .type = OPTION_FLAG, + .opt.flag = &certhash_config.dryrun, + }, + { + .name = "v", + .desc = "Verbose", + .type = OPTION_FLAG, + .opt.flag = &certhash_config.verbose, + }, + { NULL }, +}; + +struct hashinfo { + char *filename; + char *target; + unsigned long hash; + unsigned int index; + unsigned char fingerprint[EVP_MAX_MD_SIZE]; + int is_crl; + int is_dup; + int exists; + int changed; + struct hashinfo *reference; + struct hashinfo *next; +}; + +static struct hashinfo * +hashinfo(const char *filename, unsigned long hash, unsigned char *fingerprint) +{ + struct hashinfo *hi; + + if ((hi = calloc(1, sizeof(*hi))) == NULL) + return (NULL); + if (filename != NULL) { + if ((hi->filename = strdup(filename)) == NULL) { + free(hi); + return (NULL); + } + } + hi->hash = hash; + if (fingerprint != NULL) + memcpy(hi->fingerprint, fingerprint, sizeof(hi->fingerprint)); + + return (hi); +} + +static void +hashinfo_free(struct hashinfo *hi) +{ + if (hi == NULL) + return; + + free(hi->filename); + free(hi->target); + free(hi); +} + +#ifdef DEBUG +static void +hashinfo_print(struct hashinfo *hi) +{ + int i; + + printf("hashinfo %s %08lx %u %i\n", hi->filename, hi->hash, + hi->index, hi->is_crl); + for (i = 0; i < (int)EVP_MAX_MD_SIZE; i++) { + printf("%02X%c", hi->fingerprint[i], + (i + 1 == (int)EVP_MAX_MD_SIZE) ? '\n' : ':'); + } +} +#endif + +static int +hashinfo_compare(const void *a, const void *b) +{ + struct hashinfo *hia = *(struct hashinfo **)a; + struct hashinfo *hib = *(struct hashinfo **)b; + int rv; + + rv = hia->hash < hib->hash ? -1 : hia->hash > hib->hash; + if (rv != 0) + return (rv); + rv = memcmp(hia->fingerprint, hib->fingerprint, + sizeof(hia->fingerprint)); + if (rv != 0) + return (rv); + return strcmp(hia->filename, hib->filename); +} + +static struct hashinfo * +hashinfo_chain(struct hashinfo *head, struct hashinfo *entry) +{ + struct hashinfo *hi = head; + + if (hi == NULL) + return (entry); + while (hi->next != NULL) + hi = hi->next; + hi->next = entry; + + return (head); +} + +static void +hashinfo_chain_free(struct hashinfo *hi) +{ + struct hashinfo *next; + + while (hi != NULL) { + next = hi->next; + hashinfo_free(hi); + hi = next; + } +} + +static size_t +hashinfo_chain_length(struct hashinfo *hi) +{ + int len = 0; + + while (hi != NULL) { + len++; + hi = hi->next; + } + return (len); +} + +static int +hashinfo_chain_sort(struct hashinfo **head) +{ + struct hashinfo **list, *entry; + size_t len; + int i; + + if (*head == NULL) + return (0); + + len = hashinfo_chain_length(*head); + if ((list = reallocarray(NULL, len, sizeof(struct hashinfo *))) == NULL) + return (-1); + + for (entry = *head, i = 0; entry != NULL; entry = entry->next, i++) + list[i] = entry; + qsort(list, len, sizeof(struct hashinfo *), hashinfo_compare); + + *head = entry = list[0]; + for (i = 1; i < len; i++) { + entry->next = list[i]; + entry = list[i]; + } + entry->next = NULL; + + free(list); + return (0); +} + +static char * +hashinfo_linkname(struct hashinfo *hi) +{ + char *filename; + + if (asprintf(&filename, "%08lx.%s%u", hi->hash, + (hi->is_crl ? "r" : ""), hi->index) == -1) + return (NULL); + + return (filename); +} + +static int +filename_is_hash(const char *filename) +{ + const char *p = filename; + + while ((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f')) + p++; + if (*p++ != '.') + return (0); + if (*p == 'r') /* CRL format. */ + p++; + while (*p >= '0' && *p <= '9') + p++; + if (*p != '\0') + return (0); + + return (1); +} + +static int +filename_is_pem(const char *filename) +{ + const char *q, *p = filename; + + if ((q = strchr(p, '\0')) == NULL) + return (0); + if ((q - p) < 4) + return (0); + if (strncmp((q - 4), ".pem", 4) != 0) + return (0); + + return (1); +} + +static struct hashinfo * +hashinfo_from_linkname(const char *linkname, const char *target) +{ + struct hashinfo *hi = NULL; + const char *errstr; + char *l, *p, *ep; + long long val; + + if ((l = strdup(linkname)) == NULL) + goto err; + if ((p = strchr(l, '.')) == NULL) + goto err; + *p++ = '\0'; + + if ((hi = hashinfo(linkname, 0, NULL)) == NULL) + goto err; + if ((hi->target = strdup(target)) == NULL) + goto err; + + errno = 0; + val = strtoll(l, &ep, 16); + if (l[0] == '\0' || *ep != '\0') + goto err; + if (errno == ERANGE && (val == LLONG_MAX || val == LLONG_MIN)) + goto err; + if (val < 0 || val > ULONG_MAX) + goto err; + hi->hash = (unsigned long)val; + + if (*p == 'r') { + hi->is_crl = 1; + p++; + } + + val = strtonum(p, 0, 0xffffffff, &errstr); + if (errstr != NULL) + goto err; + + hi->index = (unsigned int)val; + + goto done; + +err: + hashinfo_free(hi); + hi = NULL; + +done: + free(l); + + return (hi); +} + +static struct hashinfo * +certhash_cert(BIO *bio, const char *filename) +{ + unsigned char fingerprint[EVP_MAX_MD_SIZE]; + struct hashinfo *hi = NULL; + const EVP_MD *digest; + X509 *cert = NULL; + unsigned long hash; + unsigned int len; + + if ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) == NULL) + goto err; + + hash = X509_subject_name_hash(cert); + + digest = EVP_sha256(); + if (X509_digest(cert, digest, fingerprint, &len) != 1) { + fprintf(stderr, "out of memory\n"); + goto err; + } + + hi = hashinfo(filename, hash, fingerprint); + +err: + X509_free(cert); + + return (hi); +} + +static struct hashinfo * +certhash_crl(BIO *bio, const char *filename) +{ + unsigned char fingerprint[EVP_MAX_MD_SIZE]; + struct hashinfo *hi = NULL; + const EVP_MD *digest; + X509_CRL *crl = NULL; + unsigned long hash; + unsigned int len; + + if ((crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL)) == NULL) + return (NULL); + + hash = X509_NAME_hash(X509_CRL_get_issuer(crl)); + + digest = EVP_sha256(); + if (X509_CRL_digest(crl, digest, fingerprint, &len) != 1) { + fprintf(stderr, "out of memory\n"); + goto err; + } + + hi = hashinfo(filename, hash, fingerprint); + +err: + X509_CRL_free(crl); + + return (hi); +} + +static int +certhash_addlink(struct hashinfo **links, struct hashinfo *hi) +{ + struct hashinfo *link = NULL; + + if ((link = hashinfo(NULL, hi->hash, hi->fingerprint)) == NULL) + goto err; + + if ((link->filename = hashinfo_linkname(hi)) == NULL) + goto err; + + link->reference = hi; + link->changed = 1; + *links = hashinfo_chain(*links, link); + hi->reference = link; + + return (0); + +err: + hashinfo_free(link); + return (-1); +} + +static void +certhash_findlink(struct hashinfo *links, struct hashinfo *hi) +{ + struct hashinfo *link; + + for (link = links; link != NULL; link = link->next) { + if (link->is_crl == hi->is_crl && + link->hash == hi->hash && + link->index == hi->index && + link->reference == NULL) { + link->reference = hi; + if (link->target == NULL || + strcmp(link->target, hi->filename) != 0) + link->changed = 1; + hi->reference = link; + break; + } + } +} + +static void +certhash_index(struct hashinfo *head, const char *name) +{ + struct hashinfo *last, *entry; + int index = 0; + + last = NULL; + for (entry = head; entry != NULL; entry = entry->next) { + if (last != NULL) { + if (entry->hash == last->hash) { + if (memcmp(entry->fingerprint, + last->fingerprint, + sizeof(entry->fingerprint)) == 0) { + fprintf(stderr, "WARNING: duplicate %s " + "in %s (using %s), ignoring...\n", + name, entry->filename, + last->filename); + entry->is_dup = 1; + continue; + } + index++; + } else { + index = 0; + } + } + entry->index = index; + last = entry; + } +} + +static int +certhash_merge(struct hashinfo **links, struct hashinfo **certs, + struct hashinfo **crls) +{ + struct hashinfo *cert, *crl; + + /* Pass 1 - sort and index entries. */ + if (hashinfo_chain_sort(certs) == -1) + return (-1); + if (hashinfo_chain_sort(crls) == -1) + return (-1); + certhash_index(*certs, "certificate"); + certhash_index(*crls, "CRL"); + + /* Pass 2 - map to existing links. */ + for (cert = *certs; cert != NULL; cert = cert->next) { + if (cert->is_dup == 1) + continue; + certhash_findlink(*links, cert); + } + for (crl = *crls; crl != NULL; crl = crl->next) { + if (crl->is_dup == 1) + continue; + certhash_findlink(*links, crl); + } + + /* Pass 3 - determine missing links. */ + for (cert = *certs; cert != NULL; cert = cert->next) { + if (cert->is_dup == 1 || cert->reference != NULL) + continue; + if (certhash_addlink(links, cert) == -1) + return (-1); + } + for (crl = *crls; crl != NULL; crl = crl->next) { + if (crl->is_dup == 1 || crl->reference != NULL) + continue; + if (certhash_addlink(links, crl) == -1) + return (-1); + } + + return (0); +} + +static int +certhash_link(struct dirent *dep, struct hashinfo **links) +{ + struct hashinfo *hi = NULL; + char target[PATH_MAX]; + struct stat sb; + int n; + + if (lstat(dep->d_name, &sb) == -1) { + fprintf(stderr, "failed to stat %s\n", dep->d_name); + return (-1); + } + if (!S_ISLNK(sb.st_mode)) + return (0); + + n = readlink(dep->d_name, target, sizeof(target) - 1); + if (n == -1) { + fprintf(stderr, "failed to readlink %s\n", dep->d_name); + return (-1); + } + target[n] = '\0'; + + hi = hashinfo_from_linkname(dep->d_name, target); + if (hi == NULL) { + fprintf(stderr, "failed to get hash info %s\n", dep->d_name); + return (-1); + } + hi->exists = 1; + *links = hashinfo_chain(*links, hi); + + return (0); +} + +static int +certhash_file(struct dirent *dep, struct hashinfo **certs, + struct hashinfo **crls) +{ + struct hashinfo *hi = NULL; + int has_cert, has_crl; + int ret = -1; + BIO *bio = NULL; + FILE *f; + + has_cert = has_crl = 0; + + if ((f = fopen(dep->d_name, "r")) == NULL) { + fprintf(stderr, "failed to fopen %s\n", dep->d_name); + goto err; + } + if ((bio = BIO_new_fp(f, BIO_CLOSE)) == NULL) { + fprintf(stderr, "failed to create bio\n"); + fclose(f); + goto err; + } + + if ((hi = certhash_cert(bio, dep->d_name)) != NULL) { + has_cert = 1; + *certs = hashinfo_chain(*certs, hi); + } + + if (BIO_reset(bio) != 0) { + fprintf(stderr, "BIO_reset failed\n"); + goto err; + } + + if ((hi = certhash_crl(bio, dep->d_name)) != NULL) { + has_crl = hi->is_crl = 1; + *crls = hashinfo_chain(*crls, hi); + } + + if (!has_cert && !has_crl) + fprintf(stderr, "PEM file %s does not contain a certificate " + "or CRL, ignoring...\n", dep->d_name); + + ret = 0; + +err: + BIO_free(bio); + + return (ret); +} + +static int +certhash_directory(const char *path) +{ + struct hashinfo *links = NULL, *certs = NULL, *crls = NULL, *link; + int ret = 0; + struct dirent *dep; + DIR *dip = NULL; + + if ((dip = opendir(".")) == NULL) { + fprintf(stderr, "failed to open directory %s\n", path); + goto err; + } + + if (certhash_config.verbose) + fprintf(stdout, "scanning directory %s\n", path); + + /* Create lists of existing hash links, certs and CRLs. */ + while ((dep = readdir(dip)) != NULL) { + if (filename_is_hash(dep->d_name)) { + if (certhash_link(dep, &links) == -1) + goto err; + } + if (filename_is_pem(dep->d_name)) { + if (certhash_file(dep, &certs, &crls) == -1) + goto err; + } + } + + if (certhash_merge(&links, &certs, &crls) == -1) { + fprintf(stderr, "certhash merge failed\n"); + goto err; + } + + /* Remove spurious links. */ + for (link = links; link != NULL; link = link->next) { + if (link->exists == 0 || + (link->reference != NULL && link->changed == 0)) + continue; + if (certhash_config.verbose) + fprintf(stdout, "%s link %s -> %s\n", + (certhash_config.dryrun ? "would remove" : + "removing"), link->filename, link->target); + if (certhash_config.dryrun) + continue; + if (unlink(link->filename) == -1) { + fprintf(stderr, "failed to remove link %s\n", + link->filename); + goto err; + } + } + + /* Create missing links. */ + for (link = links; link != NULL; link = link->next) { + if (link->exists == 1 && link->changed == 0) + continue; + if (certhash_config.verbose) + fprintf(stdout, "%s link %s -> %s\n", + (certhash_config.dryrun ? "would create" : + "creating"), link->filename, + link->reference->filename); + if (certhash_config.dryrun) + continue; + if (symlink(link->reference->filename, link->filename) == -1) { + fprintf(stderr, "failed to create link %s -> %s\n", + link->filename, link->reference->filename); + goto err; + } + } + + goto done; + +err: + ret = 1; + +done: + hashinfo_chain_free(certs); + hashinfo_chain_free(crls); + hashinfo_chain_free(links); + + if (dip != NULL) + closedir(dip); + return (ret); +} + +static void +certhash_usage(void) +{ + fprintf(stderr, "usage: certhash [-nv] dir ...\n"); + options_usage(certhash_options); +} + +int +certhash_main(int argc, char **argv) +{ + int argsused; + int i, cwdfd, ret = 0; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + memset(&certhash_config, 0, sizeof(certhash_config)); + + if (options_parse(argc, argv, certhash_options, NULL, &argsused) != 0) { + certhash_usage(); + return (1); + } + + if ((cwdfd = open(".", O_RDONLY)) == -1) { + perror("failed to open current directory"); + return (1); + } + + for (i = argsused; i < argc; i++) { + if (chdir(argv[i]) == -1) { + fprintf(stderr, + "failed to change to directory %s: %s\n", + argv[i], strerror(errno)); + ret = 1; + continue; + } + ret |= certhash_directory(argv[i]); + if (fchdir(cwdfd) == -1) { + perror("failed to restore current directory"); + ret = 1; + break; /* can't continue safely */ + } + } + close(cwdfd); + + return (ret); +} diff --git a/bin/openssl/ciphers.c b/bin/openssl/ciphers.c new file mode 100644 index 0000000000..72e12a3aae --- /dev/null +++ b/bin/openssl/ciphers.c @@ -0,0 +1,152 @@ +/* $OpenBSD: ciphers.c,v 1.8 2015/10/17 15:00:11 doug Exp $ */ +/* + * Copyright (c) 2014 Joel Sing + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include +#include + +#include "apps.h" +#include "progs.h" + +struct { + int usage; + int verbose; +} ciphers_config; + +struct option ciphers_options[] = { + { + .name = "h", + .type = OPTION_FLAG, + .opt.flag = &ciphers_config.usage, + }, + { + .name = "?", + .type = OPTION_FLAG, + .opt.flag = &ciphers_config.usage, + }, + { + .name = "tls1", + .desc = "This option is deprecated since it is the default", + .type = OPTION_DISCARD, + }, + { + .name = "v", + .desc = "Provide cipher listing", + .type = OPTION_VALUE, + .opt.value = &ciphers_config.verbose, + .value = 1, + }, + { + .name = "V", + .desc = "Provide cipher listing with cipher suite values", + .type = OPTION_VALUE, + .opt.value = &ciphers_config.verbose, + .value = 2, + }, + { NULL }, +}; + +static void +ciphers_usage(void) +{ + fprintf(stderr, "usage: ciphers [-hVv] [-tls1] [cipherlist]\n"); + options_usage(ciphers_options); +} + +int +ciphers_main(int argc, char **argv) +{ + char *cipherlist = NULL; + STACK_OF(SSL_CIPHER) *ciphers; + const SSL_CIPHER *cipher; + SSL_CTX *ssl_ctx = NULL; + SSL *ssl = NULL; + uint16_t value; + int i, rv = 0; + char *desc; + + if (single_execution) { + if (pledge("stdio rpath", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + memset(&ciphers_config, 0, sizeof(ciphers_config)); + + if (options_parse(argc, argv, ciphers_options, &cipherlist, + NULL) != 0) { + ciphers_usage(); + return (1); + } + + if (ciphers_config.usage) { + ciphers_usage(); + return (1); + } + + if ((ssl_ctx = SSL_CTX_new(TLSv1_client_method())) == NULL) + goto err; + + if (cipherlist != NULL) { + if (SSL_CTX_set_cipher_list(ssl_ctx, cipherlist) == 0) + goto err; + } + + if ((ssl = SSL_new(ssl_ctx)) == NULL) + goto err; + + if ((ciphers = SSL_get_ciphers(ssl)) == NULL) + goto err; + + for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) { + cipher = sk_SSL_CIPHER_value(ciphers, i); + if (ciphers_config.verbose == 0) { + fprintf(stdout, "%s%s", (i ? ":" : ""), + SSL_CIPHER_get_name(cipher)); + continue; + } + if (ciphers_config.verbose > 1) { + value = SSL_CIPHER_get_value(cipher); + fprintf(stdout, "%-*s0x%02X,0x%02X - ", 10, "", + ((value >> 8) & 0xff), (value & 0xff)); + } + desc = SSL_CIPHER_description(cipher, NULL, 0); + if (strcmp(desc, "OPENSSL_malloc Error") == 0) { + fprintf(stderr, "out of memory\n"); + goto err; + } + fprintf(stdout, "%s", desc); + free(desc); + } + if (ciphers_config.verbose == 0) + fprintf(stdout, "\n"); + + goto done; + +err: + ERR_print_errors_fp(stderr); + rv = 1; + +done: + SSL_CTX_free(ssl_ctx); + SSL_free(ssl); + + return (rv); +} diff --git a/bin/openssl/compat.mk b/bin/openssl/compat.mk new file mode 100644 index 0000000000..b478e2df6d --- /dev/null +++ b/bin/openssl/compat.mk @@ -0,0 +1,5 @@ +.include +LCRYPTO_SRC= ${SRCTOP}/lib/libcrypto +CPPFLAGS+= -I${LCRYPTO_SRC}/compat/include +SRCS+= strtonum.c +.PATH: ${LCRYPTO_SRC}/compat diff --git a/bin/openssl/crl.c b/bin/openssl/crl.c new file mode 100644 index 0000000000..bb7ff62775 --- /dev/null +++ b/bin/openssl/crl.c @@ -0,0 +1,477 @@ +/* $OpenBSD: crl.c,v 1.10 2017/01/20 08:57:11 deraadt Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include +#include +#include + +#include "apps.h" + +#include +#include +#include +#include +#include + +static struct { + char *cafile; + char *capath; + int crlnumber; + int fingerprint; + int hash; + int hash_old; + char *infile; + int informat; + int issuer; + int lastupdate; + char *nameopt; + int nextupdate; + int noout; + char *outfile; + int outformat; + int text; + int verify; +} crl_config; + +static struct option crl_options[] = { + { + .name = "CAfile", + .argname = "file", + .desc = "Verify the CRL using certificates in the given file", + .type = OPTION_ARG, + .opt.arg = &crl_config.cafile, + }, + { + .name = "CApath", + .argname = "path", + .desc = "Verify the CRL using certificates in the given path", + .type = OPTION_ARG, + .opt.arg = &crl_config.capath, + }, + { + .name = "crlnumber", + .desc = "Print the CRL number", + .type = OPTION_FLAG_ORD, + .opt.flag = &crl_config.crlnumber, + }, + { + .name = "fingerprint", + .desc = "Print the CRL fingerprint", + .type = OPTION_FLAG_ORD, + .opt.flag = &crl_config.fingerprint, + }, + { + .name = "hash", + .desc = "Print the hash of the issuer name", + .type = OPTION_FLAG_ORD, + .opt.flag = &crl_config.hash, + }, + { + .name = "hash_old", + .desc = "Print an old-style (MD5) hash of the issuer name", + .type = OPTION_FLAG_ORD, + .opt.flag = &crl_config.hash_old, + }, + { + .name = "in", + .argname = "file", + .desc = "Input file to read from (stdin if unspecified)", + .type = OPTION_ARG, + .opt.arg = &crl_config.infile, + }, + { + .name = "inform", + .argname = "format", + .desc = "Input format (DER or PEM)", + .type = OPTION_ARG_FORMAT, + .opt.value = &crl_config.informat, + }, + { + .name = "issuer", + .desc = "Print the issuer name", + .type = OPTION_FLAG_ORD, + .opt.flag = &crl_config.issuer, + }, + { + .name = "lastupdate", + .desc = "Print the lastUpdate field", + .type = OPTION_FLAG_ORD, + .opt.flag = &crl_config.lastupdate, + }, + { + .name = "nameopt", + .argname = "options", + .desc = "Specify certificate name options", + .type = OPTION_ARG, + .opt.arg = &crl_config.nameopt, + }, + { + .name = "nextupdate", + .desc = "Print the nextUpdate field", + .type = OPTION_FLAG_ORD, + .opt.flag = &crl_config.nextupdate, + }, + { + .name = "noout", + .desc = "Do not output the encoded version of the CRL", + .type = OPTION_FLAG, + .opt.flag = &crl_config.noout, + }, + { + .name = "out", + .argname = "file", + .desc = "Output file to write to (stdout if unspecified)", + .type = OPTION_ARG, + .opt.arg = &crl_config.outfile, + }, + { + .name = "outform", + .argname = "format", + .desc = "Output format (DER or PEM)", + .type = OPTION_ARG_FORMAT, + .opt.value = &crl_config.outformat, + }, + { + .name = "text", + .desc = "Print out the CRL in text form", + .type = OPTION_FLAG, + .opt.flag = &crl_config.text, + }, + { + .name = "verify", + .desc = "Verify the signature on the CRL", + .type = OPTION_FLAG, + .opt.flag = &crl_config.verify, + }, + {NULL}, +}; + +static void +crl_usage(void) +{ + fprintf(stderr, + "usage: crl [-CAfile file] [-CApath dir] [-fingerprint] [-hash]\n" + " [-in file] [-inform DER | PEM] [-issuer] [-lastupdate]\n" + " [-nextupdate] [-noout] [-out file] [-outform DER | PEM]\n" + " [-text]\n\n"); + options_usage(crl_options); +} + +static X509_CRL *load_crl(char *file, int format); +static BIO *bio_out = NULL; + +int +crl_main(int argc, char **argv) +{ + unsigned long nmflag = 0; + X509_CRL *x = NULL; + int ret = 1, i; + BIO *out = NULL; + X509_STORE *store = NULL; + X509_STORE_CTX ctx; + X509_LOOKUP *lookup = NULL; + X509_OBJECT xobj; + EVP_PKEY *pkey; + const EVP_MD *digest; + char *digest_name = NULL; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + if (bio_out == NULL) { + if ((bio_out = BIO_new(BIO_s_file())) != NULL) { + BIO_set_fp(bio_out, stdout, BIO_NOCLOSE); + } + } + + digest = EVP_sha1(); + + memset(&crl_config, 0, sizeof(crl_config)); + crl_config.informat = FORMAT_PEM; + crl_config.outformat = FORMAT_PEM; + + if (options_parse(argc, argv, crl_options, &digest_name, NULL) != 0) { + crl_usage(); + goto end; + } + + if (crl_config.cafile != NULL || crl_config.capath != NULL) + crl_config.verify = 1; + + if (crl_config.nameopt != NULL) { + if (set_name_ex(&nmflag, crl_config.nameopt) != 1) { + fprintf(stderr, + "Invalid -nameopt argument '%s'\n", + crl_config.nameopt); + goto end; + } + } + + if (digest_name != NULL) { + if ((digest = EVP_get_digestbyname(digest_name)) == NULL) { + fprintf(stderr, + "Unknown message digest algorithm '%s'\n", + digest_name); + goto end; + } + } + + x = load_crl(crl_config.infile, crl_config.informat); + if (x == NULL) + goto end; + + if (crl_config.verify) { + store = X509_STORE_new(); + lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); + if (lookup == NULL) + goto end; + if (!X509_LOOKUP_load_file(lookup, crl_config.cafile, + X509_FILETYPE_PEM)) + X509_LOOKUP_load_file(lookup, NULL, + X509_FILETYPE_DEFAULT); + + lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir()); + if (lookup == NULL) + goto end; + if (!X509_LOOKUP_add_dir(lookup, crl_config.capath, + X509_FILETYPE_PEM)) + X509_LOOKUP_add_dir(lookup, NULL, + X509_FILETYPE_DEFAULT); + ERR_clear_error(); + + if (!X509_STORE_CTX_init(&ctx, store, NULL, NULL)) { + BIO_printf(bio_err, + "Error initialising X509 store\n"); + goto end; + } + i = X509_STORE_get_by_subject(&ctx, X509_LU_X509, + X509_CRL_get_issuer(x), &xobj); + if (i <= 0) { + BIO_printf(bio_err, + "Error getting CRL issuer certificate\n"); + goto end; + } + pkey = X509_get_pubkey(xobj.data.x509); + X509_OBJECT_free_contents(&xobj); + if (!pkey) { + BIO_printf(bio_err, + "Error getting CRL issuer public key\n"); + goto end; + } + i = X509_CRL_verify(x, pkey); + EVP_PKEY_free(pkey); + if (i < 0) + goto end; + if (i == 0) + BIO_printf(bio_err, "verify failure\n"); + else + BIO_printf(bio_err, "verify OK\n"); + } + + /* Print requested information the order that the flags were given. */ + for (i = 1; i <= argc; i++) { + if (crl_config.issuer == i) { + print_name(bio_out, "issuer=", + X509_CRL_get_issuer(x), nmflag); + } + if (crl_config.crlnumber == i) { + ASN1_INTEGER *crlnum; + crlnum = X509_CRL_get_ext_d2i(x, + NID_crl_number, NULL, NULL); + BIO_printf(bio_out, "crlNumber="); + if (crlnum) { + i2a_ASN1_INTEGER(bio_out, crlnum); + ASN1_INTEGER_free(crlnum); + } else + BIO_puts(bio_out, ""); + BIO_printf(bio_out, "\n"); + } + if (crl_config.hash == i) { + BIO_printf(bio_out, "%08lx\n", + X509_NAME_hash(X509_CRL_get_issuer(x))); + } +#ifndef OPENSSL_NO_MD5 + if (crl_config.hash_old == i) { + BIO_printf(bio_out, "%08lx\n", + X509_NAME_hash_old(X509_CRL_get_issuer(x))); + } +#endif + if (crl_config.lastupdate == i) { + BIO_printf(bio_out, "lastUpdate="); + ASN1_TIME_print(bio_out, + X509_CRL_get_lastUpdate(x)); + BIO_printf(bio_out, "\n"); + } + if (crl_config.nextupdate == i) { + BIO_printf(bio_out, "nextUpdate="); + if (X509_CRL_get_nextUpdate(x)) + ASN1_TIME_print(bio_out, + X509_CRL_get_nextUpdate(x)); + else + BIO_printf(bio_out, "NONE"); + BIO_printf(bio_out, "\n"); + } + if (crl_config.fingerprint == i) { + int j; + unsigned int n; + unsigned char md[EVP_MAX_MD_SIZE]; + + if (!X509_CRL_digest(x, digest, md, &n)) { + BIO_printf(bio_err, "out of memory\n"); + goto end; + } + BIO_printf(bio_out, "%s Fingerprint=", + OBJ_nid2sn(EVP_MD_type(digest))); + for (j = 0; j < (int) n; j++) { + BIO_printf(bio_out, "%02X%c", md[j], + (j + 1 == (int)n) ? '\n' : ':'); + } + } + } + + out = BIO_new(BIO_s_file()); + if (out == NULL) { + ERR_print_errors(bio_err); + goto end; + } + if (crl_config.outfile == NULL) { + BIO_set_fp(out, stdout, BIO_NOCLOSE); + } else { + if (BIO_write_filename(out, crl_config.outfile) <= 0) { + perror(crl_config.outfile); + goto end; + } + } + + if (crl_config.text) + X509_CRL_print(out, x); + + if (crl_config.noout) { + ret = 0; + goto end; + } + if (crl_config.outformat == FORMAT_ASN1) + i = (int) i2d_X509_CRL_bio(out, x); + else if (crl_config.outformat == FORMAT_PEM) + i = PEM_write_bio_X509_CRL(out, x); + else { + BIO_printf(bio_err, + "bad output format specified for outfile\n"); + goto end; + } + if (!i) { + BIO_printf(bio_err, "unable to write CRL\n"); + goto end; + } + ret = 0; + +end: + BIO_free_all(out); + BIO_free_all(bio_out); + bio_out = NULL; + X509_CRL_free(x); + if (store) { + X509_STORE_CTX_cleanup(&ctx); + X509_STORE_free(store); + } + + return (ret); +} + +static X509_CRL * +load_crl(char *infile, int format) +{ + X509_CRL *x = NULL; + BIO *in = NULL; + + in = BIO_new(BIO_s_file()); + if (in == NULL) { + ERR_print_errors(bio_err); + goto end; + } + if (infile == NULL) + BIO_set_fp(in, stdin, BIO_NOCLOSE); + else { + if (BIO_read_filename(in, infile) <= 0) { + perror(infile); + goto end; + } + } + if (format == FORMAT_ASN1) + x = d2i_X509_CRL_bio(in, NULL); + else if (format == FORMAT_PEM) + x = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL); + else { + BIO_printf(bio_err, + "bad input format specified for input crl\n"); + goto end; + } + if (x == NULL) { + BIO_printf(bio_err, "unable to load CRL\n"); + ERR_print_errors(bio_err); + goto end; + } + +end: + BIO_free(in); + return (x); +} diff --git a/bin/openssl/crl2p7.c b/bin/openssl/crl2p7.c new file mode 100644 index 0000000000..9fceee8098 --- /dev/null +++ b/bin/openssl/crl2p7.c @@ -0,0 +1,333 @@ +/* $OpenBSD: crl2p7.c,v 1.7 2017/01/20 08:57:11 deraadt Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +/* This was written by Gordon Chaffee + * and donated 'to the cause' along with lots and lots of other fixes to + * the library. */ + +#include + +#include +#include + +#include "apps.h" + +#include +#include +#include +#include +#include +#include + +static int add_certs_from_file(STACK_OF(X509) * stack, char *certfile); + +static struct { + STACK_OF(OPENSSL_STRING) *certflst; + char *infile; + int informat; + int nocrl; + char *outfile; + int outformat; +} crl2p7_config; + +static int +crl2p7_opt_certfile(char *arg) +{ + if (crl2p7_config.certflst == NULL) + crl2p7_config.certflst = sk_OPENSSL_STRING_new_null(); + if (crl2p7_config.certflst == NULL) { + fprintf(stderr, "out of memory\n"); + return (1); + } + if (!sk_OPENSSL_STRING_push(crl2p7_config.certflst, arg)) { + fprintf(stderr, "out of memory\n"); + return (1); + } + + return (0); +} + +static struct option crl2p7_options[] = { + { + .name = "certfile", + .argname = "file", + .desc = "Chain of PEM certificates to a trusted CA", + .type = OPTION_ARG_FUNC, + .opt.argfunc = crl2p7_opt_certfile, + }, + { + .name = "in", + .argname = "file", + .desc = "Input file (default stdin)", + .type = OPTION_ARG, + .opt.arg = &crl2p7_config.infile, + }, + { + .name = "inform", + .argname = "format", + .desc = "Input format (DER or PEM (default))", + .type = OPTION_ARG_FORMAT, + .opt.value = &crl2p7_config.informat, + }, + { + .name = "nocrl", + .desc = "Do not read CRL from input or include CRL in output", + .type = OPTION_FLAG, + .opt.flag = &crl2p7_config.nocrl, + }, + { + .name = "out", + .argname = "file", + .desc = "Output file (default stdout)", + .type = OPTION_ARG, + .opt.arg = &crl2p7_config.outfile, + }, + { + .name = "outform", + .argname = "format", + .desc = "Output format (DER or PEM (default))", + .type = OPTION_ARG_FORMAT, + .opt.value = &crl2p7_config.outformat, + }, + { NULL }, +}; + +static void +crl2p7_usage(void) +{ + fprintf(stderr, + "usage: crl2p7 [-certfile file] [-in file] [-inform DER | PEM]\n" + " [-nocrl] [-out file] [-outform DER | PEM]\n\n"); + options_usage(crl2p7_options); +} + +int +crl2pkcs7_main(int argc, char **argv) +{ + int i; + BIO *in = NULL, *out = NULL; + char *certfile; + PKCS7 *p7 = NULL; + PKCS7_SIGNED *p7s = NULL; + X509_CRL *crl = NULL; + STACK_OF(X509_CRL) *crl_stack = NULL; + STACK_OF(X509) *cert_stack = NULL; + int ret = 1; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + memset(&crl2p7_config, 0, sizeof(crl2p7_config)); + + crl2p7_config.informat = FORMAT_PEM; + crl2p7_config.outformat = FORMAT_PEM; + + if (options_parse(argc, argv, crl2p7_options, NULL, NULL) != 0) { + crl2p7_usage(); + goto end; + } + + in = BIO_new(BIO_s_file()); + out = BIO_new(BIO_s_file()); + if (in == NULL || out == NULL) { + ERR_print_errors(bio_err); + goto end; + } + if (!crl2p7_config.nocrl) { + if (crl2p7_config.infile == NULL) + BIO_set_fp(in, stdin, BIO_NOCLOSE); + else { + if (BIO_read_filename(in, crl2p7_config.infile) <= 0) { + perror(crl2p7_config.infile); + goto end; + } + } + + if (crl2p7_config.informat == FORMAT_ASN1) + crl = d2i_X509_CRL_bio(in, NULL); + else if (crl2p7_config.informat == FORMAT_PEM) + crl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL); + else { + BIO_printf(bio_err, + "bad input format specified for input crl\n"); + goto end; + } + if (crl == NULL) { + BIO_printf(bio_err, "unable to load CRL\n"); + ERR_print_errors(bio_err); + goto end; + } + } + if ((p7 = PKCS7_new()) == NULL) + goto end; + if ((p7s = PKCS7_SIGNED_new()) == NULL) + goto end; + p7->type = OBJ_nid2obj(NID_pkcs7_signed); + p7->d.sign = p7s; + p7s->contents->type = OBJ_nid2obj(NID_pkcs7_data); + + if (!ASN1_INTEGER_set(p7s->version, 1)) + goto end; + if ((crl_stack = sk_X509_CRL_new_null()) == NULL) + goto end; + p7s->crl = crl_stack; + if (crl != NULL) { + sk_X509_CRL_push(crl_stack, crl); + crl = NULL; /* now part of p7 for freeing */ + } + if ((cert_stack = sk_X509_new_null()) == NULL) + goto end; + p7s->cert = cert_stack; + + if (crl2p7_config.certflst) { + for (i = 0; i < sk_OPENSSL_STRING_num(crl2p7_config.certflst); i++) { + certfile = sk_OPENSSL_STRING_value(crl2p7_config.certflst, i); + if (add_certs_from_file(cert_stack, certfile) < 0) { + BIO_printf(bio_err, + "error loading certificates\n"); + ERR_print_errors(bio_err); + goto end; + } + } + } + + sk_OPENSSL_STRING_free(crl2p7_config.certflst); + + if (crl2p7_config.outfile == NULL) { + BIO_set_fp(out, stdout, BIO_NOCLOSE); + } else { + if (BIO_write_filename(out, crl2p7_config.outfile) <= 0) { + perror(crl2p7_config.outfile); + goto end; + } + } + + if (crl2p7_config.outformat == FORMAT_ASN1) + i = i2d_PKCS7_bio(out, p7); + else if (crl2p7_config.outformat == FORMAT_PEM) + i = PEM_write_bio_PKCS7(out, p7); + else { + BIO_printf(bio_err, + "bad output format specified for outfile\n"); + goto end; + } + if (!i) { + BIO_printf(bio_err, "unable to write pkcs7 object\n"); + ERR_print_errors(bio_err); + goto end; + } + ret = 0; + +end: + if (in != NULL) + BIO_free(in); + if (out != NULL) + BIO_free_all(out); + if (p7 != NULL) + PKCS7_free(p7); + if (crl != NULL) + X509_CRL_free(crl); + + return (ret); +} + +static int +add_certs_from_file(STACK_OF(X509) *stack, char *certfile) +{ + BIO *in = NULL; + int count = 0; + int ret = -1; + STACK_OF(X509_INFO) *sk = NULL; + X509_INFO *xi; + + in = BIO_new(BIO_s_file()); + if (in == NULL || BIO_read_filename(in, certfile) <= 0) { + BIO_printf(bio_err, "error opening the file, %s\n", certfile); + goto end; + } + /* This loads from a file, a stack of x509/crl/pkey sets */ + sk = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL); + if (sk == NULL) { + BIO_printf(bio_err, "error reading the file, %s\n", certfile); + goto end; + } + /* scan over it and pull out the CRL's */ + while (sk_X509_INFO_num(sk)) { + xi = sk_X509_INFO_shift(sk); + if (xi->x509 != NULL) { + sk_X509_push(stack, xi->x509); + xi->x509 = NULL; + count++; + } + X509_INFO_free(xi); + } + + ret = count; + +end: + /* never need to free x */ + if (in != NULL) + BIO_free(in); + if (sk != NULL) + sk_X509_INFO_free(sk); + return (ret); +} diff --git a/bin/openssl/dgst.c b/bin/openssl/dgst.c new file mode 100644 index 0000000000..ce50e08b53 --- /dev/null +++ b/bin/openssl/dgst.c @@ -0,0 +1,544 @@ +/* $OpenBSD: dgst.c,v 1.10 2017/01/20 08:57:11 deraadt Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include +#include +#include + +#include "apps.h" + +#include +#include +#include +#include +#include +#include +#include + +#define BUFSIZE 1024*8 + +int +do_fp(BIO * out, unsigned char *buf, BIO * bp, int sep, int binout, + EVP_PKEY * key, unsigned char *sigin, int siglen, + const char *sig_name, const char *md_name, + const char *file, BIO * bmd); + +static void +list_md_fn(const EVP_MD * m, const char *from, const char *to, void *arg) +{ + const char *mname; + /* Skip aliases */ + if (!m) + return; + mname = OBJ_nid2ln(EVP_MD_type(m)); + /* Skip shortnames */ + if (strcmp(from, mname)) + return; + /* Skip clones */ + if (EVP_MD_flags(m) & EVP_MD_FLAG_PKEY_DIGEST) + return; + if (strchr(mname, ' ')) + mname = EVP_MD_name(m); + BIO_printf(arg, "-%-14s to use the %s message digest algorithm\n", + mname, mname); +} + +int +dgst_main(int argc, char **argv) +{ + unsigned char *buf = NULL; + int i, err = 1; + const EVP_MD *md = NULL, *m; + BIO *in = NULL, *inp; + BIO *bmd = NULL; + BIO *out = NULL; +#define PROG_NAME_SIZE 39 + char pname[PROG_NAME_SIZE + 1]; + int separator = 0; + int debug = 0; + int keyform = FORMAT_PEM; + const char *outfile = NULL, *keyfile = NULL; + const char *sigfile = NULL; + int out_bin = -1, want_pub = 0, do_verify = 0; + EVP_PKEY *sigkey = NULL; + unsigned char *sigbuf = NULL; + int siglen = 0; + char *passargin = NULL, *passin = NULL; + char *hmac_key = NULL; + char *mac_name = NULL; + STACK_OF(OPENSSL_STRING) * sigopts = NULL, *macopts = NULL; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + if ((buf = malloc(BUFSIZE)) == NULL) { + BIO_printf(bio_err, "out of memory\n"); + goto end; + } + + /* first check the program name */ + program_name(argv[0], pname, sizeof pname); + + md = EVP_get_digestbyname(pname); + + argc--; + argv++; + while (argc > 0) { + if ((*argv)[0] != '-') + break; + if (strcmp(*argv, "-c") == 0) + separator = 1; + else if (strcmp(*argv, "-r") == 0) + separator = 2; + else if (strcmp(*argv, "-out") == 0) { + if (--argc < 1) + break; + outfile = *(++argv); + } else if (strcmp(*argv, "-sign") == 0) { + if (--argc < 1) + break; + keyfile = *(++argv); + } else if (!strcmp(*argv, "-passin")) { + if (--argc < 1) + break; + passargin = *++argv; + } else if (strcmp(*argv, "-verify") == 0) { + if (--argc < 1) + break; + keyfile = *(++argv); + want_pub = 1; + do_verify = 1; + } else if (strcmp(*argv, "-prverify") == 0) { + if (--argc < 1) + break; + keyfile = *(++argv); + do_verify = 1; + } else if (strcmp(*argv, "-signature") == 0) { + if (--argc < 1) + break; + sigfile = *(++argv); + } else if (strcmp(*argv, "-keyform") == 0) { + if (--argc < 1) + break; + keyform = str2fmt(*(++argv)); + } + else if (strcmp(*argv, "-hex") == 0) + out_bin = 0; + else if (strcmp(*argv, "-binary") == 0) + out_bin = 1; + else if (strcmp(*argv, "-d") == 0) + debug = 1; + else if (!strcmp(*argv, "-hmac")) { + if (--argc < 1) + break; + hmac_key = *++argv; + } else if (!strcmp(*argv, "-mac")) { + if (--argc < 1) + break; + mac_name = *++argv; + } else if (strcmp(*argv, "-sigopt") == 0) { + if (--argc < 1) + break; + if (!sigopts) + sigopts = sk_OPENSSL_STRING_new_null(); + if (!sigopts || !sk_OPENSSL_STRING_push(sigopts, *(++argv))) + break; + } else if (strcmp(*argv, "-macopt") == 0) { + if (--argc < 1) + break; + if (!macopts) + macopts = sk_OPENSSL_STRING_new_null(); + if (!macopts || !sk_OPENSSL_STRING_push(macopts, *(++argv))) + break; + } else if ((m = EVP_get_digestbyname(&((*argv)[1]))) != NULL) + md = m; + else + break; + argc--; + argv++; + } + + + if (do_verify && !sigfile) { + BIO_printf(bio_err, "No signature to verify: use the -signature option\n"); + goto end; + } + if ((argc > 0) && (argv[0][0] == '-')) { /* bad option */ + BIO_printf(bio_err, "unknown option '%s'\n", *argv); + BIO_printf(bio_err, "options are\n"); + BIO_printf(bio_err, "-c to output the digest with separating colons\n"); + BIO_printf(bio_err, "-r to output the digest in coreutils format\n"); + BIO_printf(bio_err, "-d to output debug info\n"); + BIO_printf(bio_err, "-hex output as hex dump\n"); + BIO_printf(bio_err, "-binary output in binary form\n"); + BIO_printf(bio_err, "-sign file sign digest using private key in file\n"); + BIO_printf(bio_err, "-verify file verify a signature using public key in file\n"); + BIO_printf(bio_err, "-prverify file verify a signature using private key in file\n"); + BIO_printf(bio_err, "-keyform arg key file format (PEM)\n"); + BIO_printf(bio_err, "-out filename output to filename rather than stdout\n"); + BIO_printf(bio_err, "-signature file signature to verify\n"); + BIO_printf(bio_err, "-sigopt nm:v signature parameter\n"); + BIO_printf(bio_err, "-hmac key create hashed MAC with key\n"); + BIO_printf(bio_err, "-mac algorithm create MAC (not neccessarily HMAC)\n"); + BIO_printf(bio_err, "-macopt nm:v MAC algorithm parameters or key\n"); + + EVP_MD_do_all_sorted(list_md_fn, bio_err); + goto end; + } + + in = BIO_new(BIO_s_file()); + bmd = BIO_new(BIO_f_md()); + if (in == NULL || bmd == NULL) { + ERR_print_errors(bio_err); + goto end; + } + + if (debug) { + BIO_set_callback(in, BIO_debug_callback); + /* needed for windows 3.1 */ + BIO_set_callback_arg(in, (char *) bio_err); + } + if (!app_passwd(bio_err, passargin, NULL, &passin, NULL)) { + BIO_printf(bio_err, "Error getting password\n"); + goto end; + } + if (out_bin == -1) { + if (keyfile) + out_bin = 1; + else + out_bin = 0; + } + + if (outfile) { + if (out_bin) + out = BIO_new_file(outfile, "wb"); + else + out = BIO_new_file(outfile, "w"); + } else { + out = BIO_new_fp(stdout, BIO_NOCLOSE); + } + + if (!out) { + BIO_printf(bio_err, "Error opening output file %s\n", + outfile ? outfile : "(stdout)"); + ERR_print_errors(bio_err); + goto end; + } + if ((!!mac_name + !!keyfile + !!hmac_key) > 1) { + BIO_printf(bio_err, "MAC and Signing key cannot both be specified\n"); + goto end; + } + if (keyfile) { + if (want_pub) + sigkey = load_pubkey(bio_err, keyfile, keyform, 0, NULL, + "key file"); + else + sigkey = load_key(bio_err, keyfile, keyform, 0, passin, + "key file"); + if (!sigkey) { + /* + * load_[pub]key() has already printed an appropriate + * message + */ + goto end; + } + } + if (mac_name) { + EVP_PKEY_CTX *mac_ctx = NULL; + int r = 0; + if (!init_gen_str(bio_err, &mac_ctx, mac_name, 0)) + goto mac_end; + if (macopts) { + char *macopt; + for (i = 0; i < sk_OPENSSL_STRING_num(macopts); i++) { + macopt = sk_OPENSSL_STRING_value(macopts, i); + if (pkey_ctrl_string(mac_ctx, macopt) <= 0) { + BIO_printf(bio_err, + "MAC parameter error \"%s\"\n", + macopt); + ERR_print_errors(bio_err); + goto mac_end; + } + } + } + if (EVP_PKEY_keygen(mac_ctx, &sigkey) <= 0) { + BIO_puts(bio_err, "Error generating key\n"); + ERR_print_errors(bio_err); + goto mac_end; + } + r = 1; +mac_end: + if (mac_ctx) + EVP_PKEY_CTX_free(mac_ctx); + if (r == 0) + goto end; + } + if (hmac_key) { + sigkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, + (unsigned char *) hmac_key, -1); + if (!sigkey) + goto end; + } + if (sigkey) { + EVP_MD_CTX *mctx = NULL; + EVP_PKEY_CTX *pctx = NULL; + int r; + if (!BIO_get_md_ctx(bmd, &mctx)) { + BIO_printf(bio_err, "Error getting context\n"); + ERR_print_errors(bio_err); + goto end; + } + if (do_verify) + r = EVP_DigestVerifyInit(mctx, &pctx, md, NULL, sigkey); + else + r = EVP_DigestSignInit(mctx, &pctx, md, NULL, sigkey); + if (!r) { + BIO_printf(bio_err, "Error setting context\n"); + ERR_print_errors(bio_err); + goto end; + } + if (sigopts) { + char *sigopt; + for (i = 0; i < sk_OPENSSL_STRING_num(sigopts); i++) { + sigopt = sk_OPENSSL_STRING_value(sigopts, i); + if (pkey_ctrl_string(pctx, sigopt) <= 0) { + BIO_printf(bio_err, + "parameter error \"%s\"\n", + sigopt); + ERR_print_errors(bio_err); + goto end; + } + } + } + } + /* we use md as a filter, reading from 'in' */ + else { + if (md == NULL) + md = EVP_md5(); + if (!BIO_set_md(bmd, md)) { + BIO_printf(bio_err, "Error setting digest %s\n", pname); + ERR_print_errors(bio_err); + goto end; + } + } + + if (sigfile && sigkey) { + BIO *sigbio; + siglen = EVP_PKEY_size(sigkey); + sigbuf = malloc(siglen); + if (sigbuf == NULL) { + BIO_printf(bio_err, "out of memory\n"); + ERR_print_errors(bio_err); + goto end; + } + sigbio = BIO_new_file(sigfile, "rb"); + if (!sigbio) { + BIO_printf(bio_err, "Error opening signature file %s\n", + sigfile); + ERR_print_errors(bio_err); + goto end; + } + siglen = BIO_read(sigbio, sigbuf, siglen); + BIO_free(sigbio); + if (siglen <= 0) { + BIO_printf(bio_err, "Error reading signature file %s\n", + sigfile); + ERR_print_errors(bio_err); + goto end; + } + } + inp = BIO_push(bmd, in); + + if (md == NULL) { + EVP_MD_CTX *tctx; + BIO_get_md_ctx(bmd, &tctx); + md = EVP_MD_CTX_md(tctx); + } + if (argc == 0) { + BIO_set_fp(in, stdin, BIO_NOCLOSE); + err = do_fp(out, buf, inp, separator, out_bin, sigkey, sigbuf, + siglen, NULL, NULL, "stdin", bmd); + } else { + const char *md_name = NULL, *sig_name = NULL; + if (!out_bin) { + if (sigkey) { + const EVP_PKEY_ASN1_METHOD *ameth; + ameth = EVP_PKEY_get0_asn1(sigkey); + if (ameth) + EVP_PKEY_asn1_get0_info(NULL, NULL, + NULL, NULL, &sig_name, ameth); + } + md_name = EVP_MD_name(md); + } + err = 0; + for (i = 0; i < argc; i++) { + int r; + if (BIO_read_filename(in, argv[i]) <= 0) { + perror(argv[i]); + err++; + continue; + } else { + r = do_fp(out, buf, inp, separator, out_bin, + sigkey, sigbuf, siglen, sig_name, md_name, + argv[i], bmd); + } + if (r) + err = r; + (void) BIO_reset(bmd); + } + } + +end: + if (buf != NULL) { + explicit_bzero(buf, BUFSIZE); + free(buf); + } + if (in != NULL) + BIO_free(in); + free(passin); + BIO_free_all(out); + EVP_PKEY_free(sigkey); + if (sigopts) + sk_OPENSSL_STRING_free(sigopts); + if (macopts) + sk_OPENSSL_STRING_free(macopts); + free(sigbuf); + if (bmd != NULL) + BIO_free(bmd); + + return (err); +} + +int +do_fp(BIO * out, unsigned char *buf, BIO * bp, int sep, int binout, + EVP_PKEY * key, unsigned char *sigin, int siglen, + const char *sig_name, const char *md_name, + const char *file, BIO * bmd) +{ + size_t len; + int i; + + for (;;) { + i = BIO_read(bp, (char *) buf, BUFSIZE); + if (i < 0) { + BIO_printf(bio_err, "Read Error in %s\n", file); + ERR_print_errors(bio_err); + return 1; + } + if (i == 0) + break; + } + if (sigin) { + EVP_MD_CTX *ctx; + BIO_get_md_ctx(bp, &ctx); + i = EVP_DigestVerifyFinal(ctx, sigin, (unsigned int) siglen); + if (i > 0) + BIO_printf(out, "Verified OK\n"); + else if (i == 0) { + BIO_printf(out, "Verification Failure\n"); + return 1; + } else { + BIO_printf(bio_err, "Error Verifying Data\n"); + ERR_print_errors(bio_err); + return 1; + } + return 0; + } + if (key) { + EVP_MD_CTX *ctx; + BIO_get_md_ctx(bp, &ctx); + len = BUFSIZE; + if (!EVP_DigestSignFinal(ctx, buf, &len)) { + BIO_printf(bio_err, "Error Signing Data\n"); + ERR_print_errors(bio_err); + return 1; + } + } else { + len = BIO_gets(bp, (char *) buf, BUFSIZE); + if ((int) len < 0) { + ERR_print_errors(bio_err); + return 1; + } + } + + if (binout) + BIO_write(out, buf, len); + else if (sep == 2) { + for (i = 0; i < (int) len; i++) + BIO_printf(out, "%02x", buf[i]); + BIO_printf(out, " *%s\n", file); + } else { + if (sig_name) + BIO_printf(out, "%s-%s(%s)= ", sig_name, md_name, file); + else if (md_name) + BIO_printf(out, "%s(%s)= ", md_name, file); + else + BIO_printf(out, "(%s)= ", file); + for (i = 0; i < (int) len; i++) { + if (sep && (i != 0)) + BIO_printf(out, ":"); + BIO_printf(out, "%02x", buf[i]); + } + BIO_printf(out, "\n"); + } + return 0; +} diff --git a/bin/openssl/dh.c b/bin/openssl/dh.c new file mode 100644 index 0000000000..eb51b4b12f --- /dev/null +++ b/bin/openssl/dh.c @@ -0,0 +1,300 @@ +/* $OpenBSD: dh.c,v 1.9 2017/01/20 08:57:11 deraadt Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include /* for OPENSSL_NO_DH */ + +#ifndef OPENSSL_NO_DH + +#include +#include +#include +#include + +#include "apps.h" + +#include +#include +#include +#include +#include +#include + +static struct { + int C; + int check; + char *infile; + int informat; + int noout; + char *outfile; + int outformat; + int text; +} dh_config; + +static struct option dh_options[] = { + { + .name = "C", + .desc = "Convert DH parameters into C code", + .type = OPTION_FLAG, + .opt.flag = &dh_config.C, + }, + { + .name = "check", + .desc = "Check the DH parameters", + .type = OPTION_FLAG, + .opt.flag = &dh_config.check, + }, + { + .name = "in", + .argname = "file", + .desc = "Input file (default stdin)", + .type = OPTION_ARG, + .opt.arg = &dh_config.infile, + }, + { + .name = "inform", + .argname = "format", + .desc = "Input format (DER or PEM (default))", + .type = OPTION_ARG_FORMAT, + .opt.value = &dh_config.informat, + }, + { + .name = "noout", + .desc = "No output", + .type = OPTION_FLAG, + .opt.flag = &dh_config.noout, + }, + { + .name = "out", + .argname = "file", + .desc = "Output file (default stdout)", + .type = OPTION_ARG, + .opt.arg = &dh_config.outfile, + }, + { + .name = "outform", + .argname = "format", + .desc = "Output format (DER or PEM (default))", + .type = OPTION_ARG_FORMAT, + .opt.value = &dh_config.outformat, + }, + { + .name = "text", + .desc = "Print a text form of the DH parameters", + .type = OPTION_FLAG, + .opt.flag = &dh_config.text, + }, + { NULL }, +}; + +static void +dh_usage(void) +{ + fprintf(stderr, + "usage: dh [-C] [-check] [-in file] [-inform format]\n" + " [-noout] [-out file] [-outform format] [-text]\n\n"); + options_usage(dh_options); +} + +int +dh_main(int argc, char **argv) +{ + DH *dh = NULL; + int i; + BIO *in = NULL, *out = NULL; + int ret = 1; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + memset(&dh_config, 0, sizeof(dh_config)); + + dh_config.informat = FORMAT_PEM; + dh_config.outformat = FORMAT_PEM; + + if (options_parse(argc, argv, dh_options, NULL, NULL) != 0) { + dh_usage(); + goto end; + } + + in = BIO_new(BIO_s_file()); + out = BIO_new(BIO_s_file()); + if (in == NULL || out == NULL) { + ERR_print_errors(bio_err); + goto end; + } + if (dh_config.infile == NULL) + BIO_set_fp(in, stdin, BIO_NOCLOSE); + else { + if (BIO_read_filename(in, dh_config.infile) <= 0) { + perror(dh_config.infile); + goto end; + } + } + if (dh_config.outfile == NULL) { + BIO_set_fp(out, stdout, BIO_NOCLOSE); + } else { + if (BIO_write_filename(out, dh_config.outfile) <= 0) { + perror(dh_config.outfile); + goto end; + } + } + + if (dh_config.informat == FORMAT_ASN1) + dh = d2i_DHparams_bio(in, NULL); + else if (dh_config.informat == FORMAT_PEM) + dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL); + else { + BIO_printf(bio_err, "bad input format specified\n"); + goto end; + } + if (dh == NULL) { + BIO_printf(bio_err, "unable to load DH parameters\n"); + ERR_print_errors(bio_err); + goto end; + } + if (dh_config.text) { + DHparams_print(out, dh); + } + if (dh_config.check) { + if (!DH_check(dh, &i)) { + ERR_print_errors(bio_err); + goto end; + } + if (i & DH_CHECK_P_NOT_PRIME) + printf("p value is not prime\n"); + if (i & DH_CHECK_P_NOT_SAFE_PRIME) + printf("p value is not a safe prime\n"); + if (i & DH_UNABLE_TO_CHECK_GENERATOR) + printf("unable to check the generator value\n"); + if (i & DH_NOT_SUITABLE_GENERATOR) + printf("the g value is not a generator\n"); + if (i == 0) + printf("DH parameters appear to be ok.\n"); + } + if (dh_config.C) { + unsigned char *data; + int len, l, bits; + + len = BN_num_bytes(dh->p); + bits = BN_num_bits(dh->p); + data = malloc(len); + if (data == NULL) { + perror("malloc"); + goto end; + } + l = BN_bn2bin(dh->p, data); + printf("static unsigned char dh%d_p[] = {", bits); + for (i = 0; i < l; i++) { + if ((i % 12) == 0) + printf("\n\t"); + printf("0x%02X, ", data[i]); + } + printf("\n\t};\n"); + + l = BN_bn2bin(dh->g, data); + printf("static unsigned char dh%d_g[] = {", bits); + for (i = 0; i < l; i++) { + if ((i % 12) == 0) + printf("\n\t"); + printf("0x%02X, ", data[i]); + } + printf("\n\t};\n\n"); + + printf("DH *get_dh%d()\n\t{\n", bits); + printf("\tDH *dh;\n\n"); + printf("\tif ((dh = DH_new()) == NULL) return(NULL);\n"); + printf("\tdh->p = BN_bin2bn(dh%d_p, sizeof(dh%d_p), NULL);\n", + bits, bits); + printf("\tdh->g = BN_bin2bn(dh%d_g, sizeof(dh%d_g), NULL);\n", + bits, bits); + printf("\tif ((dh->p == NULL) || (dh->g == NULL))\n"); + printf("\t\treturn(NULL);\n"); + printf("\treturn(dh);\n\t}\n"); + free(data); + } + if (!dh_config.noout) { + if (dh_config.outformat == FORMAT_ASN1) + i = i2d_DHparams_bio(out, dh); + else if (dh_config.outformat == FORMAT_PEM) + i = PEM_write_bio_DHparams(out, dh); + else { + BIO_printf(bio_err, "bad output format specified for outfile\n"); + goto end; + } + if (!i) { + BIO_printf(bio_err, "unable to write DH parameters\n"); + ERR_print_errors(bio_err); + goto end; + } + } + ret = 0; + +end: + BIO_free(in); + if (out != NULL) + BIO_free_all(out); + if (dh != NULL) + DH_free(dh); + + return (ret); +} +#endif diff --git a/bin/openssl/dhparam.c b/bin/openssl/dhparam.c new file mode 100644 index 0000000000..7c3bfb44c8 --- /dev/null +++ b/bin/openssl/dhparam.c @@ -0,0 +1,499 @@ +/* $OpenBSD: dhparam.c,v 1.9 2017/01/20 08:57:11 deraadt Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2000 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include /* for OPENSSL_NO_DH */ + +#ifndef OPENSSL_NO_DH + +#include +#include +#include +#include + +#include "apps.h" + +#include +#include +#include +#include +#include +#include + +#include + +#define DEFBITS 2048 + +struct { + int C; + int check; + int dsaparam; + int g; + char *infile; + int informat; + int noout; + char *outfile; + int outformat; + int text; +} dhparam_config; + +struct option dhparam_options[] = { + { + .name = "2", + .desc = "Generate DH parameters with a generator value of 2 " + "(default)", + .type = OPTION_VALUE, + .opt.value = &dhparam_config.g, + .value = 2, + }, + { + .name = "5", + .desc = "Generate DH parameters with a generator value of 5", + .type = OPTION_VALUE, + .opt.value = &dhparam_config.g, + .value = 5, + }, + { + .name = "C", + .desc = "Convert DH parameters into C code", + .type = OPTION_FLAG, + .opt.flag = &dhparam_config.C, + }, + { + .name = "check", + .desc = "Check the DH parameters", + .type = OPTION_FLAG, + .opt.flag = &dhparam_config.check, + }, + { + .name = "dsaparam", + .desc = "Read or generate DSA parameters and convert to DH", + .type = OPTION_FLAG, + .opt.flag = &dhparam_config.dsaparam, + }, + { + .name = "in", + .argname = "file", + .desc = "Input file (default stdin)", + .type = OPTION_ARG, + .opt.arg = &dhparam_config.infile, + }, + { + .name = "inform", + .argname = "format", + .desc = "Input format (DER or PEM (default))", + .type = OPTION_ARG_FORMAT, + .opt.value = &dhparam_config.informat, + }, + { + .name = "noout", + .desc = "Do not output encoded version of DH parameters", + .type = OPTION_FLAG, + .opt.flag = &dhparam_config.noout, + }, + { + .name = "out", + .argname = "file", + .desc = "Output file (default stdout)", + .type = OPTION_ARG, + .opt.arg = &dhparam_config.outfile, + }, + { + .name = "outform", + .argname = "format", + .desc = "Output format (DER or PEM (default))", + .type = OPTION_ARG_FORMAT, + .opt.value = &dhparam_config.outformat, + }, + { + .name = "text", + .desc = "Print DH parameters in plain text", + .type = OPTION_FLAG, + .opt.flag = &dhparam_config.text, + }, + { NULL }, +}; + +static void +dhparam_usage() +{ + fprintf(stderr, + "usage: dhparam [-2 | -5] [-C] [-check] [-dsaparam]\n" + " [-in file] [-inform DER | PEM] [-noout] [-out file]\n" + " [-outform DER | PEM] [-text] [numbits]\n\n"); + options_usage(dhparam_options); +} + +static int dh_cb(int p, int n, BN_GENCB * cb); + +int +dhparam_main(int argc, char **argv) +{ + BIO *in = NULL, *out = NULL; + char *num_bits = NULL; + DH *dh = NULL; + int num = 0; + int ret = 1; + int i; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + memset(&dhparam_config, 0, sizeof(dhparam_config)); + + dhparam_config.informat = FORMAT_PEM; + dhparam_config.outformat = FORMAT_PEM; + + if (options_parse(argc, argv, dhparam_options, &num_bits, NULL) != 0) { + dhparam_usage(); + return (1); + } + + if (num_bits != NULL) { + if(sscanf(num_bits, "%d", &num) == 0 || num <= 0) { + BIO_printf(bio_err, "invalid number of bits: %s\n", + num_bits); + return (1); + } + } + + if (dhparam_config.g && !num) + num = DEFBITS; + + if (dhparam_config.dsaparam) { + if (dhparam_config.g) { + BIO_printf(bio_err, "generator may not be chosen for DSA parameters\n"); + goto end; + } + } else { + /* DH parameters */ + if (num && !dhparam_config.g) + dhparam_config.g = 2; + } + + if (num) { + + BN_GENCB cb; + BN_GENCB_set(&cb, dh_cb, bio_err); + if (dhparam_config.dsaparam) { + DSA *dsa = DSA_new(); + + BIO_printf(bio_err, "Generating DSA parameters, %d bit long prime\n", num); + if (!dsa || !DSA_generate_parameters_ex(dsa, num, + NULL, 0, NULL, NULL, &cb)) { + if (dsa) + DSA_free(dsa); + ERR_print_errors(bio_err); + goto end; + } + dh = DSA_dup_DH(dsa); + DSA_free(dsa); + if (dh == NULL) { + ERR_print_errors(bio_err); + goto end; + } + } else { + dh = DH_new(); + BIO_printf(bio_err, "Generating DH parameters, %d bit long safe prime, generator %d\n", num, dhparam_config.g); + BIO_printf(bio_err, "This is going to take a long time\n"); + if (!dh || !DH_generate_parameters_ex(dh, num, dhparam_config.g, &cb)) { + ERR_print_errors(bio_err); + goto end; + } + } + } else { + + in = BIO_new(BIO_s_file()); + if (in == NULL) { + ERR_print_errors(bio_err); + goto end; + } + if (dhparam_config.infile == NULL) + BIO_set_fp(in, stdin, BIO_NOCLOSE); + else { + if (BIO_read_filename(in, dhparam_config.infile) <= 0) { + perror(dhparam_config.infile); + goto end; + } + } + + if (dhparam_config.informat != FORMAT_ASN1 && + dhparam_config.informat != FORMAT_PEM) { + BIO_printf(bio_err, "bad input format specified\n"); + goto end; + } + if (dhparam_config.dsaparam) { + DSA *dsa; + + if (dhparam_config.informat == FORMAT_ASN1) + dsa = d2i_DSAparams_bio(in, NULL); + else /* informat == FORMAT_PEM */ + dsa = PEM_read_bio_DSAparams(in, NULL, NULL, NULL); + + if (dsa == NULL) { + BIO_printf(bio_err, "unable to load DSA parameters\n"); + ERR_print_errors(bio_err); + goto end; + } + dh = DSA_dup_DH(dsa); + DSA_free(dsa); + if (dh == NULL) { + ERR_print_errors(bio_err); + goto end; + } + } else + { + if (dhparam_config.informat == FORMAT_ASN1) + dh = d2i_DHparams_bio(in, NULL); + else /* informat == FORMAT_PEM */ + dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL); + + if (dh == NULL) { + BIO_printf(bio_err, "unable to load DH parameters\n"); + ERR_print_errors(bio_err); + goto end; + } + } + + /* dh != NULL */ + } + + out = BIO_new(BIO_s_file()); + if (out == NULL) { + ERR_print_errors(bio_err); + goto end; + } + if (dhparam_config.outfile == NULL) { + BIO_set_fp(out, stdout, BIO_NOCLOSE); + } else { + if (BIO_write_filename(out, dhparam_config.outfile) <= 0) { + perror(dhparam_config.outfile); + goto end; + } + } + + + if (dhparam_config.text) { + DHparams_print(out, dh); + } + if (dhparam_config.check) { + if (!DH_check(dh, &i)) { + ERR_print_errors(bio_err); + goto end; + } + if (i & DH_CHECK_P_NOT_PRIME) + printf("p value is not prime\n"); + if (i & DH_CHECK_P_NOT_SAFE_PRIME) + printf("p value is not a safe prime\n"); + if (i & DH_UNABLE_TO_CHECK_GENERATOR) + printf("unable to check the generator value\n"); + if (i & DH_NOT_SUITABLE_GENERATOR) + printf("the g value is not a generator\n"); + if (i == 0) + printf("DH parameters appear to be ok.\n"); + } + if (dhparam_config.C) { + unsigned char *data; + int len, l, bits; + + len = BN_num_bytes(dh->p); + bits = BN_num_bits(dh->p); + data = malloc(len); + if (data == NULL) { + perror("malloc"); + goto end; + } + printf("#ifndef HEADER_DH_H\n" + "#include \n" + "#endif\n"); + printf("DH *get_dh%d()\n\t{\n", bits); + + l = BN_bn2bin(dh->p, data); + printf("\tstatic unsigned char dh%d_p[] = {", bits); + for (i = 0; i < l; i++) { + if ((i % 12) == 0) + printf("\n\t\t"); + printf("0x%02X, ", data[i]); + } + printf("\n\t\t};\n"); + + l = BN_bn2bin(dh->g, data); + printf("\tstatic unsigned char dh%d_g[] = {", bits); + for (i = 0; i < l; i++) { + if ((i % 12) == 0) + printf("\n\t\t"); + printf("0x%02X, ", data[i]); + } + printf("\n\t\t};\n"); + + printf("\tDH *dh;\n\n"); + printf("\tif ((dh = DH_new()) == NULL) return(NULL);\n"); + printf("\tdh->p = BN_bin2bn(dh%d_p, sizeof(dh%d_p), NULL);\n", + bits, bits); + printf("\tdh->g = BN_bin2bn(dh%d_g, sizeof(dh%d_g), NULL);\n", + bits, bits); + printf("\tif ((dh->p == NULL) || (dh->g == NULL))\n"); + printf("\t\t{ DH_free(dh); return(NULL); }\n"); + if (dh->length) + printf("\tdh->length = %ld;\n", dh->length); + printf("\treturn(dh);\n\t}\n"); + free(data); + } + if (!dhparam_config.noout) { + if (dhparam_config.outformat == FORMAT_ASN1) + i = i2d_DHparams_bio(out, dh); + else if (dhparam_config.outformat == FORMAT_PEM) + i = PEM_write_bio_DHparams(out, dh); + else { + BIO_printf(bio_err, "bad output format specified for outfile\n"); + goto end; + } + if (!i) { + BIO_printf(bio_err, "unable to write DH parameters\n"); + ERR_print_errors(bio_err); + goto end; + } + } + ret = 0; + +end: + BIO_free(in); + if (out != NULL) + BIO_free_all(out); + if (dh != NULL) + DH_free(dh); + + return (ret); +} + +/* dh_cb is identical to dsa_cb in apps/dsaparam.c */ +static int +dh_cb(int p, int n, BN_GENCB * cb) +{ + char c = '*'; + + if (p == 0) + c = '.'; + if (p == 1) + c = '+'; + if (p == 2) + c = '*'; + if (p == 3) + c = '\n'; + BIO_write(cb->arg, &c, 1); + (void) BIO_flush(cb->arg); + return 1; +} + +#endif diff --git a/bin/openssl/dsa.c b/bin/openssl/dsa.c new file mode 100644 index 0000000000..5e0301c734 --- /dev/null +++ b/bin/openssl/dsa.c @@ -0,0 +1,373 @@ +/* $OpenBSD: dsa.c,v 1.9 2017/01/20 08:57:11 deraadt Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include /* for OPENSSL_NO_DSA */ + +#include +#include +#include +#include +#include + +#include "apps.h" + +#include +#include +#include +#include +#include +#include +#include + +static struct { + const EVP_CIPHER *enc; + char *infile; + int informat; + int modulus; + int noout; + char *outfile; + int outformat; + char *passargin; + char *passargout; + int pubin; + int pubout; + int pvk_encr; + int text; +} dsa_config; + +static int +dsa_opt_enc(int argc, char **argv, int *argsused) +{ + char *name = argv[0]; + + if (*name++ != '-') + return (1); + + if ((dsa_config.enc = EVP_get_cipherbyname(name)) != NULL) { + *argsused = 1; + return (0); + } + + return (1); +} + +static struct option dsa_options[] = { + { + .name = "in", + .argname = "file", + .desc = "Input file (default stdin)", + .type = OPTION_ARG, + .opt.arg = &dsa_config.infile, + }, + { + .name = "inform", + .argname = "format", + .desc = "Input format (PEM (default) or any other supported" + " format)", + .type = OPTION_ARG_FORMAT, + .opt.value = &dsa_config.informat, + }, + { + .name = "noout", + .desc = "No output", + .type = OPTION_FLAG, + .opt.flag = &dsa_config.noout, + }, + { + .name = "out", + .argname = "file", + .desc = "Output file (default stdout)", + .type = OPTION_ARG, + .opt.arg = &dsa_config.outfile, + }, + { + .name = "outform", + .argname = "format", + .desc = "Output format (DER, MSBLOB, PEM (default) or PVK)", + .type = OPTION_ARG_FORMAT, + .opt.value = &dsa_config.outformat, + }, + { + .name = "passin", + .argname = "source", + .desc = "Input file passphrase source", + .type = OPTION_ARG, + .opt.arg = &dsa_config.passargin, + }, + { + .name = "passout", + .argname = "source", + .desc = "Output file passphrase source", + .type = OPTION_ARG, + .opt.arg = &dsa_config.passargout, + }, + { + .name = "pubin", + .desc = "Read a public key from the input file instead of" + " private key", + .type = OPTION_FLAG, + .opt.flag = &dsa_config.pubin, + }, + { + .name = "pubout", + .desc = "Output a public key instead of private key", + .type = OPTION_FLAG, + .opt.flag = &dsa_config.pubout, + }, + { + .name = "pvk-none", + .desc = "PVK encryption level", + .type = OPTION_VALUE, + .value = 0, + .opt.value = &dsa_config.pvk_encr, + }, + { + .name = "pvk-strong", + .desc = "PVK encryption level (default)", + .type = OPTION_VALUE, + .value = 2, + .opt.value = &dsa_config.pvk_encr, + }, + { + .name = "pvk-weak", + .desc = "PVK encryption level", + .type = OPTION_VALUE, + .value = 1, + .opt.value = &dsa_config.pvk_encr, + }, + { + .name = "text", + .desc = "Print the key in text form", + .type = OPTION_FLAG, + .opt.flag = &dsa_config.text, + }, + { + .name = NULL, + .type = OPTION_ARGV_FUNC, + .opt.argvfunc = dsa_opt_enc, + }, + { NULL }, +}; + +static void +show_ciphers(const OBJ_NAME *name, void *arg) +{ + static int n; + + if (!islower((unsigned char)*name->name)) + return; + + fprintf(stderr, " -%-24s%s", name->name, (++n % 3 ? "" : "\n")); +} + +static void +dsa_usage(void) +{ + fprintf(stderr, + "usage: dsa [-in file] [-inform format] [-noout]\n" + " [-out file] [-outform format] [-passin src] [-passout src]\n" + " [-pubin] [-pubout] [-pvk-none | -pvk-strong | -pvk-weak]\n" + " [-text] [-ciphername]\n\n"); + options_usage(dsa_options); + fprintf(stderr, "\n"); + + fprintf(stderr, "Valid ciphername values:\n\n"); + OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, show_ciphers, NULL); + fprintf(stderr, "\n"); +} + +int +dsa_main(int argc, char **argv) +{ + int ret = 1; + DSA *dsa = NULL; + int i; + BIO *in = NULL, *out = NULL; + char *passin = NULL, *passout = NULL; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + memset(&dsa_config, 0, sizeof(dsa_config)); + + dsa_config.pvk_encr = 2; + dsa_config.informat = FORMAT_PEM; + dsa_config.outformat = FORMAT_PEM; + + if (options_parse(argc, argv, dsa_options, NULL, NULL) != 0) { + dsa_usage(); + goto end; + } + + if (!app_passwd(bio_err, dsa_config.passargin, dsa_config.passargout, + &passin, &passout)) { + BIO_printf(bio_err, "Error getting passwords\n"); + goto end; + } + + in = BIO_new(BIO_s_file()); + out = BIO_new(BIO_s_file()); + if (in == NULL || out == NULL) { + ERR_print_errors(bio_err); + goto end; + } + if (dsa_config.infile == NULL) + BIO_set_fp(in, stdin, BIO_NOCLOSE); + else { + if (BIO_read_filename(in, dsa_config.infile) <= 0) { + perror(dsa_config.infile); + goto end; + } + } + + BIO_printf(bio_err, "read DSA key\n"); + + { + EVP_PKEY *pkey; + + if (dsa_config.pubin) + pkey = load_pubkey(bio_err, dsa_config.infile, + dsa_config.informat, 1, passin, "Public Key"); + else + pkey = load_key(bio_err, dsa_config.infile, + dsa_config.informat, 1, passin, "Private Key"); + + if (pkey) { + dsa = EVP_PKEY_get1_DSA(pkey); + EVP_PKEY_free(pkey); + } + } + if (dsa == NULL) { + BIO_printf(bio_err, "unable to load Key\n"); + ERR_print_errors(bio_err); + goto end; + } + if (dsa_config.outfile == NULL) { + BIO_set_fp(out, stdout, BIO_NOCLOSE); + } else { + if (BIO_write_filename(out, dsa_config.outfile) <= 0) { + perror(dsa_config.outfile); + goto end; + } + } + + if (dsa_config.text) { + if (!DSA_print(out, dsa, 0)) { + perror(dsa_config.outfile); + ERR_print_errors(bio_err); + goto end; + } + } + if (dsa_config.modulus) { + fprintf(stdout, "Public Key="); + BN_print(out, dsa->pub_key); + fprintf(stdout, "\n"); + } + if (dsa_config.noout) + goto end; + BIO_printf(bio_err, "writing DSA key\n"); + if (dsa_config.outformat == FORMAT_ASN1) { + if (dsa_config.pubin || dsa_config.pubout) + i = i2d_DSA_PUBKEY_bio(out, dsa); + else + i = i2d_DSAPrivateKey_bio(out, dsa); + } else if (dsa_config.outformat == FORMAT_PEM) { + if (dsa_config.pubin || dsa_config.pubout) + i = PEM_write_bio_DSA_PUBKEY(out, dsa); + else + i = PEM_write_bio_DSAPrivateKey(out, dsa, dsa_config.enc, + NULL, 0, NULL, passout); +#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_RC4) + } else if (dsa_config.outformat == FORMAT_MSBLOB || + dsa_config.outformat == FORMAT_PVK) { + EVP_PKEY *pk; + pk = EVP_PKEY_new(); + EVP_PKEY_set1_DSA(pk, dsa); + if (dsa_config.outformat == FORMAT_PVK) + i = i2b_PVK_bio(out, pk, dsa_config.pvk_encr, 0, + passout); + else if (dsa_config.pubin || dsa_config.pubout) + i = i2b_PublicKey_bio(out, pk); + else + i = i2b_PrivateKey_bio(out, pk); + EVP_PKEY_free(pk); +#endif + } else { + BIO_printf(bio_err, "bad output format specified for outfile\n"); + goto end; + } + if (i <= 0) { + BIO_printf(bio_err, "unable to write private key\n"); + ERR_print_errors(bio_err); + } else + ret = 0; +end: + BIO_free(in); + if (out != NULL) + BIO_free_all(out); + if (dsa != NULL) + DSA_free(dsa); + free(passin); + free(passout); + + return (ret); +} diff --git a/bin/openssl/dsaparam.c b/bin/openssl/dsaparam.c new file mode 100644 index 0000000000..46efd5d453 --- /dev/null +++ b/bin/openssl/dsaparam.c @@ -0,0 +1,371 @@ +/* $OpenBSD: dsaparam.c,v 1.8 2017/01/20 08:57:12 deraadt Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include /* for OPENSSL_NO_DSA */ + +/* Until the key-gen callbacks are modified to use newer prototypes, we allow + * deprecated functions for openssl-internal code */ +#ifdef OPENSSL_NO_DEPRECATED +#undef OPENSSL_NO_DEPRECATED +#endif + +#include +#include +#include +#include +#include + +#include "apps.h" + +#include +#include +#include +#include +#include +#include + +static struct { + int C; + int genkey; + char *infile; + int informat; + int noout; + char *outfile; + int outformat; + int text; +} dsaparam_config; + +static struct option dsaparam_options[] = { + { + .name = "C", + .desc = "Convert DSA parameters into C code", + .type = OPTION_FLAG, + .opt.flag = &dsaparam_config.C, + }, + { + .name = "genkey", + .desc = "Generate a DSA key", + .type = OPTION_FLAG, + .opt.flag = &dsaparam_config.genkey, + }, + { + .name = "in", + .argname = "file", + .desc = "Input file (default stdin)", + .type = OPTION_ARG, + .opt.arg = &dsaparam_config.infile, + }, + { + .name = "inform", + .argname = "format", + .desc = "Input format (DER or PEM (default))", + .type = OPTION_ARG_FORMAT, + .opt.value = &dsaparam_config.informat, + }, + { + .name = "noout", + .desc = "No output", + .type = OPTION_FLAG, + .opt.flag = &dsaparam_config.noout, + }, + { + .name = "out", + .argname = "file", + .desc = "Output file (default stdout)", + .type = OPTION_ARG, + .opt.arg = &dsaparam_config.outfile, + }, + { + .name = "outform", + .argname = "format", + .desc = "Output format (DER or PEM (default))", + .type = OPTION_ARG_FORMAT, + .opt.value = &dsaparam_config.outformat, + }, + { + .name = "text", + .desc = "Print as text", + .type = OPTION_FLAG, + .opt.flag = &dsaparam_config.text, + }, + { NULL }, +}; + +static void +dsaparam_usage(void) +{ + fprintf(stderr, + "usage: dsaparam [-C] [-genkey] [-in file]\n" + " [-inform format] [-noout] [-out file] [-outform format]\n" + " [-text] [numbits]\n\n"); + options_usage(dsaparam_options); +} + +static int dsa_cb(int p, int n, BN_GENCB * cb); + +int +dsaparam_main(int argc, char **argv) +{ + DSA *dsa = NULL; + int i; + BIO *in = NULL, *out = NULL; + int ret = 1; + int numbits = -1; + char *strbits = NULL; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + memset(&dsaparam_config, 0, sizeof(dsaparam_config)); + + dsaparam_config.informat = FORMAT_PEM; + dsaparam_config.outformat = FORMAT_PEM; + + if (options_parse(argc, argv, dsaparam_options, &strbits, NULL) != 0) { + dsaparam_usage(); + goto end; + } + + if (strbits != NULL) { + const char *errstr; + numbits = strtonum(strbits, 0, INT_MAX, &errstr); + if (errstr) { + fprintf(stderr, "Invalid number of bits: %s", errstr); + goto end; + } + } + + in = BIO_new(BIO_s_file()); + out = BIO_new(BIO_s_file()); + if (in == NULL || out == NULL) { + ERR_print_errors(bio_err); + goto end; + } + if (dsaparam_config.infile == NULL) + BIO_set_fp(in, stdin, BIO_NOCLOSE); + else { + if (BIO_read_filename(in, dsaparam_config.infile) <= 0) { + perror(dsaparam_config.infile); + goto end; + } + } + if (dsaparam_config.outfile == NULL) { + BIO_set_fp(out, stdout, BIO_NOCLOSE); + } else { + if (BIO_write_filename(out, dsaparam_config.outfile) <= 0) { + perror(dsaparam_config.outfile); + goto end; + } + } + + if (numbits > 0) { + BN_GENCB cb; + BN_GENCB_set(&cb, dsa_cb, bio_err); + dsa = DSA_new(); + if (!dsa) { + BIO_printf(bio_err, "Error allocating DSA object\n"); + goto end; + } + BIO_printf(bio_err, "Generating DSA parameters, %d bit long prime\n", numbits); + BIO_printf(bio_err, "This could take some time\n"); + if (!DSA_generate_parameters_ex(dsa, numbits, NULL, 0, NULL, NULL, &cb)) { + ERR_print_errors(bio_err); + BIO_printf(bio_err, "Error, DSA key generation failed\n"); + goto end; + } + } else if (dsaparam_config.informat == FORMAT_ASN1) + dsa = d2i_DSAparams_bio(in, NULL); + else if (dsaparam_config.informat == FORMAT_PEM) + dsa = PEM_read_bio_DSAparams(in, NULL, NULL, NULL); + else { + BIO_printf(bio_err, "bad input format specified\n"); + goto end; + } + if (dsa == NULL) { + BIO_printf(bio_err, "unable to load DSA parameters\n"); + ERR_print_errors(bio_err); + goto end; + } + if (dsaparam_config.text) { + DSAparams_print(out, dsa); + } + if (dsaparam_config.C) { + unsigned char *data; + int l, len, bits_p; + + len = BN_num_bytes(dsa->p); + bits_p = BN_num_bits(dsa->p); + data = malloc(len + 20); + if (data == NULL) { + perror("malloc"); + goto end; + } + l = BN_bn2bin(dsa->p, data); + printf("static unsigned char dsa%d_p[] = {", bits_p); + for (i = 0; i < l; i++) { + if ((i % 12) == 0) + printf("\n\t"); + printf("0x%02X, ", data[i]); + } + printf("\n\t};\n"); + + l = BN_bn2bin(dsa->q, data); + printf("static unsigned char dsa%d_q[] = {", bits_p); + for (i = 0; i < l; i++) { + if ((i % 12) == 0) + printf("\n\t"); + printf("0x%02X, ", data[i]); + } + printf("\n\t};\n"); + + l = BN_bn2bin(dsa->g, data); + printf("static unsigned char dsa%d_g[] = {", bits_p); + for (i = 0; i < l; i++) { + if ((i % 12) == 0) + printf("\n\t"); + printf("0x%02X, ", data[i]); + } + free(data); + printf("\n\t};\n\n"); + + printf("DSA *get_dsa%d()\n\t{\n", bits_p); + printf("\tDSA *dsa;\n\n"); + printf("\tif ((dsa = DSA_new()) == NULL) return(NULL);\n"); + printf("\tdsa->p = BN_bin2bn(dsa%d_p, sizeof(dsa%d_p), NULL);\n", + bits_p, bits_p); + printf("\tdsa->q = BN_bin2bn(dsa%d_q, sizeof(dsa%d_q), NULL);\n", + bits_p, bits_p); + printf("\tdsa->g = BN_bin2bn(dsa%d_g, sizeof(dsa%d_g), NULL);\n", + bits_p, bits_p); + printf("\tif ((dsa->p == NULL) || (dsa->q == NULL) || (dsa->g == NULL))\n"); + printf("\t\t{ DSA_free(dsa); return(NULL); }\n"); + printf("\treturn(dsa);\n\t}\n"); + } + if (!dsaparam_config.noout) { + if (dsaparam_config.outformat == FORMAT_ASN1) + i = i2d_DSAparams_bio(out, dsa); + else if (dsaparam_config.outformat == FORMAT_PEM) + i = PEM_write_bio_DSAparams(out, dsa); + else { + BIO_printf(bio_err, "bad output format specified for outfile\n"); + goto end; + } + if (!i) { + BIO_printf(bio_err, "unable to write DSA parameters\n"); + ERR_print_errors(bio_err); + goto end; + } + } + if (dsaparam_config.genkey) { + DSA *dsakey; + + if ((dsakey = DSAparams_dup(dsa)) == NULL) + goto end; + if (!DSA_generate_key(dsakey)) { + ERR_print_errors(bio_err); + DSA_free(dsakey); + goto end; + } + if (dsaparam_config.outformat == FORMAT_ASN1) + i = i2d_DSAPrivateKey_bio(out, dsakey); + else if (dsaparam_config.outformat == FORMAT_PEM) + i = PEM_write_bio_DSAPrivateKey(out, dsakey, NULL, NULL, 0, NULL, NULL); + else { + BIO_printf(bio_err, "bad output format specified for outfile\n"); + DSA_free(dsakey); + goto end; + } + DSA_free(dsakey); + } + ret = 0; + +end: + BIO_free(in); + if (out != NULL) + BIO_free_all(out); + if (dsa != NULL) + DSA_free(dsa); + + return (ret); +} + +static int +dsa_cb(int p, int n, BN_GENCB * cb) +{ + char c = '*'; + + if (p == 0) + c = '.'; + if (p == 1) + c = '+'; + if (p == 2) + c = '*'; + if (p == 3) + c = '\n'; + BIO_write(cb->arg, &c, 1); + (void) BIO_flush(cb->arg); +#ifdef GENCB_TEST + if (stop_keygen_flag) + return 0; +#endif + return 1; +} diff --git a/bin/openssl/ec.c b/bin/openssl/ec.c new file mode 100644 index 0000000000..e557990cb9 --- /dev/null +++ b/bin/openssl/ec.c @@ -0,0 +1,406 @@ +/* $OpenBSD: ec.c,v 1.9 2017/01/20 08:57:12 deraadt Exp $ */ +/* + * Written by Nils Larsch for the OpenSSL project. + */ +/* ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include + +#ifndef OPENSSL_NO_EC + +#include +#include +#include +#include + +#include "apps.h" + +#include +#include +#include +#include + +static struct { + int asn1_flag; + const EVP_CIPHER *enc; + point_conversion_form_t form; + char *infile; + int informat; + char *outfile; + int outformat; + int new_asn1_flag; + int new_form; + int noout; + int param_out; + char *passargin; + char *passargout; + int pubin; + int pubout; + int text; +} ec_config; + +static int +ec_opt_enc(int argc, char **argv, int *argsused) +{ + char *name = argv[0]; + + if (*name++ != '-') + return (1); + + if ((ec_config.enc = EVP_get_cipherbyname(name)) != NULL) { + *argsused = 1; + return (0); + } + + return (1); +} + +static int +ec_opt_form(char *arg) +{ + if (strcmp(arg, "compressed") == 0) + ec_config.form = POINT_CONVERSION_COMPRESSED; + else if (strcmp(arg, "uncompressed") == 0) + ec_config.form = POINT_CONVERSION_UNCOMPRESSED; + else if (strcmp(arg, "hybrid") == 0) + ec_config.form = POINT_CONVERSION_HYBRID; + else { + fprintf(stderr, "Invalid point conversion: %s\n", arg); + return (1); + } + + ec_config.new_form = 1; + return (0); +} + +static int +ec_opt_named(char *arg) +{ + if (strcmp(arg, "named_curve") == 0) + ec_config.asn1_flag = OPENSSL_EC_NAMED_CURVE; + else if (strcmp(arg, "explicit") == 0) + ec_config.asn1_flag = 0; + else { + fprintf(stderr, "Invalid curve type: %s\n", arg); + return (1); + } + + ec_config.new_asn1_flag = 1; + return (0); +} + +static struct option ec_options[] = { + { + .name = "conv_form", + .argname = "form", + .desc = "Specify the point conversion form (default" + " \"named_curve\")", + .type = OPTION_ARG_FUNC, + .opt.argfunc = ec_opt_form, + }, + { + .name = "in", + .argname = "file", + .desc = "Input file (default stdin)", + .type = OPTION_ARG, + .opt.arg = &ec_config.infile, + }, + { + .name = "inform", + .argname = "format", + .desc = "Input format (DER or PEM (default))", + .type = OPTION_ARG_FORMAT, + .opt.value = &ec_config.informat, + }, + { + .name = "noout", + .desc = "No output", + .type = OPTION_FLAG, + .opt.flag = &ec_config.noout, + }, + { + .name = "out", + .argname = "file", + .desc = "Output file (default stdout)", + .type = OPTION_ARG, + .opt.arg = &ec_config.outfile, + }, + { + .name = "outform", + .argname = "format", + .desc = "Output format (DER or PEM (default))", + .type = OPTION_ARG_FORMAT, + .opt.value = &ec_config.outformat, + }, + { + .name = "param_enc", + .argname = "type", + .desc = "Specify the way the ec parameters are encoded" + " (default \"uncompressed\")", + .type = OPTION_ARG_FUNC, + .opt.argfunc = ec_opt_named, + }, + { + .name = "param_out", + .desc = "Print the elliptic curve parameters", + .type = OPTION_FLAG, + .opt.flag = &ec_config.param_out, + }, + { + .name = "passin", + .argname = "source", + .desc = "Input file passphrase source", + .type = OPTION_ARG, + .opt.arg = &ec_config.passargin, + }, + { + .name = "passout", + .argname = "source", + .desc = "Output file passphrase source", + .type = OPTION_ARG, + .opt.arg = &ec_config.passargout, + }, + { + .name = "pubin", + .desc = "Read public key instead of private key from input", + .type = OPTION_FLAG, + .opt.flag = &ec_config.pubin, + }, + { + .name = "pubout", + .desc = "Output public key instead of private key in output", + .type = OPTION_FLAG, + .opt.flag = &ec_config.pubout, + }, + { + .name = "text", + .desc = "Print the public/private key components and parameters", + .type = OPTION_FLAG, + .opt.flag = &ec_config.text, + }, + { + .name = NULL, + .desc = "Cipher to encrypt the output if using PEM format", + .type = OPTION_ARGV_FUNC, + .opt.argvfunc = ec_opt_enc, + }, + { NULL }, +}; + +static void +show_ciphers(const OBJ_NAME *name, void *arg) +{ + static int n; + + if (!islower((unsigned char)*name->name)) + return; + + fprintf(stderr, " -%-24s%s", name->name, (++n % 3 ? "" : "\n")); +} + +static void +ec_usage(void) +{ + fprintf(stderr, + "usage: ec [-conv_form form] [-in file]\n" + " [-inform format] [-noout] [-out file] [-outform format]\n" + " [-param_enc type] [-param_out] [-passin file]\n" + " [-passout file] [-pubin] [-pubout] [-text] [-ciphername]\n\n"); + options_usage(ec_options); + + fprintf(stderr, "\n"); + + fprintf(stderr, "Valid ciphername values:\n\n"); + OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, show_ciphers, NULL); + fprintf(stderr, "\n"); +} + +int +ec_main(int argc, char **argv) +{ + int ret = 1; + EC_KEY *eckey = NULL; + const EC_GROUP *group; + int i; + BIO *in = NULL, *out = NULL; + char *passin = NULL, *passout = NULL; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + memset(&ec_config, 0, sizeof(ec_config)); + + ec_config.asn1_flag = OPENSSL_EC_NAMED_CURVE; + ec_config.form = POINT_CONVERSION_UNCOMPRESSED; + ec_config.informat = FORMAT_PEM; + ec_config.outformat = FORMAT_PEM; + + if (options_parse(argc, argv, ec_options, NULL, NULL) != 0) { + ec_usage(); + goto end; + } + + if (!app_passwd(bio_err, ec_config.passargin, ec_config.passargout, + &passin, &passout)) { + BIO_printf(bio_err, "Error getting passwords\n"); + goto end; + } + in = BIO_new(BIO_s_file()); + out = BIO_new(BIO_s_file()); + if (in == NULL || out == NULL) { + ERR_print_errors(bio_err); + goto end; + } + if (ec_config.infile == NULL) + BIO_set_fp(in, stdin, BIO_NOCLOSE); + else { + if (BIO_read_filename(in, ec_config.infile) <= 0) { + perror(ec_config.infile); + goto end; + } + } + + BIO_printf(bio_err, "read EC key\n"); + if (ec_config.informat == FORMAT_ASN1) { + if (ec_config.pubin) + eckey = d2i_EC_PUBKEY_bio(in, NULL); + else + eckey = d2i_ECPrivateKey_bio(in, NULL); + } else if (ec_config.informat == FORMAT_PEM) { + if (ec_config.pubin) + eckey = PEM_read_bio_EC_PUBKEY(in, NULL, NULL, + NULL); + else + eckey = PEM_read_bio_ECPrivateKey(in, NULL, NULL, + passin); + } else { + BIO_printf(bio_err, "bad input format specified for key\n"); + goto end; + } + if (eckey == NULL) { + BIO_printf(bio_err, "unable to load Key\n"); + ERR_print_errors(bio_err); + goto end; + } + if (ec_config.outfile == NULL) { + BIO_set_fp(out, stdout, BIO_NOCLOSE); + } else { + if (BIO_write_filename(out, ec_config.outfile) <= 0) { + perror(ec_config.outfile); + goto end; + } + } + + group = EC_KEY_get0_group(eckey); + + if (ec_config.new_form) + EC_KEY_set_conv_form(eckey, ec_config.form); + + if (ec_config.new_asn1_flag) + EC_KEY_set_asn1_flag(eckey, ec_config.asn1_flag); + + if (ec_config.text) + if (!EC_KEY_print(out, eckey, 0)) { + perror(ec_config.outfile); + ERR_print_errors(bio_err); + goto end; + } + if (ec_config.noout) { + ret = 0; + goto end; + } + BIO_printf(bio_err, "writing EC key\n"); + if (ec_config.outformat == FORMAT_ASN1) { + if (ec_config.param_out) + i = i2d_ECPKParameters_bio(out, group); + else if (ec_config.pubin || ec_config.pubout) + i = i2d_EC_PUBKEY_bio(out, eckey); + else + i = i2d_ECPrivateKey_bio(out, eckey); + } else if (ec_config.outformat == FORMAT_PEM) { + if (ec_config.param_out) + i = PEM_write_bio_ECPKParameters(out, group); + else if (ec_config.pubin || ec_config.pubout) + i = PEM_write_bio_EC_PUBKEY(out, eckey); + else + i = PEM_write_bio_ECPrivateKey(out, eckey, + ec_config.enc, NULL, 0, NULL, passout); + } else { + BIO_printf(bio_err, "bad output format specified for " + "outfile\n"); + goto end; + } + + if (!i) { + BIO_printf(bio_err, "unable to write private key\n"); + ERR_print_errors(bio_err); + } else + ret = 0; +end: + BIO_free(in); + if (out) + BIO_free_all(out); + if (eckey) + EC_KEY_free(eckey); + free(passin); + free(passout); + + return (ret); +} +#endif diff --git a/bin/openssl/ecparam.c b/bin/openssl/ecparam.c new file mode 100644 index 0000000000..6c497bd355 --- /dev/null +++ b/bin/openssl/ecparam.c @@ -0,0 +1,615 @@ +/* $OpenBSD: ecparam.c,v 1.16 2017/01/20 08:57:12 deraadt Exp $ */ +/* + * Written by Nils Larsch for the OpenSSL project. + */ +/* ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems Laboratories. + * + */ + +#include + +#ifndef OPENSSL_NO_EC + +#include +#include +#include +#include + +#include "apps.h" + +#include +#include +#include +#include +#include +#include + +static int ecparam_print_var(BIO *, BIGNUM *, const char *, int, + unsigned char *); + +static struct { + int C; + int asn1_flag; + int check; + char *curve_name; + point_conversion_form_t form; + int genkey; + char *infile; + int informat; + int list_curves; + int new_asn1_flag; + int new_form; + int no_seed; + int noout; + char *outfile; + int outformat; + int text; +} ecparam_config; + +static int +ecparam_opt_form(char *arg) +{ + if (strcmp(arg, "compressed") == 0) + ecparam_config.form = POINT_CONVERSION_COMPRESSED; + else if (strcmp(arg, "uncompressed") == 0) + ecparam_config.form = POINT_CONVERSION_UNCOMPRESSED; + else if (strcmp(arg, "hybrid") == 0) + ecparam_config.form = POINT_CONVERSION_HYBRID; + else + return (1); + + ecparam_config.new_form = 1; + return (0); +} + +static int +ecparam_opt_enctype(char *arg) +{ + if (strcmp(arg, "explicit") == 0) + ecparam_config.asn1_flag = 0; + else if (strcmp(arg, "named_curve") == 0) + ecparam_config.asn1_flag = OPENSSL_EC_NAMED_CURVE; + else + return (1); + + ecparam_config.new_asn1_flag = 1; + return (0); +} + +struct option ecparam_options[] = { + { + .name = "C", + .desc = "Convert the EC parameters into C code", + .type = OPTION_FLAG, + .opt.flag = &ecparam_config.C, + }, + { + .name = "check", + .desc = "Validate the elliptic curve parameters", + .type = OPTION_FLAG, + .opt.flag = &ecparam_config.check, + }, + { + .name = "conv_form", + .argname = "form", + .desc = "Specify point conversion form:\n" + " compressed, uncompressed (default), hybrid", + .type = OPTION_ARG_FUNC, + .opt.argfunc = ecparam_opt_form, + }, + { + .name = "genkey", + .desc = "Generate an EC private key using the specified " + "parameters", + .type = OPTION_FLAG, + .opt.flag = &ecparam_config.genkey, + }, + { + .name = "in", + .argname = "file", + .desc = "Input file to read parameters from (default stdin)", + .type = OPTION_ARG, + .opt.arg = &ecparam_config.infile, + }, + { + .name = "inform", + .argname = "format", + .desc = "Input format (DER or PEM)", + .type = OPTION_ARG_FORMAT, + .opt.value = &ecparam_config.informat, + }, + { + .name = "list_curves", + .desc = "Print list of all currently implemented EC " + "parameter names", + .type = OPTION_FLAG, + .opt.flag = &ecparam_config.list_curves, + }, + { + .name = "name", + .argname = "curve", + .desc = "Use the EC parameters with the specified name", + .type = OPTION_ARG, + .opt.arg = &ecparam_config.curve_name, + }, + { + .name = "no_seed", + .desc = "Do not output seed with explicit parameter encoding", + .type = OPTION_FLAG, + .opt.flag = &ecparam_config.no_seed, + }, + { + .name = "noout", + .desc = "Do not output encoded version of EC parameters", + .type = OPTION_FLAG, + .opt.flag = &ecparam_config.noout, + }, + { + .name = "out", + .argname = "file", + .desc = "Output file to write parameters to (default stdout)", + .type = OPTION_ARG, + .opt.arg = &ecparam_config.outfile, + }, + { + .name = "outform", + .argname = "format", + .desc = "Output format (DER or PEM)", + .type = OPTION_ARG_FORMAT, + .opt.value = &ecparam_config.outformat, + }, + { + .name = "param_enc", + .argname = "type", + .desc = "Specify EC parameter ASN.1 encoding type:\n" + " explicit, named_curve (default)", + .type = OPTION_ARG_FUNC, + .opt.argfunc = ecparam_opt_enctype, + }, + { + .name = "text", + .desc = "Print out the EC parameters in human readable form", + .type = OPTION_FLAG, + .opt.flag = &ecparam_config.text, + }, + {NULL}, +}; + +static void +ecparam_usage(void) +{ + fprintf(stderr, "usage: ecparam [-C] [-check] [-conv_form arg] " + " [-genkey]\n" + " [-in file] [-inform DER | PEM] [-list_curves] [-name arg]\n" + " [-no_seed] [-noout] [-out file] [-outform DER | PEM]\n" + " [-param_enc arg] [-text]\n\n"); + options_usage(ecparam_options); +} + +int +ecparam_main(int argc, char **argv) +{ + BIGNUM *ec_p = NULL, *ec_a = NULL, *ec_b = NULL, *ec_gen = NULL; + BIGNUM *ec_order = NULL, *ec_cofactor = NULL; + EC_GROUP *group = NULL; + unsigned char *buffer = NULL; + BIO *in = NULL, *out = NULL; + int i, ret = 1; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + memset(&ecparam_config, 0, sizeof(ecparam_config)); + ecparam_config.asn1_flag = OPENSSL_EC_NAMED_CURVE; + ecparam_config.form = POINT_CONVERSION_UNCOMPRESSED; + ecparam_config.informat = FORMAT_PEM; + ecparam_config.outformat = FORMAT_PEM; + + if (options_parse(argc, argv, ecparam_options, NULL, NULL) != 0) { + ecparam_usage(); + goto end; + } + + in = BIO_new(BIO_s_file()); + out = BIO_new(BIO_s_file()); + if ((in == NULL) || (out == NULL)) { + ERR_print_errors(bio_err); + goto end; + } + if (ecparam_config.infile == NULL) + BIO_set_fp(in, stdin, BIO_NOCLOSE); + else { + if (BIO_read_filename(in, ecparam_config.infile) <= 0) { + perror(ecparam_config.infile); + goto end; + } + } + if (ecparam_config.outfile == NULL) { + BIO_set_fp(out, stdout, BIO_NOCLOSE); + } else { + if (BIO_write_filename(out, ecparam_config.outfile) <= 0) { + perror(ecparam_config.outfile); + goto end; + } + } + + if (ecparam_config.list_curves) { + EC_builtin_curve *curves = NULL; + size_t crv_len = 0; + size_t n = 0; + + crv_len = EC_get_builtin_curves(NULL, 0); + + curves = reallocarray(NULL, crv_len, sizeof(EC_builtin_curve)); + if (curves == NULL) + goto end; + + if (!EC_get_builtin_curves(curves, crv_len)) { + free(curves); + goto end; + } + for (n = 0; n < crv_len; n++) { + const char *comment; + const char *sname; + comment = curves[n].comment; + sname = OBJ_nid2sn(curves[n].nid); + if (comment == NULL) + comment = "CURVE DESCRIPTION NOT AVAILABLE"; + if (sname == NULL) + sname = ""; + + BIO_printf(out, " %-10s: ", sname); + BIO_printf(out, "%s\n", comment); + } + + free(curves); + ret = 0; + goto end; + } + if (ecparam_config.curve_name != NULL) { + int nid; + + /* + * workaround for the SECG curve names secp192r1 and + * secp256r1 (which are the same as the curves prime192v1 and + * prime256v1 defined in X9.62) + */ + if (!strcmp(ecparam_config.curve_name, "secp192r1")) { + BIO_printf(bio_err, "using curve name prime192v1 " + "instead of secp192r1\n"); + nid = NID_X9_62_prime192v1; + } else if (!strcmp(ecparam_config.curve_name, "secp256r1")) { + BIO_printf(bio_err, "using curve name prime256v1 " + "instead of secp256r1\n"); + nid = NID_X9_62_prime256v1; + } else + nid = OBJ_sn2nid(ecparam_config.curve_name); + + if (nid == 0) + nid = EC_curve_nist2nid(ecparam_config.curve_name); + + if (nid == 0) { + BIO_printf(bio_err, "unknown curve name (%s)\n", + ecparam_config.curve_name); + goto end; + } + group = EC_GROUP_new_by_curve_name(nid); + if (group == NULL) { + BIO_printf(bio_err, "unable to create curve (%s)\n", + ecparam_config.curve_name); + goto end; + } + EC_GROUP_set_asn1_flag(group, ecparam_config.asn1_flag); + EC_GROUP_set_point_conversion_form(group, ecparam_config.form); + } else if (ecparam_config.informat == FORMAT_ASN1) { + group = d2i_ECPKParameters_bio(in, NULL); + } else if (ecparam_config.informat == FORMAT_PEM) { + group = PEM_read_bio_ECPKParameters(in, NULL, NULL, NULL); + } else { + BIO_printf(bio_err, "bad input format specified\n"); + goto end; + } + + if (group == NULL) { + BIO_printf(bio_err, + "unable to load elliptic curve parameters\n"); + ERR_print_errors(bio_err); + goto end; + } + if (ecparam_config.new_form) + EC_GROUP_set_point_conversion_form(group, ecparam_config.form); + + if (ecparam_config.new_asn1_flag) + EC_GROUP_set_asn1_flag(group, ecparam_config.asn1_flag); + + if (ecparam_config.no_seed) + EC_GROUP_set_seed(group, NULL, 0); + + if (ecparam_config.text) { + if (!ECPKParameters_print(out, group, 0)) + goto end; + } + if (ecparam_config.check) { + BIO_printf(bio_err, "checking elliptic curve parameters: "); + if (!EC_GROUP_check(group, NULL)) { + BIO_printf(bio_err, "failed\n"); + ERR_print_errors(bio_err); + } else + BIO_printf(bio_err, "ok\n"); + + } + if (ecparam_config.C) { + size_t buf_len = 0, tmp_len = 0; + const EC_POINT *point; + int is_prime, len = 0; + const EC_METHOD *meth = EC_GROUP_method_of(group); + + if ((ec_p = BN_new()) == NULL || (ec_a = BN_new()) == NULL || + (ec_b = BN_new()) == NULL || (ec_gen = BN_new()) == NULL || + (ec_order = BN_new()) == NULL || + (ec_cofactor = BN_new()) == NULL) { + perror("malloc"); + goto end; + } + is_prime = (EC_METHOD_get_field_type(meth) == + NID_X9_62_prime_field); + + if (is_prime) { + if (!EC_GROUP_get_curve_GFp(group, ec_p, ec_a, + ec_b, NULL)) + goto end; + } else { + if (!EC_GROUP_get_curve_GF2m(group, ec_p, ec_a, + ec_b, NULL)) + goto end; + } + + if ((point = EC_GROUP_get0_generator(group)) == NULL) + goto end; + if (!EC_POINT_point2bn(group, point, + EC_GROUP_get_point_conversion_form(group), ec_gen, + NULL)) + goto end; + if (!EC_GROUP_get_order(group, ec_order, NULL)) + goto end; + if (!EC_GROUP_get_cofactor(group, ec_cofactor, NULL)) + goto end; + + len = BN_num_bits(ec_order); + + if ((tmp_len = (size_t) BN_num_bytes(ec_p)) > buf_len) + buf_len = tmp_len; + if ((tmp_len = (size_t) BN_num_bytes(ec_a)) > buf_len) + buf_len = tmp_len; + if ((tmp_len = (size_t) BN_num_bytes(ec_b)) > buf_len) + buf_len = tmp_len; + if ((tmp_len = (size_t) BN_num_bytes(ec_gen)) > buf_len) + buf_len = tmp_len; + if ((tmp_len = (size_t) BN_num_bytes(ec_order)) > buf_len) + buf_len = tmp_len; + if ((tmp_len = (size_t) BN_num_bytes(ec_cofactor)) > buf_len) + buf_len = tmp_len; + + buffer = malloc(buf_len); + + if (buffer == NULL) { + perror("malloc"); + goto end; + } + ecparam_print_var(out, ec_p, "ec_p", len, buffer); + ecparam_print_var(out, ec_a, "ec_a", len, buffer); + ecparam_print_var(out, ec_b, "ec_b", len, buffer); + ecparam_print_var(out, ec_gen, "ec_gen", len, buffer); + ecparam_print_var(out, ec_order, "ec_order", len, buffer); + ecparam_print_var(out, ec_cofactor, "ec_cofactor", len, + buffer); + + BIO_printf(out, "\n\n"); + + BIO_printf(out, "EC_GROUP *get_ec_group_%d(void)\n\t{\n", len); + BIO_printf(out, "\tint ok=0;\n"); + BIO_printf(out, "\tEC_GROUP *group = NULL;\n"); + BIO_printf(out, "\tEC_POINT *point = NULL;\n"); + BIO_printf(out, "\tBIGNUM *tmp_1 = NULL, *tmp_2 = NULL, " + "*tmp_3 = NULL;\n\n"); + BIO_printf(out, "\tif ((tmp_1 = BN_bin2bn(ec_p_%d, " + "sizeof(ec_p_%d), NULL)) == NULL)\n\t\t" + "goto err;\n", len, len); + BIO_printf(out, "\tif ((tmp_2 = BN_bin2bn(ec_a_%d, " + "sizeof(ec_a_%d), NULL)) == NULL)\n\t\t" + "goto err;\n", len, len); + BIO_printf(out, "\tif ((tmp_3 = BN_bin2bn(ec_b_%d, " + "sizeof(ec_b_%d), NULL)) == NULL)\n\t\t" + "goto err;\n", len, len); + if (is_prime) { + BIO_printf(out, "\tif ((group = EC_GROUP_new_curve_" + "GFp(tmp_1, tmp_2, tmp_3, NULL)) == NULL)" + "\n\t\tgoto err;\n\n"); + } else { + BIO_printf(out, "\tif ((group = EC_GROUP_new_curve_" + "GF2m(tmp_1, tmp_2, tmp_3, NULL)) == NULL)" + "\n\t\tgoto err;\n\n"); + } + BIO_printf(out, "\t/* build generator */\n"); + BIO_printf(out, "\tif ((tmp_1 = BN_bin2bn(ec_gen_%d, " + "sizeof(ec_gen_%d), tmp_1)) == NULL)" + "\n\t\tgoto err;\n", len, len); + BIO_printf(out, "\tpoint = EC_POINT_bn2point(group, tmp_1, " + "NULL, NULL);\n"); + BIO_printf(out, "\tif (point == NULL)\n\t\tgoto err;\n"); + BIO_printf(out, "\tif ((tmp_2 = BN_bin2bn(ec_order_%d, " + "sizeof(ec_order_%d), tmp_2)) == NULL)" + "\n\t\tgoto err;\n", len, len); + BIO_printf(out, "\tif ((tmp_3 = BN_bin2bn(ec_cofactor_%d, " + "sizeof(ec_cofactor_%d), tmp_3)) == NULL)" + "\n\t\tgoto err;\n", len, len); + BIO_printf(out, "\tif (!EC_GROUP_set_generator(group, point," + " tmp_2, tmp_3))\n\t\tgoto err;\n"); + BIO_printf(out, "\n\tok=1;\n"); + BIO_printf(out, "err:\n"); + BIO_printf(out, "\tif (tmp_1)\n\t\tBN_free(tmp_1);\n"); + BIO_printf(out, "\tif (tmp_2)\n\t\tBN_free(tmp_2);\n"); + BIO_printf(out, "\tif (tmp_3)\n\t\tBN_free(tmp_3);\n"); + BIO_printf(out, "\tif (point)\n\t\tEC_POINT_free(point);\n"); + BIO_printf(out, "\tif (!ok)\n"); + BIO_printf(out, "\t\t{\n"); + BIO_printf(out, "\t\tEC_GROUP_free(group);\n"); + BIO_printf(out, "\t\tgroup = NULL;\n"); + BIO_printf(out, "\t\t}\n"); + BIO_printf(out, "\treturn(group);\n\t}\n"); + } + if (!ecparam_config.noout) { + if (ecparam_config.outformat == FORMAT_ASN1) + i = i2d_ECPKParameters_bio(out, group); + else if (ecparam_config.outformat == FORMAT_PEM) + i = PEM_write_bio_ECPKParameters(out, group); + else { + BIO_printf(bio_err, "bad output format specified for" + " outfile\n"); + goto end; + } + if (!i) { + BIO_printf(bio_err, "unable to write elliptic " + "curve parameters\n"); + ERR_print_errors(bio_err); + goto end; + } + } + if (ecparam_config.genkey) { + EC_KEY *eckey = EC_KEY_new(); + + if (eckey == NULL) + goto end; + + if (EC_KEY_set_group(eckey, group) == 0) { + EC_KEY_free(eckey); + goto end; + } + + if (!EC_KEY_generate_key(eckey)) { + EC_KEY_free(eckey); + goto end; + } + if (ecparam_config.outformat == FORMAT_ASN1) + i = i2d_ECPrivateKey_bio(out, eckey); + else if (ecparam_config.outformat == FORMAT_PEM) + i = PEM_write_bio_ECPrivateKey(out, eckey, NULL, + NULL, 0, NULL, NULL); + else { + BIO_printf(bio_err, "bad output format specified " + "for outfile\n"); + EC_KEY_free(eckey); + goto end; + } + EC_KEY_free(eckey); + } + ret = 0; + +end: + BN_free(ec_p); + BN_free(ec_a); + BN_free(ec_b); + BN_free(ec_gen); + BN_free(ec_order); + BN_free(ec_cofactor); + + free(buffer); + + BIO_free(in); + BIO_free_all(out); + EC_GROUP_free(group); + + return (ret); +} + +static int +ecparam_print_var(BIO * out, BIGNUM * in, const char *var, + int len, unsigned char *buffer) +{ + BIO_printf(out, "static unsigned char %s_%d[] = {", var, len); + if (BN_is_zero(in)) + BIO_printf(out, "\n\t0x00"); + else { + int i, l; + + l = BN_bn2bin(in, buffer); + for (i = 0; i < l - 1; i++) { + if ((i % 12) == 0) + BIO_printf(out, "\n\t"); + BIO_printf(out, "0x%02X,", buffer[i]); + } + if ((i % 12) == 0) + BIO_printf(out, "\n\t"); + BIO_printf(out, "0x%02X", buffer[i]); + } + BIO_printf(out, "\n\t};\n\n"); + return 1; +} +#endif diff --git a/bin/openssl/enc.c b/bin/openssl/enc.c new file mode 100644 index 0000000000..195dc2fc44 --- /dev/null +++ b/bin/openssl/enc.c @@ -0,0 +1,770 @@ +/* $OpenBSD: enc.c,v 1.12 2017/01/20 08:57:12 deraadt Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include +#include +#include +#include + +#include "apps.h" + +#include +#include +#include +#include +#include +#include +#include + +int set_hex(char *in, unsigned char *out, int size); + +#define SIZE (512) +#define BSIZE (8*1024) + +static struct { + int base64; + char *bufsize; + const EVP_CIPHER *cipher; + int debug; +#ifdef ZLIB + int do_zlib; +#endif + int enc; + char *hiv; + char *hkey; + char *hsalt; + char *inf; + char *keyfile; + char *keystr; + char *md; + int nopad; + int nosalt; + int olb64; + char *outf; + char *passarg; + int printkey; + int verbose; +} enc_config; + +static int +enc_opt_cipher(int argc, char **argv, int *argsused) +{ + char *name = argv[0]; + + if (*name++ != '-') + return (1); + + if (strcmp(name, "none") == 0) { + enc_config.cipher = NULL; + *argsused = 1; + return (0); + } + + if ((enc_config.cipher = EVP_get_cipherbyname(name)) != NULL) { + *argsused = 1; + return (0); + } + + return (1); +} + +static struct option enc_options[] = { + { + .name = "A", + .desc = "Process base64 data on one line (requires -a)", + .type = OPTION_FLAG, + .opt.flag = &enc_config.olb64, + }, + { + .name = "a", + .desc = "Perform base64 encoding/decoding (alias -base64)", + .type = OPTION_FLAG, + .opt.flag = &enc_config.base64, + }, + { + .name = "base64", + .type = OPTION_FLAG, + .opt.flag = &enc_config.base64, + }, + { + .name = "bufsize", + .argname = "size", + .desc = "Specify the buffer size to use for I/O", + .type = OPTION_ARG, + .opt.arg = &enc_config.bufsize, + }, + { + .name = "d", + .desc = "Decrypt the input data", + .type = OPTION_VALUE, + .opt.value = &enc_config.enc, + .value = 0, + }, + { + .name = "debug", + .desc = "Print debugging information", + .type = OPTION_FLAG, + .opt.flag = &enc_config.debug, + }, + { + .name = "e", + .desc = "Encrypt the input data (default)", + .type = OPTION_VALUE, + .opt.value = &enc_config.enc, + .value = 1, + }, + { + .name = "in", + .argname = "file", + .desc = "Input file to read from (default stdin)", + .type = OPTION_ARG, + .opt.arg = &enc_config.inf, + }, + { + .name = "iv", + .argname = "IV", + .desc = "IV to use, specified as a hexadecimal string", + .type = OPTION_ARG, + .opt.arg = &enc_config.hiv, + }, + { + .name = "K", + .argname = "key", + .desc = "Key to use, specified as a hexadecimal string", + .type = OPTION_ARG, + .opt.arg = &enc_config.hkey, + }, + { + .name = "k", /* Superseded by -pass. */ + .type = OPTION_ARG, + .opt.arg = &enc_config.keystr, + }, + { + .name = "kfile", /* Superseded by -pass. */ + .type = OPTION_ARG, + .opt.arg = &enc_config.keyfile, + }, + { + .name = "md", + .argname = "digest", + .desc = "Digest to use to create a key from the passphrase", + .type = OPTION_ARG, + .opt.arg = &enc_config.md, + }, + { + .name = "none", + .desc = "Use NULL cipher (no encryption or decryption)", + .type = OPTION_ARGV_FUNC, + .opt.argvfunc = enc_opt_cipher, + }, + { + .name = "nopad", + .desc = "Disable standard block padding", + .type = OPTION_FLAG, + .opt.flag = &enc_config.nopad, + }, + { + .name = "nosalt", + .type = OPTION_VALUE, + .opt.value = &enc_config.nosalt, + .value = 1, + }, + { + .name = "out", + .argname = "file", + .desc = "Output file to write to (default stdout)", + .type = OPTION_ARG, + .opt.arg = &enc_config.outf, + }, + { + .name = "P", + .desc = "Print out the salt, key and IV used, then exit\n" + " (no encryption or decryption is performed)", + .type = OPTION_VALUE, + .opt.value = &enc_config.printkey, + .value = 2, + }, + { + .name = "p", + .desc = "Print out the salt, key and IV used", + .type = OPTION_VALUE, + .opt.value = &enc_config.printkey, + .value = 1, + }, + { + .name = "pass", + .argname = "source", + .desc = "Password source", + .type = OPTION_ARG, + .opt.arg = &enc_config.passarg, + }, + { + .name = "S", + .argname = "salt", + .desc = "Salt to use, specified as a hexadecimal string", + .type = OPTION_ARG, + .opt.arg = &enc_config.hsalt, + }, + { + .name = "salt", + .desc = "Use a salt in the key derivation routines (default)", + .type = OPTION_VALUE, + .opt.value = &enc_config.nosalt, + .value = 0, + }, + { + .name = "v", + .desc = "Verbose", + .type = OPTION_FLAG, + .opt.flag = &enc_config.verbose, + }, +#ifdef ZLIB + { + .name = "z", + .desc = "Perform zlib compression/decompression", + .type = OPTION_FLAG, + .opt.flag = &enc_config.do_zlib, + }, +#endif + { + .name = NULL, + .type = OPTION_ARGV_FUNC, + .opt.argvfunc = enc_opt_cipher, + }, + { NULL }, +}; + +static void +show_ciphers(const OBJ_NAME *name, void *arg) +{ + static int n; + + if (!islower((unsigned char)*name->name)) + return; + + fprintf(stderr, " -%-24s%s", name->name, (++n % 3 ? "" : "\n")); +} + +static void +enc_usage(void) +{ + fprintf(stderr, "usage: enc -ciphername [-AadePp] [-base64] " + "[-bufsize number] [-debug]\n" + " [-in file] [-iv IV] [-K key] [-k password]\n" + " [-kfile file] [-md digest] [-none] [-nopad] [-nosalt]\n" + " [-out file] [-pass arg] [-S salt] [-salt]\n\n"); + options_usage(enc_options); + fprintf(stderr, "\n"); + + fprintf(stderr, "Valid ciphername values:\n\n"); + OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, show_ciphers, NULL); + fprintf(stderr, "\n"); +} + +int +enc_main(int argc, char **argv) +{ + static const char magic[] = "Salted__"; + char mbuf[sizeof magic - 1]; + char *strbuf = NULL, *pass = NULL; + unsigned char *buff = NULL; + int bsize = BSIZE; + int ret = 1, inl; + unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH]; + unsigned char salt[PKCS5_SALT_LEN]; +#ifdef ZLIB + BIO *bzl = NULL; +#endif + EVP_CIPHER_CTX *ctx = NULL; + const EVP_MD *dgst = NULL; + BIO *in = NULL, *out = NULL, *b64 = NULL, *benc = NULL; + BIO *rbio = NULL, *wbio = NULL; +#define PROG_NAME_SIZE 39 + char pname[PROG_NAME_SIZE + 1]; + int i; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + memset(&enc_config, 0, sizeof(enc_config)); + enc_config.enc = 1; + + /* first check the program name */ + program_name(argv[0], pname, sizeof(pname)); + + if (strcmp(pname, "base64") == 0) + enc_config.base64 = 1; + +#ifdef ZLIB + if (strcmp(pname, "zlib") == 0) + enc_config.do_zlib = 1; +#endif + + enc_config.cipher = EVP_get_cipherbyname(pname); + +#ifdef ZLIB + if (!enc_config.do_zlib && !enc_config.base64 && + enc_config.cipher == NULL && strcmp(pname, "enc") != 0) +#else + if (!enc_config.base64 && enc_config.cipher == NULL && + strcmp(pname, "enc") != 0) +#endif + { + BIO_printf(bio_err, "%s is an unknown cipher\n", pname); + goto end; + } + + if (options_parse(argc, argv, enc_options, NULL, NULL) != 0) { + enc_usage(); + goto end; + } + + if (enc_config.keyfile != NULL) { + static char buf[128]; + FILE *infile; + + infile = fopen(enc_config.keyfile, "r"); + if (infile == NULL) { + BIO_printf(bio_err, "unable to read key from '%s'\n", + enc_config.keyfile); + goto end; + } + buf[0] = '\0'; + if (!fgets(buf, sizeof buf, infile)) { + BIO_printf(bio_err, "unable to read key from '%s'\n", + enc_config.keyfile); + fclose(infile); + goto end; + } + fclose(infile); + i = strlen(buf); + if ((i > 0) && ((buf[i - 1] == '\n') || (buf[i - 1] == '\r'))) + buf[--i] = '\0'; + if ((i > 0) && ((buf[i - 1] == '\n') || (buf[i - 1] == '\r'))) + buf[--i] = '\0'; + if (i < 1) { + BIO_printf(bio_err, "zero length password\n"); + goto end; + } + enc_config.keystr = buf; + } + + if (enc_config.md != NULL && + (dgst = EVP_get_digestbyname(enc_config.md)) == NULL) { + BIO_printf(bio_err, + "%s is an unsupported message digest type\n", + enc_config.md); + goto end; + } + if (dgst == NULL) { + dgst = EVP_md5(); /* XXX */ + } + + if (enc_config.bufsize != NULL) { + char *p = enc_config.bufsize; + unsigned long n; + + /* XXX - provide an OPTION_ARG_DISKUNIT. */ + for (n = 0; *p != '\0'; p++) { + i = *p; + if ((i <= '9') && (i >= '0')) + n = n * 10 + i - '0'; + else if (i == 'k') { + n *= 1024; + p++; + break; + } + } + if (*p != '\0') { + BIO_printf(bio_err, "invalid 'bufsize' specified.\n"); + goto end; + } + /* It must be large enough for a base64 encoded line. */ + if (enc_config.base64 && n < 80) + n = 80; + + bsize = (int)n; + if (enc_config.verbose) + BIO_printf(bio_err, "bufsize=%d\n", bsize); + } + strbuf = malloc(SIZE); + buff = malloc(EVP_ENCODE_LENGTH(bsize)); + if ((buff == NULL) || (strbuf == NULL)) { + BIO_printf(bio_err, "malloc failure %ld\n", (long) EVP_ENCODE_LENGTH(bsize)); + goto end; + } + in = BIO_new(BIO_s_file()); + out = BIO_new(BIO_s_file()); + if ((in == NULL) || (out == NULL)) { + ERR_print_errors(bio_err); + goto end; + } + if (enc_config.debug) { + BIO_set_callback(in, BIO_debug_callback); + BIO_set_callback(out, BIO_debug_callback); + BIO_set_callback_arg(in, (char *) bio_err); + BIO_set_callback_arg(out, (char *) bio_err); + } + if (enc_config.inf == NULL) { + if (enc_config.bufsize != NULL) + setvbuf(stdin, (char *) NULL, _IONBF, 0); + BIO_set_fp(in, stdin, BIO_NOCLOSE); + } else { + if (BIO_read_filename(in, enc_config.inf) <= 0) { + perror(enc_config.inf); + goto end; + } + } + + if (!enc_config.keystr && enc_config.passarg) { + if (!app_passwd(bio_err, enc_config.passarg, NULL, + &pass, NULL)) { + BIO_printf(bio_err, "Error getting password\n"); + goto end; + } + enc_config.keystr = pass; + } + if (enc_config.keystr == NULL && enc_config.cipher != NULL && + enc_config.hkey == NULL) { + for (;;) { + char buf[200]; + int retval; + + retval = snprintf(buf, sizeof buf, + "enter %s %s password:", + OBJ_nid2ln(EVP_CIPHER_nid(enc_config.cipher)), + enc_config.enc ? "encryption" : "decryption"); + if ((size_t)retval >= sizeof buf) { + BIO_printf(bio_err, + "Password prompt too long\n"); + goto end; + } + strbuf[0] = '\0'; + i = EVP_read_pw_string((char *)strbuf, SIZE, buf, + enc_config.enc); + if (i == 0) { + if (strbuf[0] == '\0') { + ret = 1; + goto end; + } + enc_config.keystr = strbuf; + break; + } + if (i < 0) { + BIO_printf(bio_err, "bad password read\n"); + goto end; + } + } + } + if (enc_config.outf == NULL) { + BIO_set_fp(out, stdout, BIO_NOCLOSE); + if (enc_config.bufsize != NULL) + setvbuf(stdout, (char *)NULL, _IONBF, 0); + } else { + if (BIO_write_filename(out, enc_config.outf) <= 0) { + perror(enc_config.outf); + goto end; + } + } + + rbio = in; + wbio = out; + +#ifdef ZLIB + if (do_zlib) { + if ((bzl = BIO_new(BIO_f_zlib())) == NULL) + goto end; + if (enc) + wbio = BIO_push(bzl, wbio); + else + rbio = BIO_push(bzl, rbio); + } +#endif + + if (enc_config.base64) { + if ((b64 = BIO_new(BIO_f_base64())) == NULL) + goto end; + if (enc_config.debug) { + BIO_set_callback(b64, BIO_debug_callback); + BIO_set_callback_arg(b64, (char *) bio_err); + } + if (enc_config.olb64) + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + if (enc_config.enc) + wbio = BIO_push(b64, wbio); + else + rbio = BIO_push(b64, rbio); + } + if (enc_config.cipher != NULL) { + /* + * Note that keystr is NULL if a key was passed on the command + * line, so we get no salt in that case. Is this a bug? + */ + if (enc_config.keystr != NULL) { + /* + * Salt handling: if encrypting generate a salt and + * write to output BIO. If decrypting read salt from + * input BIO. + */ + unsigned char *sptr; + if (enc_config.nosalt) + sptr = NULL; + else { + if (enc_config.enc) { + if (enc_config.hsalt) { + if (!set_hex(enc_config.hsalt, salt, sizeof salt)) { + BIO_printf(bio_err, + "invalid hex salt value\n"); + goto end; + } + } else + arc4random_buf(salt, + sizeof(salt)); + /* + * If -P option then don't bother + * writing + */ + if ((enc_config.printkey != 2) + && (BIO_write(wbio, magic, + sizeof magic - 1) != sizeof magic - 1 + || BIO_write(wbio, + (char *) salt, + sizeof salt) != sizeof salt)) { + BIO_printf(bio_err, "error writing output file\n"); + goto end; + } + } else if (BIO_read(rbio, mbuf, sizeof mbuf) != sizeof mbuf + || BIO_read(rbio, + (unsigned char *) salt, + sizeof salt) != sizeof salt) { + BIO_printf(bio_err, "error reading input file\n"); + goto end; + } else if (memcmp(mbuf, magic, sizeof magic - 1)) { + BIO_printf(bio_err, "bad magic number\n"); + goto end; + } + sptr = salt; + } + + EVP_BytesToKey(enc_config.cipher, dgst, sptr, + (unsigned char *)enc_config.keystr, + strlen(enc_config.keystr), 1, key, iv); + /* + * zero the complete buffer or the string passed from + * the command line bug picked up by Larry J. Hughes + * Jr. + */ + if (enc_config.keystr == strbuf) + explicit_bzero(enc_config.keystr, SIZE); + else + explicit_bzero(enc_config.keystr, + strlen(enc_config.keystr)); + } + if (enc_config.hiv != NULL && + !set_hex(enc_config.hiv, iv, sizeof iv)) { + BIO_printf(bio_err, "invalid hex iv value\n"); + goto end; + } + if (enc_config.hiv == NULL && enc_config.keystr == NULL && + EVP_CIPHER_iv_length(enc_config.cipher) != 0) { + /* + * No IV was explicitly set and no IV was generated + * during EVP_BytesToKey. Hence the IV is undefined, + * making correct decryption impossible. + */ + BIO_printf(bio_err, "iv undefined\n"); + goto end; + } + if (enc_config.hkey != NULL && + !set_hex(enc_config.hkey, key, sizeof key)) { + BIO_printf(bio_err, "invalid hex key value\n"); + goto end; + } + if ((benc = BIO_new(BIO_f_cipher())) == NULL) + goto end; + + /* + * Since we may be changing parameters work on the encryption + * context rather than calling BIO_set_cipher(). + */ + + BIO_get_cipher_ctx(benc, &ctx); + + if (!EVP_CipherInit_ex(ctx, enc_config.cipher, NULL, NULL, + NULL, enc_config.enc)) { + BIO_printf(bio_err, "Error setting cipher %s\n", + EVP_CIPHER_name(enc_config.cipher)); + ERR_print_errors(bio_err); + goto end; + } + if (enc_config.nopad) + EVP_CIPHER_CTX_set_padding(ctx, 0); + + if (!EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, + enc_config.enc)) { + BIO_printf(bio_err, "Error setting cipher %s\n", + EVP_CIPHER_name(enc_config.cipher)); + ERR_print_errors(bio_err); + goto end; + } + if (enc_config.debug) { + BIO_set_callback(benc, BIO_debug_callback); + BIO_set_callback_arg(benc, (char *) bio_err); + } + if (enc_config.printkey) { + if (!enc_config.nosalt) { + printf("salt="); + for (i = 0; i < (int) sizeof(salt); i++) + printf("%02X", salt[i]); + printf("\n"); + } + if (enc_config.cipher->key_len > 0) { + printf("key="); + for (i = 0; i < enc_config.cipher->key_len; i++) + printf("%02X", key[i]); + printf("\n"); + } + if (enc_config.cipher->iv_len > 0) { + printf("iv ="); + for (i = 0; i < enc_config.cipher->iv_len; i++) + printf("%02X", iv[i]); + printf("\n"); + } + if (enc_config.printkey == 2) { + ret = 0; + goto end; + } + } + } + /* Only encrypt/decrypt as we write the file */ + if (benc != NULL) + wbio = BIO_push(benc, wbio); + + for (;;) { + inl = BIO_read(rbio, (char *) buff, bsize); + if (inl <= 0) + break; + if (BIO_write(wbio, (char *) buff, inl) != inl) { + BIO_printf(bio_err, "error writing output file\n"); + goto end; + } + } + if (!BIO_flush(wbio)) { + BIO_printf(bio_err, "bad decrypt\n"); + goto end; + } + ret = 0; + if (enc_config.verbose) { + BIO_printf(bio_err, "bytes read :%8ld\n", BIO_number_read(in)); + BIO_printf(bio_err, "bytes written:%8ld\n", BIO_number_written(out)); + } +end: + ERR_print_errors(bio_err); + free(strbuf); + free(buff); + BIO_free(in); + if (out != NULL) + BIO_free_all(out); + BIO_free(benc); + BIO_free(b64); +#ifdef ZLIB + BIO_free(bzl); +#endif + free(pass); + + return (ret); +} + +int +set_hex(char *in, unsigned char *out, int size) +{ + int i, n; + unsigned char j; + + n = strlen(in); + if (n > (size * 2)) { + BIO_printf(bio_err, "hex string is too long\n"); + return (0); + } + memset(out, 0, size); + for (i = 0; i < n; i++) { + j = (unsigned char) *in; + *(in++) = '\0'; + if (j == 0) + break; + if ((j >= '0') && (j <= '9')) + j -= '0'; + else if ((j >= 'A') && (j <= 'F')) + j = j - 'A' + 10; + else if ((j >= 'a') && (j <= 'f')) + j = j - 'a' + 10; + else { + BIO_printf(bio_err, "non-hex digit\n"); + return (0); + } + if (i & 1) + out[i / 2] |= j; + else + out[i / 2] = (j << 4); + } + return (1); +} diff --git a/bin/openssl/errstr.c b/bin/openssl/errstr.c new file mode 100644 index 0000000000..0d31d4fc85 --- /dev/null +++ b/bin/openssl/errstr.c @@ -0,0 +1,148 @@ +/* $OpenBSD: errstr.c,v 1.6 2015/10/17 15:00:11 doug Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include +#include +#include +#include + +#include "apps.h" + +#include +#include +#include +#include + +struct { + int stats; +} errstr_config; + +struct option errstr_options[] = { + { + .name = "stats", + .desc = "Print debugging statistics for the hash table", + .type = OPTION_FLAG, + .opt.flag = &errstr_config.stats, + }, + { NULL }, +}; + +static void +errstr_usage() +{ + fprintf(stderr, "usage: errstr [-stats] errno ...\n"); + options_usage(errstr_options); +} + +int +errstr_main(int argc, char **argv) +{ + unsigned long ulval; + char *ularg, *ep; + int argsused, i; + char buf[256]; + int ret = 0; + + if (single_execution) { + if (pledge("stdio rpath", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + memset(&errstr_config, 0, sizeof(errstr_config)); + + if (options_parse(argc, argv, errstr_options, NULL, &argsused) != 0) { + errstr_usage(); + return (1); + } + + if (errstr_config.stats) { + BIO *out; + + if ((out = BIO_new_fp(stdout, BIO_NOCLOSE)) == NULL) { + fprintf(stderr, "Out of memory"); + return (1); + } + + lh_ERR_STRING_DATA_node_stats_bio(ERR_get_string_table(), out); + lh_ERR_STRING_DATA_stats_bio(ERR_get_string_table(), out); + lh_ERR_STRING_DATA_node_usage_stats_bio( + ERR_get_string_table(), out); + + BIO_free_all(out); + } + + for (i = argsused; i < argc; i++) { + errno = 0; + ularg = argv[i]; + ulval = strtoul(ularg, &ep, 16); + if (strchr(ularg, '-') != NULL || + (ularg[0] == '\0' || *ep != '\0') || + (errno == ERANGE && ulval == ULONG_MAX)) { + printf("%s: bad error code\n", ularg); + ret++; + continue; + } + + ERR_error_string_n(ulval, buf, sizeof(buf)); + printf("%s\n", buf); + } + + return (ret); +} diff --git a/bin/openssl/gendh.c b/bin/openssl/gendh.c new file mode 100644 index 0000000000..7c037f44e1 --- /dev/null +++ b/bin/openssl/gendh.c @@ -0,0 +1,217 @@ +/* $OpenBSD: gendh.c,v 1.8 2017/01/20 08:57:12 deraadt Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include + +/* Until the key-gen callbacks are modified to use newer prototypes, we allow + * deprecated functions for openssl-internal code */ +#ifdef OPENSSL_NO_DEPRECATED +#undef OPENSSL_NO_DEPRECATED +#endif + +#ifndef OPENSSL_NO_DH + +#include +#include + +#include +#include +#include + +#include "apps.h" + +#include +#include +#include +#include +#include +#include + +#define DEFBITS 512 + +static int dh_cb(int p, int n, BN_GENCB * cb); + +static struct { + int g; + char *outfile; +} gendh_config; + +static struct option gendh_options[] = { + { + .name = "2", + .desc = "Generate DH parameters with a generator value of 2 " + "(default)", + .type = OPTION_VALUE, + .value = 2, + .opt.value = &gendh_config.g, + }, + { + .name = "5", + .desc = "Generate DH parameters with a generator value of 5", + .type = OPTION_VALUE, + .value = 5, + .opt.value = &gendh_config.g, + }, + { + .name = "out", + .argname = "file", + .desc = "Output file (default stdout)", + .type = OPTION_ARG, + .opt.arg = &gendh_config.outfile, + }, + { NULL }, +}; + +static void +gendh_usage(void) +{ + fprintf(stderr, + "usage: gendh [-2 | -5] [-out file] [numbits]\n\n"); + options_usage(gendh_options); +} + +int +gendh_main(int argc, char **argv) +{ + BN_GENCB cb; + DH *dh = NULL; + int ret = 1, numbits = DEFBITS; + BIO *out = NULL; + char *strbits = NULL; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + BN_GENCB_set(&cb, dh_cb, bio_err); + + memset(&gendh_config, 0, sizeof(gendh_config)); + + gendh_config.g = 2; + + if (options_parse(argc, argv, gendh_options, &strbits, NULL) != 0) { + gendh_usage(); + goto end; + } + + if (strbits != NULL) { + const char *errstr; + numbits = strtonum(strbits, 0, INT_MAX, &errstr); + if (errstr) { + fprintf(stderr, "Invalid number of bits: %s\n", errstr); + goto end; + } + } + + out = BIO_new(BIO_s_file()); + if (out == NULL) { + ERR_print_errors(bio_err); + goto end; + } + if (gendh_config.outfile == NULL) { + BIO_set_fp(out, stdout, BIO_NOCLOSE); + } else { + if (BIO_write_filename(out, gendh_config.outfile) <= 0) { + perror(gendh_config.outfile); + goto end; + } + } + + BIO_printf(bio_err, "Generating DH parameters, %d bit long safe prime," + " generator %d\n", numbits, gendh_config.g); + BIO_printf(bio_err, "This is going to take a long time\n"); + + if (((dh = DH_new()) == NULL) || + !DH_generate_parameters_ex(dh, numbits, gendh_config.g, &cb)) + goto end; + + if (!PEM_write_bio_DHparams(out, dh)) + goto end; + ret = 0; +end: + if (ret != 0) + ERR_print_errors(bio_err); + if (out != NULL) + BIO_free_all(out); + if (dh != NULL) + DH_free(dh); + + return (ret); +} + +static int +dh_cb(int p, int n, BN_GENCB * cb) +{ + char c = '*'; + + if (p == 0) + c = '.'; + if (p == 1) + c = '+'; + if (p == 2) + c = '*'; + if (p == 3) + c = '\n'; + BIO_write(cb->arg, &c, 1); + (void) BIO_flush(cb->arg); + return 1; +} +#endif diff --git a/bin/openssl/gendsa.c b/bin/openssl/gendsa.c new file mode 100644 index 0000000000..5aeb294e7f --- /dev/null +++ b/bin/openssl/gendsa.c @@ -0,0 +1,216 @@ +/* $OpenBSD: gendsa.c,v 1.8 2017/01/20 08:57:12 deraadt Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include /* for OPENSSL_NO_DSA */ + + +#include +#include + +#include +#include + +#include "apps.h" + +#include +#include +#include +#include +#include +#include + +int +gendsa_main(int argc, char **argv) +{ + DSA *dsa = NULL; + int ret = 1; + char *outfile = NULL; + char *dsaparams = NULL; + char *passargout = NULL, *passout = NULL; + BIO *out = NULL, *in = NULL; + const EVP_CIPHER *enc = NULL; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + argv++; + argc--; + for (;;) { + if (argc <= 0) + break; + if (strcmp(*argv, "-out") == 0) { + if (--argc < 1) + goto bad; + outfile = *(++argv); + } else if (strcmp(*argv, "-passout") == 0) { + if (--argc < 1) + goto bad; + passargout = *(++argv); + } + else if (strcmp(*argv, "-") == 0) + goto bad; +#ifndef OPENSSL_NO_DES + else if (strcmp(*argv, "-des") == 0) + enc = EVP_des_cbc(); + else if (strcmp(*argv, "-des3") == 0) + enc = EVP_des_ede3_cbc(); +#endif +#ifndef OPENSSL_NO_IDEA + else if (strcmp(*argv, "-idea") == 0) + enc = EVP_idea_cbc(); +#endif +#ifndef OPENSSL_NO_AES + else if (strcmp(*argv, "-aes128") == 0) + enc = EVP_aes_128_cbc(); + else if (strcmp(*argv, "-aes192") == 0) + enc = EVP_aes_192_cbc(); + else if (strcmp(*argv, "-aes256") == 0) + enc = EVP_aes_256_cbc(); +#endif +#ifndef OPENSSL_NO_CAMELLIA + else if (strcmp(*argv, "-camellia128") == 0) + enc = EVP_camellia_128_cbc(); + else if (strcmp(*argv, "-camellia192") == 0) + enc = EVP_camellia_192_cbc(); + else if (strcmp(*argv, "-camellia256") == 0) + enc = EVP_camellia_256_cbc(); +#endif + else if (**argv != '-' && dsaparams == NULL) { + dsaparams = *argv; + } else + goto bad; + argv++; + argc--; + } + + if (dsaparams == NULL) { +bad: + BIO_printf(bio_err, "usage: gendsa [args] dsaparam-file\n"); + BIO_printf(bio_err, " -out file - output the key to 'file'\n"); +#ifndef OPENSSL_NO_DES + BIO_printf(bio_err, " -des - encrypt the generated key with DES in cbc mode\n"); + BIO_printf(bio_err, " -des3 - encrypt the generated key with DES in ede cbc mode (168 bit key)\n"); +#endif +#ifndef OPENSSL_NO_IDEA + BIO_printf(bio_err, " -idea - encrypt the generated key with IDEA in cbc mode\n"); +#endif +#ifndef OPENSSL_NO_AES + BIO_printf(bio_err, " -aes128, -aes192, -aes256\n"); + BIO_printf(bio_err, " encrypt PEM output with cbc aes\n"); +#endif +#ifndef OPENSSL_NO_CAMELLIA + BIO_printf(bio_err, " -camellia128, -camellia192, -camellia256\n"); + BIO_printf(bio_err, " encrypt PEM output with cbc camellia\n"); +#endif + BIO_printf(bio_err, " dsaparam-file\n"); + BIO_printf(bio_err, " - a DSA parameter file as generated by the dsaparam command\n"); + goto end; + } + if (!app_passwd(bio_err, NULL, passargout, NULL, &passout)) { + BIO_printf(bio_err, "Error getting password\n"); + goto end; + } + in = BIO_new(BIO_s_file()); + if (!(BIO_read_filename(in, dsaparams))) { + perror(dsaparams); + goto end; + } + if ((dsa = PEM_read_bio_DSAparams(in, NULL, NULL, NULL)) == NULL) { + BIO_printf(bio_err, "unable to load DSA parameter file\n"); + goto end; + } + BIO_free(in); + in = NULL; + + out = BIO_new(BIO_s_file()); + if (out == NULL) + goto end; + + if (outfile == NULL) { + BIO_set_fp(out, stdout, BIO_NOCLOSE); + } else { + if (BIO_write_filename(out, outfile) <= 0) { + perror(outfile); + goto end; + } + } + + BIO_printf(bio_err, "Generating DSA key, %d bits\n", + BN_num_bits(dsa->p)); + if (!DSA_generate_key(dsa)) + goto end; + + if (!PEM_write_bio_DSAPrivateKey(out, dsa, enc, NULL, 0, NULL, passout)) + goto end; + ret = 0; +end: + if (ret != 0) + ERR_print_errors(bio_err); + BIO_free(in); + if (out != NULL) + BIO_free_all(out); + if (dsa != NULL) + DSA_free(dsa); + free(passout); + + return (ret); +} diff --git a/bin/openssl/genpkey.c b/bin/openssl/genpkey.c new file mode 100644 index 0000000000..cae7eacd4e --- /dev/null +++ b/bin/openssl/genpkey.c @@ -0,0 +1,359 @@ +/* $OpenBSD: genpkey.c,v 1.9 2017/01/20 08:57:12 deraadt Exp $ */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2006 + */ +/* ==================================================================== + * Copyright (c) 2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include +#include + +#include "apps.h" + +#include +#include +#include + +static int +init_keygen_file(BIO * err, EVP_PKEY_CTX ** pctx, const char *file); +static int genpkey_cb(EVP_PKEY_CTX * ctx); + +int +genpkey_main(int argc, char **argv) +{ + char **args, *outfile = NULL; + char *passarg = NULL; + BIO *in = NULL, *out = NULL; + const EVP_CIPHER *cipher = NULL; + int outformat; + int text = 0; + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *ctx = NULL; + char *pass = NULL; + int badarg = 0; + int ret = 1, rv; + + int do_param = 0; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + outformat = FORMAT_PEM; + + args = argv + 1; + while (!badarg && *args && *args[0] == '-') { + if (!strcmp(*args, "-outform")) { + if (args[1]) { + args++; + outformat = str2fmt(*args); + } else + badarg = 1; + } else if (!strcmp(*args, "-pass")) { + if (!args[1]) + goto bad; + passarg = *(++args); + } + else if (!strcmp(*args, "-paramfile")) { + if (!args[1]) + goto bad; + args++; + if (do_param == 1) + goto bad; + if (!init_keygen_file(bio_err, &ctx, *args)) + goto end; + } else if (!strcmp(*args, "-out")) { + if (args[1]) { + args++; + outfile = *args; + } else + badarg = 1; + } else if (strcmp(*args, "-algorithm") == 0) { + if (!args[1]) + goto bad; + if (!init_gen_str(bio_err, &ctx, *(++args), do_param)) + goto end; + } else if (strcmp(*args, "-pkeyopt") == 0) { + if (!args[1]) + goto bad; + if (!ctx) { + BIO_puts(bio_err, "No keytype specified\n"); + goto bad; + } else if (pkey_ctrl_string(ctx, *(++args)) <= 0) { + BIO_puts(bio_err, "parameter setting error\n"); + ERR_print_errors(bio_err); + goto end; + } + } else if (strcmp(*args, "-genparam") == 0) { + if (ctx) + goto bad; + do_param = 1; + } else if (strcmp(*args, "-text") == 0) + text = 1; + else { + cipher = EVP_get_cipherbyname(*args + 1); + if (!cipher) { + BIO_printf(bio_err, "Unknown cipher %s\n", + *args + 1); + badarg = 1; + } + if (do_param == 1) + badarg = 1; + } + args++; + } + + if (!ctx) + badarg = 1; + + if (badarg) { +bad: + BIO_printf(bio_err, "Usage: genpkey [options]\n"); + BIO_printf(bio_err, "where options may be\n"); + BIO_printf(bio_err, "-out file output file\n"); + BIO_printf(bio_err, "-outform X output format (DER or PEM)\n"); + BIO_printf(bio_err, "-pass arg output file pass phrase source\n"); + BIO_printf(bio_err, "- use cipher to encrypt the key\n"); + BIO_printf(bio_err, "-paramfile file parameters file\n"); + BIO_printf(bio_err, "-algorithm alg the public key algorithm\n"); + BIO_printf(bio_err, "-pkeyopt opt:value set the public key algorithm option \n" + " to value \n"); + BIO_printf(bio_err, "-genparam generate parameters, not key\n"); + BIO_printf(bio_err, "-text print the in text\n"); + BIO_printf(bio_err, "NB: options order may be important! See the manual page.\n"); + goto end; + } + if (!app_passwd(bio_err, passarg, NULL, &pass, NULL)) { + BIO_puts(bio_err, "Error getting password\n"); + goto end; + } + if (outfile) { + if (!(out = BIO_new_file(outfile, "wb"))) { + BIO_printf(bio_err, + "Can't open output file %s\n", outfile); + goto end; + } + } else { + out = BIO_new_fp(stdout, BIO_NOCLOSE); + } + + EVP_PKEY_CTX_set_cb(ctx, genpkey_cb); + EVP_PKEY_CTX_set_app_data(ctx, bio_err); + + if (do_param) { + if (EVP_PKEY_paramgen(ctx, &pkey) <= 0) { + BIO_puts(bio_err, "Error generating parameters\n"); + ERR_print_errors(bio_err); + goto end; + } + } else { + if (EVP_PKEY_keygen(ctx, &pkey) <= 0) { + BIO_puts(bio_err, "Error generating key\n"); + ERR_print_errors(bio_err); + goto end; + } + } + + if (do_param) + rv = PEM_write_bio_Parameters(out, pkey); + else if (outformat == FORMAT_PEM) + rv = PEM_write_bio_PrivateKey(out, pkey, cipher, NULL, 0, + NULL, pass); + else if (outformat == FORMAT_ASN1) + rv = i2d_PrivateKey_bio(out, pkey); + else { + BIO_printf(bio_err, "Bad format specified for key\n"); + goto end; + } + + if (rv <= 0) { + BIO_puts(bio_err, "Error writing key\n"); + ERR_print_errors(bio_err); + } + if (text) { + if (do_param) + rv = EVP_PKEY_print_params(out, pkey, 0, NULL); + else + rv = EVP_PKEY_print_private(out, pkey, 0, NULL); + + if (rv <= 0) { + BIO_puts(bio_err, "Error printing key\n"); + ERR_print_errors(bio_err); + } + } + ret = 0; + +end: + if (pkey) + EVP_PKEY_free(pkey); + if (ctx) + EVP_PKEY_CTX_free(ctx); + if (out) + BIO_free_all(out); + BIO_free(in); + free(pass); + + return ret; +} + +static int +init_keygen_file(BIO * err, EVP_PKEY_CTX ** pctx, + const char *file) +{ + BIO *pbio; + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *ctx = NULL; + if (*pctx) { + BIO_puts(err, "Parameters already set!\n"); + return 0; + } + pbio = BIO_new_file(file, "r"); + if (!pbio) { + BIO_printf(err, "Can't open parameter file %s\n", file); + return 0; + } + pkey = PEM_read_bio_Parameters(pbio, NULL); + BIO_free(pbio); + + if (!pkey) { + BIO_printf(bio_err, "Error reading parameter file %s\n", file); + return 0; + } + ctx = EVP_PKEY_CTX_new(pkey, NULL); + if (!ctx) + goto err; + if (EVP_PKEY_keygen_init(ctx) <= 0) + goto err; + EVP_PKEY_free(pkey); + *pctx = ctx; + return 1; + +err: + BIO_puts(err, "Error initializing context\n"); + ERR_print_errors(err); + if (ctx) + EVP_PKEY_CTX_free(ctx); + if (pkey) + EVP_PKEY_free(pkey); + return 0; + +} + +int +init_gen_str(BIO * err, EVP_PKEY_CTX ** pctx, + const char *algname, int do_param) +{ + EVP_PKEY_CTX *ctx = NULL; + const EVP_PKEY_ASN1_METHOD *ameth; + int pkey_id; + + if (*pctx) { + BIO_puts(err, "Algorithm already set!\n"); + return 0; + } + ameth = EVP_PKEY_asn1_find_str(NULL, algname, -1); + + if (!ameth) { + BIO_printf(bio_err, "Algorithm %s not found\n", algname); + return 0; + } + ERR_clear_error(); + + EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth); + ctx = EVP_PKEY_CTX_new_id(pkey_id, NULL); + + if (!ctx) + goto err; + if (do_param) { + if (EVP_PKEY_paramgen_init(ctx) <= 0) + goto err; + } else { + if (EVP_PKEY_keygen_init(ctx) <= 0) + goto err; + } + + *pctx = ctx; + return 1; + +err: + BIO_printf(err, "Error initializing %s context\n", algname); + ERR_print_errors(err); + if (ctx) + EVP_PKEY_CTX_free(ctx); + return 0; + +} + +static int +genpkey_cb(EVP_PKEY_CTX * ctx) +{ + char c = '*'; + BIO *b = EVP_PKEY_CTX_get_app_data(ctx); + int p; + p = EVP_PKEY_CTX_get_keygen_info(ctx, 0); + if (p == 0) + c = '.'; + if (p == 1) + c = '+'; + if (p == 2) + c = '*'; + if (p == 3) + c = '\n'; + BIO_write(b, &c, 1); + (void) BIO_flush(b); + return 1; +} diff --git a/bin/openssl/genrsa.c b/bin/openssl/genrsa.c new file mode 100644 index 0000000000..4fa5747b28 --- /dev/null +++ b/bin/openssl/genrsa.c @@ -0,0 +1,266 @@ +/* $OpenBSD: genrsa.c,v 1.9 2017/01/20 08:57:12 deraadt Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include + +/* Until the key-gen callbacks are modified to use newer prototypes, we allow + * deprecated functions for openssl-internal code */ +#ifdef OPENSSL_NO_DEPRECATED +#undef OPENSSL_NO_DEPRECATED +#endif + + +#include +#include + +#include +#include + +#include "apps.h" + +#include +#include +#include +#include +#include +#include +#include + +#define DEFBITS 2048 + +static int genrsa_cb(int p, int n, BN_GENCB * cb); + +int +genrsa_main(int argc, char **argv) +{ + BN_GENCB cb; + int ret = 1; + int i, num = DEFBITS; + long l; + const EVP_CIPHER *enc = NULL; + unsigned long f4 = RSA_F4; + char *outfile = NULL; + char *passargout = NULL, *passout = NULL; + BIO *out = NULL; + BIGNUM *bn = BN_new(); + RSA *rsa = NULL; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + if (!bn) + goto err; + + BN_GENCB_set(&cb, genrsa_cb, bio_err); + + if ((out = BIO_new(BIO_s_file())) == NULL) { + BIO_printf(bio_err, "unable to create BIO for output\n"); + goto err; + } + argv++; + argc--; + for (;;) { + if (argc <= 0) + break; + if (strcmp(*argv, "-out") == 0) { + if (--argc < 1) + goto bad; + outfile = *(++argv); + } else if (strcmp(*argv, "-3") == 0) + f4 = 3; + else if (strcmp(*argv, "-F4") == 0 || strcmp(*argv, "-f4") == 0) + f4 = RSA_F4; +#ifndef OPENSSL_NO_DES + else if (strcmp(*argv, "-des") == 0) + enc = EVP_des_cbc(); + else if (strcmp(*argv, "-des3") == 0) + enc = EVP_des_ede3_cbc(); +#endif +#ifndef OPENSSL_NO_IDEA + else if (strcmp(*argv, "-idea") == 0) + enc = EVP_idea_cbc(); +#endif +#ifndef OPENSSL_NO_AES + else if (strcmp(*argv, "-aes128") == 0) + enc = EVP_aes_128_cbc(); + else if (strcmp(*argv, "-aes192") == 0) + enc = EVP_aes_192_cbc(); + else if (strcmp(*argv, "-aes256") == 0) + enc = EVP_aes_256_cbc(); +#endif +#ifndef OPENSSL_NO_CAMELLIA + else if (strcmp(*argv, "-camellia128") == 0) + enc = EVP_camellia_128_cbc(); + else if (strcmp(*argv, "-camellia192") == 0) + enc = EVP_camellia_192_cbc(); + else if (strcmp(*argv, "-camellia256") == 0) + enc = EVP_camellia_256_cbc(); +#endif + else if (strcmp(*argv, "-passout") == 0) { + if (--argc < 1) + goto bad; + passargout = *(++argv); + } else + break; + argv++; + argc--; + } + if ((argc >= 1) && ((sscanf(*argv, "%d", &num) == 0) || (num < 0))) { +bad: + BIO_printf(bio_err, "usage: genrsa [args] [numbits]\n"); + BIO_printf(bio_err, " -des encrypt the generated key with DES in cbc mode\n"); + BIO_printf(bio_err, " -des3 encrypt the generated key with DES in ede cbc mode (168 bit key)\n"); +#ifndef OPENSSL_NO_IDEA + BIO_printf(bio_err, " -idea encrypt the generated key with IDEA in cbc mode\n"); +#endif +#ifndef OPENSSL_NO_AES + BIO_printf(bio_err, " -aes128, -aes192, -aes256\n"); + BIO_printf(bio_err, " encrypt PEM output with cbc aes\n"); +#endif +#ifndef OPENSSL_NO_CAMELLIA + BIO_printf(bio_err, " -camellia128, -camellia192, -camellia256\n"); + BIO_printf(bio_err, " encrypt PEM output with cbc camellia\n"); +#endif + BIO_printf(bio_err, " -out file output the key to 'file\n"); + BIO_printf(bio_err, " -passout arg output file pass phrase source\n"); + BIO_printf(bio_err, " -f4 use F4 (0x10001) for the E value\n"); + BIO_printf(bio_err, " -3 use 3 for the E value\n"); + goto err; + } + + if (!app_passwd(bio_err, NULL, passargout, NULL, &passout)) { + BIO_printf(bio_err, "Error getting password\n"); + goto err; + } + + if (outfile == NULL) { + BIO_set_fp(out, stdout, BIO_NOCLOSE); + } else { + if (BIO_write_filename(out, outfile) <= 0) { + perror(outfile); + goto err; + } + } + + BIO_printf(bio_err, "Generating RSA private key, %d bit long modulus\n", + num); + rsa = RSA_new(); + if (!rsa) + goto err; + + if (!BN_set_word(bn, f4) || !RSA_generate_key_ex(rsa, num, bn, &cb)) + goto err; + + /* + * We need to do the following for when the base number size is < + * long, esp windows 3.1 :-(. + */ + l = 0L; + for (i = 0; i < rsa->e->top; i++) { +#ifndef _LP64 + l <<= BN_BITS4; + l <<= BN_BITS4; +#endif + l += rsa->e->d[i]; + } + BIO_printf(bio_err, "e is %ld (0x%lX)\n", l, l); + { + PW_CB_DATA cb_data; + cb_data.password = passout; + cb_data.prompt_info = outfile; + if (!PEM_write_bio_RSAPrivateKey(out, rsa, enc, NULL, 0, + password_callback, &cb_data)) + goto err; + } + + ret = 0; +err: + if (bn) + BN_free(bn); + if (rsa) + RSA_free(rsa); + if (out) + BIO_free_all(out); + free(passout); + if (ret != 0) + ERR_print_errors(bio_err); + + return (ret); +} + +static int +genrsa_cb(int p, int n, BN_GENCB * cb) +{ + char c = '*'; + + if (p == 0) + c = '.'; + if (p == 1) + c = '+'; + if (p == 2) + c = '*'; + if (p == 3) + c = '\n'; + BIO_write(cb->arg, &c, 1); + (void) BIO_flush(cb->arg); + return 1; +} diff --git a/bin/openssl/nseq.c b/bin/openssl/nseq.c new file mode 100644 index 0000000000..4669147416 --- /dev/null +++ b/bin/openssl/nseq.c @@ -0,0 +1,176 @@ +/* $OpenBSD: nseq.c,v 1.7 2017/01/20 08:57:12 deraadt Exp $ */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include +#include + +#include "apps.h" + +#include +#include + +static struct { + char *infile; + char *outfile; + int toseq; +} nseq_config; + +static struct option nseq_options[] = { + { + .name = "in", + .argname = "file", + .desc = "Input file to read from (default stdin)", + .type = OPTION_ARG, + .opt.arg = &nseq_config.infile, + }, + { + .name = "out", + .argname = "file", + .desc = "Output file to write to (default stdout)", + .type = OPTION_ARG, + .opt.arg = &nseq_config.outfile, + }, + { + .name = "toseq", + .desc = "Convert certificates to Netscape certificate sequence", + .type = OPTION_FLAG, + .opt.flag = &nseq_config.toseq, + }, + { NULL }, +}; + +static void +nseq_usage() +{ + fprintf(stderr, "usage: nseq [-in file] [-out file] [-toseq]\n"); + options_usage(nseq_options); +} + +int +nseq_main(int argc, char **argv) +{ + BIO *in = NULL, *out = NULL; + X509 *x509 = NULL; + NETSCAPE_CERT_SEQUENCE *seq = NULL; + int i, ret = 1; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + memset(&nseq_config, 0, sizeof(nseq_config)); + + if (options_parse(argc, argv, nseq_options, NULL, NULL) != 0) { + nseq_usage(); + return (1); + } + + if (nseq_config.infile) { + if (!(in = BIO_new_file(nseq_config.infile, "r"))) { + BIO_printf(bio_err, + "Can't open input file %s\n", nseq_config.infile); + goto end; + } + } else + in = BIO_new_fp(stdin, BIO_NOCLOSE); + + if (nseq_config.outfile) { + if (!(out = BIO_new_file(nseq_config.outfile, "w"))) { + BIO_printf(bio_err, + "Can't open output file %s\n", nseq_config.outfile); + goto end; + } + } else { + out = BIO_new_fp(stdout, BIO_NOCLOSE); + } + if (nseq_config.toseq) { + seq = NETSCAPE_CERT_SEQUENCE_new(); + seq->certs = sk_X509_new_null(); + while ((x509 = PEM_read_bio_X509(in, NULL, NULL, NULL))) + sk_X509_push(seq->certs, x509); + + if (!sk_X509_num(seq->certs)) { + BIO_printf(bio_err, "Error reading certs file %s\n", nseq_config.infile); + ERR_print_errors(bio_err); + goto end; + } + PEM_write_bio_NETSCAPE_CERT_SEQUENCE(out, seq); + ret = 0; + goto end; + } + if (!(seq = PEM_read_bio_NETSCAPE_CERT_SEQUENCE(in, NULL, NULL, NULL))) { + BIO_printf(bio_err, "Error reading sequence file %s\n", nseq_config.infile); + ERR_print_errors(bio_err); + goto end; + } + for (i = 0; i < sk_X509_num(seq->certs); i++) { + x509 = sk_X509_value(seq->certs, i); + dump_cert_text(out, x509); + PEM_write_bio_X509(out, x509); + } + ret = 0; +end: + BIO_free(in); + BIO_free_all(out); + NETSCAPE_CERT_SEQUENCE_free(seq); + + return (ret); +} diff --git a/bin/openssl/ocsp.c b/bin/openssl/ocsp.c new file mode 100644 index 0000000000..64eeef8e5c --- /dev/null +++ b/bin/openssl/ocsp.c @@ -0,0 +1,1220 @@ +/* $OpenBSD: ocsp.c,v 1.12 2017/01/21 09:29:09 deraadt Exp $ */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2000. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +#ifndef OPENSSL_NO_OCSP + +#include + +#include +#include +#include +#include +#include +#include + +/* Needs to be included before the openssl headers! */ +#include "apps.h" + +#include +#include +#include +#include +#include +#include + +/* Maximum leeway in validity period: default 5 minutes */ +#define MAX_VALIDITY_PERIOD (5 * 60) + +static int +add_ocsp_cert(OCSP_REQUEST ** req, X509 * cert, const EVP_MD * cert_id_md, X509 * issuer, + STACK_OF(OCSP_CERTID) * ids); +static int add_ocsp_serial(OCSP_REQUEST ** req, char *serial, const EVP_MD * cert_id_md, X509 * issuer, + STACK_OF(OCSP_CERTID) * ids); +static int print_ocsp_summary(BIO * out, OCSP_BASICRESP * bs, OCSP_REQUEST * req, + STACK_OF(OPENSSL_STRING) * names, + STACK_OF(OCSP_CERTID) * ids, long nsec, + long maxage); + +static int make_ocsp_response(OCSP_RESPONSE ** resp, OCSP_REQUEST * req, CA_DB * db, + X509 * ca, X509 * rcert, EVP_PKEY * rkey, + STACK_OF(X509) * rother, unsigned long flags, + int nmin, int ndays); + +static char **lookup_serial(CA_DB * db, ASN1_INTEGER * ser); +static BIO *init_responder(char *port); +static int do_responder(OCSP_REQUEST ** preq, BIO ** pcbio, BIO * acbio, char *port); +static int send_ocsp_response(BIO * cbio, OCSP_RESPONSE * resp); +static OCSP_RESPONSE *query_responder(BIO * err, BIO * cbio, char *path, + STACK_OF(CONF_VALUE) * headers, + OCSP_REQUEST * req, int req_timeout); + +int +ocsp_main(int argc, char **argv) +{ + char **args; + char *host = NULL, *port = NULL, *path = "/"; + char *reqin = NULL, *respin = NULL; + char *reqout = NULL, *respout = NULL; + char *signfile = NULL, *keyfile = NULL; + char *rsignfile = NULL, *rkeyfile = NULL; + char *outfile = NULL; + int add_nonce = 1, noverify = 0, use_ssl = -1; + STACK_OF(CONF_VALUE) * headers = NULL; + OCSP_REQUEST *req = NULL; + OCSP_RESPONSE *resp = NULL; + OCSP_BASICRESP *bs = NULL; + X509 *issuer = NULL, *cert = NULL; + X509 *signer = NULL, *rsigner = NULL; + EVP_PKEY *key = NULL, *rkey = NULL; + BIO *acbio = NULL, *cbio = NULL; + BIO *derbio = NULL; + BIO *out = NULL; + int req_timeout = -1; + int req_text = 0, resp_text = 0; + long nsec = MAX_VALIDITY_PERIOD, maxage = -1; + char *CAfile = NULL, *CApath = NULL; + X509_STORE *store = NULL; + STACK_OF(X509) * sign_other = NULL, *verify_other = NULL, *rother = NULL; + char *sign_certfile = NULL, *verify_certfile = NULL, *rcertfile = NULL; + unsigned long sign_flags = 0, verify_flags = 0, rflags = 0; + int ret = 1; + int accept_count = -1; + int badarg = 0; + int i; + int ignore_err = 0; + STACK_OF(OPENSSL_STRING) * reqnames = NULL; + STACK_OF(OCSP_CERTID) * ids = NULL; + X509 *rca_cert = NULL; + char *ridx_filename = NULL; + char *rca_filename = NULL; + CA_DB *rdb = NULL; + int nmin = 0, ndays = -1; + const EVP_MD *cert_id_md = NULL; + const char *errstr = NULL; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath inet dns tty", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + args = argv + 1; + reqnames = sk_OPENSSL_STRING_new_null(); + ids = sk_OCSP_CERTID_new_null(); + while (!badarg && *args && *args[0] == '-') { + if (!strcmp(*args, "-out")) { + if (args[1]) { + args++; + outfile = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-timeout")) { + if (args[1]) { + args++; + req_timeout = strtonum(*args, 0, + INT_MAX, &errstr); + if (errstr) { + BIO_printf(bio_err, + "Illegal timeout value %s: %s\n", + *args, errstr); + badarg = 1; + } + } else + badarg = 1; + } else if (!strcmp(*args, "-url")) { + if (args[1]) { + args++; + if (!OCSP_parse_url(*args, &host, &port, &path, &use_ssl)) { + BIO_printf(bio_err, "Error parsing URL\n"); + badarg = 1; + } + } else + badarg = 1; + } else if (!strcmp(*args, "-host")) { + if (args[1]) { + args++; + host = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-port")) { + if (args[1]) { + args++; + port = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-header")) { + if (args[1] && args[2]) { + if (!X509V3_add_value(args[1], args[2], &headers)) + goto end; + args += 2; + } else + badarg = 1; + } else if (!strcmp(*args, "-ignore_err")) + ignore_err = 1; + else if (!strcmp(*args, "-noverify")) + noverify = 1; + else if (!strcmp(*args, "-nonce")) + add_nonce = 2; + else if (!strcmp(*args, "-no_nonce")) + add_nonce = 0; + else if (!strcmp(*args, "-resp_no_certs")) + rflags |= OCSP_NOCERTS; + else if (!strcmp(*args, "-resp_key_id")) + rflags |= OCSP_RESPID_KEY; + else if (!strcmp(*args, "-no_certs")) + sign_flags |= OCSP_NOCERTS; + else if (!strcmp(*args, "-no_signature_verify")) + verify_flags |= OCSP_NOSIGS; + else if (!strcmp(*args, "-no_cert_verify")) + verify_flags |= OCSP_NOVERIFY; + else if (!strcmp(*args, "-no_chain")) + verify_flags |= OCSP_NOCHAIN; + else if (!strcmp(*args, "-no_cert_checks")) + verify_flags |= OCSP_NOCHECKS; + else if (!strcmp(*args, "-no_explicit")) + verify_flags |= OCSP_NOEXPLICIT; + else if (!strcmp(*args, "-trust_other")) + verify_flags |= OCSP_TRUSTOTHER; + else if (!strcmp(*args, "-no_intern")) + verify_flags |= OCSP_NOINTERN; + else if (!strcmp(*args, "-text")) { + req_text = 1; + resp_text = 1; + } else if (!strcmp(*args, "-req_text")) + req_text = 1; + else if (!strcmp(*args, "-resp_text")) + resp_text = 1; + else if (!strcmp(*args, "-reqin")) { + if (args[1]) { + args++; + reqin = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-respin")) { + if (args[1]) { + args++; + respin = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-signer")) { + if (args[1]) { + args++; + signfile = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-VAfile")) { + if (args[1]) { + args++; + verify_certfile = *args; + verify_flags |= OCSP_TRUSTOTHER; + } else + badarg = 1; + } else if (!strcmp(*args, "-sign_other")) { + if (args[1]) { + args++; + sign_certfile = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-verify_other")) { + if (args[1]) { + args++; + verify_certfile = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-CAfile")) { + if (args[1]) { + args++; + CAfile = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-CApath")) { + if (args[1]) { + args++; + CApath = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-validity_period")) { + if (args[1]) { + args++; + nsec = strtonum(*args, 0, LONG_MAX, &errstr); + if (errstr) { + BIO_printf(bio_err, + "Illegal validity period %s: %s\n", + *args, errstr); + badarg = 1; + } + } else + badarg = 1; + } else if (!strcmp(*args, "-status_age")) { + if (args[1]) { + args++; + maxage = strtonum(*args, 0, LONG_MAX, &errstr); + if (errstr) { + BIO_printf(bio_err, + "Illegal validity age %s: %s\n", + *args, errstr); + badarg = 1; + } + } else + badarg = 1; + } else if (!strcmp(*args, "-signkey")) { + if (args[1]) { + args++; + keyfile = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-reqout")) { + if (args[1]) { + args++; + reqout = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-respout")) { + if (args[1]) { + args++; + respout = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-path")) { + if (args[1]) { + args++; + path = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-issuer")) { + if (args[1]) { + args++; + X509_free(issuer); + issuer = load_cert(bio_err, *args, FORMAT_PEM, + NULL, "issuer certificate"); + if (!issuer) + goto end; + } else + badarg = 1; + } else if (!strcmp(*args, "-cert")) { + if (args[1]) { + args++; + X509_free(cert); + cert = load_cert(bio_err, *args, FORMAT_PEM, + NULL, "certificate"); + if (!cert) + goto end; + if (!cert_id_md) + cert_id_md = EVP_sha1(); + if (!add_ocsp_cert(&req, cert, cert_id_md, issuer, ids)) + goto end; + if (!sk_OPENSSL_STRING_push(reqnames, *args)) + goto end; + } else + badarg = 1; + } else if (!strcmp(*args, "-serial")) { + if (args[1]) { + args++; + if (!cert_id_md) + cert_id_md = EVP_sha1(); + if (!add_ocsp_serial(&req, *args, cert_id_md, issuer, ids)) + goto end; + if (!sk_OPENSSL_STRING_push(reqnames, *args)) + goto end; + } else + badarg = 1; + } else if (!strcmp(*args, "-index")) { + if (args[1]) { + args++; + ridx_filename = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-CA")) { + if (args[1]) { + args++; + rca_filename = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-nmin")) { + if (args[1]) { + args++; + nmin = strtonum(*args, 0, INT_MAX, &errstr); + if (errstr) { + BIO_printf(bio_err, + "Illegal update period %s: %s\n", + *args, errstr); + badarg = 1; + } + } + if (ndays == -1) + ndays = 0; + else + badarg = 1; + } else if (!strcmp(*args, "-nrequest")) { + if (args[1]) { + args++; + accept_count = strtonum(*args, 0, INT_MAX, &errstr); + if (errstr) { + BIO_printf(bio_err, + "Illegal accept count %s: %s\n", + *args, errstr); + badarg = 1; + } + } else + badarg = 1; + } else if (!strcmp(*args, "-ndays")) { + if (args[1]) { + args++; + ndays = strtonum(*args, 0, INT_MAX, &errstr); + if (errstr) { + BIO_printf(bio_err, + "Illegal update period %s: %s\n", + *args, errstr); + badarg = 1; + } + } else + badarg = 1; + } else if (!strcmp(*args, "-rsigner")) { + if (args[1]) { + args++; + rsignfile = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-rkey")) { + if (args[1]) { + args++; + rkeyfile = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-rother")) { + if (args[1]) { + args++; + rcertfile = *args; + } else + badarg = 1; + } else if ((cert_id_md = EVP_get_digestbyname((*args) + 1)) == NULL) { + badarg = 1; + } + args++; + } + + /* Have we anything to do? */ + if (!req && !reqin && !respin && !(port && ridx_filename)) + badarg = 1; + + if (badarg) { + BIO_printf(bio_err, "OCSP utility\n"); + BIO_printf(bio_err, "Usage ocsp [options]\n"); + BIO_printf(bio_err, "where options are\n"); + BIO_printf(bio_err, "-out file output filename\n"); + BIO_printf(bio_err, "-issuer file issuer certificate\n"); + BIO_printf(bio_err, "-cert file certificate to check\n"); + BIO_printf(bio_err, "-serial n serial number to check\n"); + BIO_printf(bio_err, "-signer file certificate to sign OCSP request with\n"); + BIO_printf(bio_err, "-signkey file private key to sign OCSP request with\n"); + BIO_printf(bio_err, "-sign_other file additional certificates to include in signed request\n"); + BIO_printf(bio_err, "-no_certs don't include any certificates in signed request\n"); + BIO_printf(bio_err, "-req_text print text form of request\n"); + BIO_printf(bio_err, "-resp_text print text form of response\n"); + BIO_printf(bio_err, "-text print text form of request and response\n"); + BIO_printf(bio_err, "-reqout file write DER encoded OCSP request to \"file\"\n"); + BIO_printf(bio_err, "-respout file write DER encoded OCSP reponse to \"file\"\n"); + BIO_printf(bio_err, "-reqin file read DER encoded OCSP request from \"file\"\n"); + BIO_printf(bio_err, "-respin file read DER encoded OCSP reponse from \"file\"\n"); + BIO_printf(bio_err, "-nonce add OCSP nonce to request\n"); + BIO_printf(bio_err, "-no_nonce don't add OCSP nonce to request\n"); + BIO_printf(bio_err, "-url URL OCSP responder URL\n"); + BIO_printf(bio_err, "-host host:n send OCSP request to host on port n\n"); + BIO_printf(bio_err, "-path path to use in OCSP request\n"); + BIO_printf(bio_err, "-CApath dir trusted certificates directory\n"); + BIO_printf(bio_err, "-CAfile file trusted certificates file\n"); + BIO_printf(bio_err, "-VAfile file validator certificates file\n"); + BIO_printf(bio_err, "-validity_period n maximum validity discrepancy in seconds\n"); + BIO_printf(bio_err, "-status_age n maximum status age in seconds\n"); + BIO_printf(bio_err, "-noverify don't verify response at all\n"); + BIO_printf(bio_err, "-verify_other file additional certificates to search for signer\n"); + BIO_printf(bio_err, "-trust_other don't verify additional certificates\n"); + BIO_printf(bio_err, "-no_intern don't search certificates contained in response for signer\n"); + BIO_printf(bio_err, "-no_signature_verify don't check signature on response\n"); + BIO_printf(bio_err, "-no_cert_verify don't check signing certificate\n"); + BIO_printf(bio_err, "-no_chain don't chain verify response\n"); + BIO_printf(bio_err, "-no_cert_checks don't do additional checks on signing certificate\n"); + BIO_printf(bio_err, "-port num port to run responder on\n"); + BIO_printf(bio_err, "-index file certificate status index file\n"); + BIO_printf(bio_err, "-CA file CA certificate\n"); + BIO_printf(bio_err, "-rsigner file responder certificate to sign responses with\n"); + BIO_printf(bio_err, "-rkey file responder key to sign responses with\n"); + BIO_printf(bio_err, "-rother file other certificates to include in response\n"); + BIO_printf(bio_err, "-resp_no_certs don't include any certificates in response\n"); + BIO_printf(bio_err, "-nmin n number of minutes before next update\n"); + BIO_printf(bio_err, "-ndays n number of days before next update\n"); + BIO_printf(bio_err, "-resp_key_id identify reponse by signing certificate key ID\n"); + BIO_printf(bio_err, "-nrequest n number of requests to accept (default unlimited)\n"); + BIO_printf(bio_err, "- use specified digest in the request\n"); + goto end; + } + if (outfile) + out = BIO_new_file(outfile, "w"); + else + out = BIO_new_fp(stdout, BIO_NOCLOSE); + + if (!out) { + BIO_printf(bio_err, "Error opening output file\n"); + goto end; + } + if (!req && (add_nonce != 2)) + add_nonce = 0; + + if (!req && reqin) { + derbio = BIO_new_file(reqin, "rb"); + if (!derbio) { + BIO_printf(bio_err, "Error Opening OCSP request file\n"); + goto end; + } + req = d2i_OCSP_REQUEST_bio(derbio, NULL); + BIO_free(derbio); + if (!req) { + BIO_printf(bio_err, "Error reading OCSP request\n"); + goto end; + } + } + if (!req && port) { + acbio = init_responder(port); + if (!acbio) + goto end; + } + if (rsignfile && !rdb) { + if (!rkeyfile) + rkeyfile = rsignfile; + rsigner = load_cert(bio_err, rsignfile, FORMAT_PEM, + NULL, "responder certificate"); + if (!rsigner) { + BIO_printf(bio_err, "Error loading responder certificate\n"); + goto end; + } + rca_cert = load_cert(bio_err, rca_filename, FORMAT_PEM, + NULL, "CA certificate"); + if (rcertfile) { + rother = load_certs(bio_err, rcertfile, FORMAT_PEM, + NULL, "responder other certificates"); + if (!rother) + goto end; + } + rkey = load_key(bio_err, rkeyfile, FORMAT_PEM, 0, NULL, + "responder private key"); + if (!rkey) + goto end; + } + if (acbio) + BIO_printf(bio_err, "Waiting for OCSP client connections...\n"); + +redo_accept: + + if (acbio) { + if (!do_responder(&req, &cbio, acbio, port)) + goto end; + if (!req) { + resp = OCSP_response_create(OCSP_RESPONSE_STATUS_MALFORMEDREQUEST, NULL); + send_ocsp_response(cbio, resp); + goto done_resp; + } + } + if (!req && (signfile || reqout || host || add_nonce || ridx_filename)) { + BIO_printf(bio_err, "Need an OCSP request for this operation!\n"); + goto end; + } + if (req && add_nonce) + OCSP_request_add1_nonce(req, NULL, -1); + + if (signfile) { + if (!keyfile) + keyfile = signfile; + signer = load_cert(bio_err, signfile, FORMAT_PEM, + NULL, "signer certificate"); + if (!signer) { + BIO_printf(bio_err, "Error loading signer certificate\n"); + goto end; + } + if (sign_certfile) { + sign_other = load_certs(bio_err, sign_certfile, FORMAT_PEM, + NULL, "signer certificates"); + if (!sign_other) + goto end; + } + key = load_key(bio_err, keyfile, FORMAT_PEM, 0, NULL, + "signer private key"); + if (!key) + goto end; + + if (!OCSP_request_sign(req, signer, key, NULL, sign_other, sign_flags)) { + BIO_printf(bio_err, "Error signing OCSP request\n"); + goto end; + } + } + if (req_text && req) + OCSP_REQUEST_print(out, req, 0); + + if (reqout) { + derbio = BIO_new_file(reqout, "wb"); + if (!derbio) { + BIO_printf(bio_err, "Error opening file %s\n", reqout); + goto end; + } + i2d_OCSP_REQUEST_bio(derbio, req); + BIO_free(derbio); + } + if (ridx_filename && (!rkey || !rsigner || !rca_cert)) { + BIO_printf(bio_err, "Need a responder certificate, key and CA for this operation!\n"); + goto end; + } + if (ridx_filename && !rdb) { + rdb = load_index(ridx_filename, NULL); + if (!rdb) + goto end; + if (!index_index(rdb)) + goto end; + } + if (rdb) { + i = make_ocsp_response(&resp, req, rdb, rca_cert, rsigner, rkey, rother, rflags, nmin, ndays); + if (cbio) + send_ocsp_response(cbio, resp); + } else if (host) { + resp = process_responder(bio_err, req, host, path, + port, use_ssl, headers, req_timeout); + if (!resp) + goto end; + } else if (respin) { + derbio = BIO_new_file(respin, "rb"); + if (!derbio) { + BIO_printf(bio_err, "Error Opening OCSP response file\n"); + goto end; + } + resp = d2i_OCSP_RESPONSE_bio(derbio, NULL); + BIO_free(derbio); + if (!resp) { + BIO_printf(bio_err, "Error reading OCSP response\n"); + goto end; + } + } else { + ret = 0; + goto end; + } + +done_resp: + + if (respout) { + derbio = BIO_new_file(respout, "wb"); + if (!derbio) { + BIO_printf(bio_err, "Error opening file %s\n", respout); + goto end; + } + i2d_OCSP_RESPONSE_bio(derbio, resp); + BIO_free(derbio); + } + i = OCSP_response_status(resp); + + if (i != OCSP_RESPONSE_STATUS_SUCCESSFUL) { + BIO_printf(bio_err, "Responder Error: %s (%d)\n", + OCSP_response_status_str(i), i); + if (ignore_err) + goto redo_accept; + ret = 1; + goto end; + } + if (resp_text) + OCSP_RESPONSE_print(out, resp, 0); + + /* If running as responder don't verify our own response */ + if (cbio) { + if (accept_count > 0) + accept_count--; + /* Redo if more connections needed */ + if (accept_count) { + BIO_free_all(cbio); + cbio = NULL; + OCSP_REQUEST_free(req); + req = NULL; + OCSP_RESPONSE_free(resp); + resp = NULL; + goto redo_accept; + } + goto end; + } + if (!store) + store = setup_verify(bio_err, CAfile, CApath); + if (!store) + goto end; + if (verify_certfile) { + verify_other = load_certs(bio_err, verify_certfile, FORMAT_PEM, + NULL, "validator certificate"); + if (!verify_other) + goto end; + } + bs = OCSP_response_get1_basic(resp); + + if (!bs) { + BIO_printf(bio_err, "Error parsing response\n"); + goto end; + } + if (!noverify) { + if (req && ((i = OCSP_check_nonce(req, bs)) <= 0)) { + if (i == -1) + BIO_printf(bio_err, "WARNING: no nonce in response\n"); + else { + BIO_printf(bio_err, "Nonce Verify error\n"); + goto end; + } + } + i = OCSP_basic_verify(bs, verify_other, store, verify_flags); + if (i < 0) + i = OCSP_basic_verify(bs, NULL, store, 0); + + if (i <= 0) { + BIO_printf(bio_err, "Response Verify Failure\n"); + ERR_print_errors(bio_err); + } else + BIO_printf(bio_err, "Response verify OK\n"); + + } + if (!print_ocsp_summary(out, bs, req, reqnames, ids, nsec, maxage)) + goto end; + + ret = 0; + +end: + ERR_print_errors(bio_err); + X509_free(signer); + X509_STORE_free(store); + EVP_PKEY_free(key); + EVP_PKEY_free(rkey); + X509_free(issuer); + X509_free(cert); + X509_free(rsigner); + X509_free(rca_cert); + free_index(rdb); + BIO_free_all(cbio); + BIO_free_all(acbio); + BIO_free(out); + OCSP_REQUEST_free(req); + OCSP_RESPONSE_free(resp); + OCSP_BASICRESP_free(bs); + sk_OPENSSL_STRING_free(reqnames); + sk_OCSP_CERTID_free(ids); + sk_X509_pop_free(sign_other, X509_free); + sk_X509_pop_free(verify_other, X509_free); + sk_CONF_VALUE_pop_free(headers, X509V3_conf_free); + + if (use_ssl != -1) { + free(host); + free(port); + free(path); + } + return (ret); +} + +static int +add_ocsp_cert(OCSP_REQUEST ** req, X509 * cert, const EVP_MD * cert_id_md, X509 * issuer, + STACK_OF(OCSP_CERTID) * ids) +{ + OCSP_CERTID *id; + if (!issuer) { + BIO_printf(bio_err, "No issuer certificate specified\n"); + return 0; + } + if (!*req) + *req = OCSP_REQUEST_new(); + if (!*req) + goto err; + id = OCSP_cert_to_id(cert_id_md, cert, issuer); + if (!id || !sk_OCSP_CERTID_push(ids, id)) + goto err; + if (!OCSP_request_add0_id(*req, id)) + goto err; + return 1; + +err: + BIO_printf(bio_err, "Error Creating OCSP request\n"); + return 0; +} + +static int +add_ocsp_serial(OCSP_REQUEST ** req, char *serial, const EVP_MD * cert_id_md, X509 * issuer, + STACK_OF(OCSP_CERTID) * ids) +{ + OCSP_CERTID *id; + X509_NAME *iname; + ASN1_BIT_STRING *ikey; + ASN1_INTEGER *sno; + if (!issuer) { + BIO_printf(bio_err, "No issuer certificate specified\n"); + return 0; + } + if (!*req) + *req = OCSP_REQUEST_new(); + if (!*req) + goto err; + iname = X509_get_subject_name(issuer); + ikey = X509_get0_pubkey_bitstr(issuer); + sno = s2i_ASN1_INTEGER(NULL, serial); + if (!sno) { + BIO_printf(bio_err, "Error converting serial number %s\n", serial); + return 0; + } + id = OCSP_cert_id_new(cert_id_md, iname, ikey, sno); + ASN1_INTEGER_free(sno); + if (!id || !sk_OCSP_CERTID_push(ids, id)) + goto err; + if (!OCSP_request_add0_id(*req, id)) + goto err; + return 1; + +err: + BIO_printf(bio_err, "Error Creating OCSP request\n"); + return 0; +} + +static int +print_ocsp_summary(BIO * out, OCSP_BASICRESP * bs, OCSP_REQUEST * req, + STACK_OF(OPENSSL_STRING) * names, + STACK_OF(OCSP_CERTID) * ids, long nsec, + long maxage) +{ + OCSP_CERTID *id; + char *name; + int i; + + int status, reason; + + ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; + + if (!bs || !req || !sk_OPENSSL_STRING_num(names) || !sk_OCSP_CERTID_num(ids)) + return 1; + + for (i = 0; i < sk_OCSP_CERTID_num(ids); i++) { + id = sk_OCSP_CERTID_value(ids, i); + name = sk_OPENSSL_STRING_value(names, i); + BIO_printf(out, "%s: ", name); + + if (!OCSP_resp_find_status(bs, id, &status, &reason, + &rev, &thisupd, &nextupd)) { + BIO_puts(out, "ERROR: No Status found.\n"); + continue; + } + /* + * Check validity: if invalid write to output BIO so we know + * which response this refers to. + */ + if (!OCSP_check_validity(thisupd, nextupd, nsec, maxage)) { + BIO_puts(out, "WARNING: Status times invalid.\n"); + ERR_print_errors(out); + } + BIO_printf(out, "%s\n", OCSP_cert_status_str(status)); + + BIO_puts(out, "\tThis Update: "); + ASN1_GENERALIZEDTIME_print(out, thisupd); + BIO_puts(out, "\n"); + + if (nextupd) { + BIO_puts(out, "\tNext Update: "); + ASN1_GENERALIZEDTIME_print(out, nextupd); + BIO_puts(out, "\n"); + } + if (status != V_OCSP_CERTSTATUS_REVOKED) + continue; + + if (reason != -1) + BIO_printf(out, "\tReason: %s\n", + OCSP_crl_reason_str(reason)); + + BIO_puts(out, "\tRevocation Time: "); + ASN1_GENERALIZEDTIME_print(out, rev); + BIO_puts(out, "\n"); + } + + return 1; +} + + +static int +make_ocsp_response(OCSP_RESPONSE ** resp, OCSP_REQUEST * req, CA_DB * db, + X509 * ca, X509 * rcert, EVP_PKEY * rkey, + STACK_OF(X509) * rother, unsigned long flags, + int nmin, int ndays) +{ + ASN1_TIME *thisupd = NULL, *nextupd = NULL; + OCSP_CERTID *cid, *ca_id = NULL; + OCSP_BASICRESP *bs = NULL; + int i, id_count, ret = 1; + + id_count = OCSP_request_onereq_count(req); + + if (id_count <= 0) { + *resp = OCSP_response_create(OCSP_RESPONSE_STATUS_MALFORMEDREQUEST, NULL); + goto end; + } + bs = OCSP_BASICRESP_new(); + thisupd = X509_gmtime_adj(NULL, 0); + if (ndays != -1) + nextupd = X509_gmtime_adj(NULL, nmin * 60 + ndays * 3600 * 24); + + /* Examine each certificate id in the request */ + for (i = 0; i < id_count; i++) { + OCSP_ONEREQ *one; + ASN1_INTEGER *serial; + char **inf; + ASN1_OBJECT *cert_id_md_oid; + const EVP_MD *cert_id_md; + one = OCSP_request_onereq_get0(req, i); + cid = OCSP_onereq_get0_id(one); + + OCSP_id_get0_info(NULL, &cert_id_md_oid, NULL, NULL, cid); + + cert_id_md = EVP_get_digestbyobj(cert_id_md_oid); + if (!cert_id_md) { + *resp = OCSP_response_create(OCSP_RESPONSE_STATUS_INTERNALERROR, + NULL); + goto end; + } + if (ca_id) + OCSP_CERTID_free(ca_id); + ca_id = OCSP_cert_to_id(cert_id_md, NULL, ca); + + /* Is this request about our CA? */ + if (OCSP_id_issuer_cmp(ca_id, cid)) { + OCSP_basic_add1_status(bs, cid, + V_OCSP_CERTSTATUS_UNKNOWN, + 0, NULL, + thisupd, nextupd); + continue; + } + OCSP_id_get0_info(NULL, NULL, NULL, &serial, cid); + inf = lookup_serial(db, serial); + if (!inf) + OCSP_basic_add1_status(bs, cid, + V_OCSP_CERTSTATUS_UNKNOWN, + 0, NULL, + thisupd, nextupd); + else if (inf[DB_type][0] == DB_TYPE_VAL) + OCSP_basic_add1_status(bs, cid, + V_OCSP_CERTSTATUS_GOOD, + 0, NULL, + thisupd, nextupd); + else if (inf[DB_type][0] == DB_TYPE_REV) { + ASN1_OBJECT *inst = NULL; + ASN1_TIME *revtm = NULL; + ASN1_GENERALIZEDTIME *invtm = NULL; + OCSP_SINGLERESP *single; + int reason = -1; + unpack_revinfo(&revtm, &reason, &inst, &invtm, inf[DB_rev_date]); + single = OCSP_basic_add1_status(bs, cid, + V_OCSP_CERTSTATUS_REVOKED, + reason, revtm, + thisupd, nextupd); + if (invtm) + OCSP_SINGLERESP_add1_ext_i2d(single, NID_invalidity_date, invtm, 0, 0); + else if (inst) + OCSP_SINGLERESP_add1_ext_i2d(single, NID_hold_instruction_code, inst, 0, 0); + ASN1_OBJECT_free(inst); + ASN1_TIME_free(revtm); + ASN1_GENERALIZEDTIME_free(invtm); + } + } + + OCSP_copy_nonce(bs, req); + + OCSP_basic_sign(bs, rcert, rkey, NULL, rother, flags); + + *resp = OCSP_response_create(OCSP_RESPONSE_STATUS_SUCCESSFUL, bs); + +end: + ASN1_TIME_free(thisupd); + ASN1_TIME_free(nextupd); + OCSP_CERTID_free(ca_id); + OCSP_BASICRESP_free(bs); + return ret; + +} + +static char ** +lookup_serial(CA_DB * db, ASN1_INTEGER * ser) +{ + int i; + BIGNUM *bn = NULL; + char *itmp, *row[DB_NUMBER], **rrow; + for (i = 0; i < DB_NUMBER; i++) + row[i] = NULL; + bn = ASN1_INTEGER_to_BN(ser, NULL); + OPENSSL_assert(bn); /* FIXME: should report an error at this + * point and abort */ + if (BN_is_zero(bn)) + itmp = strdup("00"); + else + itmp = BN_bn2hex(bn); + row[DB_serial] = itmp; + BN_free(bn); + rrow = TXT_DB_get_by_index(db->db, DB_serial, row); + free(itmp); + return rrow; +} + +/* Quick and dirty OCSP server: read in and parse input request */ + +static BIO * +init_responder(char *port) +{ + BIO *acbio = NULL, *bufbio = NULL; + bufbio = BIO_new(BIO_f_buffer()); + if (!bufbio) + goto err; + acbio = BIO_new_accept(port); + if (!acbio) + goto err; + BIO_set_accept_bios(acbio, bufbio); + bufbio = NULL; + + if (BIO_do_accept(acbio) <= 0) { + BIO_printf(bio_err, "Error setting up accept BIO\n"); + ERR_print_errors(bio_err); + goto err; + } + return acbio; + +err: + BIO_free_all(acbio); + BIO_free(bufbio); + return NULL; +} + +static int +do_responder(OCSP_REQUEST ** preq, BIO ** pcbio, BIO * acbio, char *port) +{ + int have_post = 0, len; + OCSP_REQUEST *req = NULL; + char inbuf[1024]; + BIO *cbio = NULL; + + if (BIO_do_accept(acbio) <= 0) { + BIO_printf(bio_err, "Error accepting connection\n"); + ERR_print_errors(bio_err); + return 0; + } + cbio = BIO_pop(acbio); + *pcbio = cbio; + + for (;;) { + len = BIO_gets(cbio, inbuf, sizeof inbuf); + if (len <= 0) + return 1; + /* Look for "POST" signalling start of query */ + if (!have_post) { + if (strncmp(inbuf, "POST", 4)) { + BIO_printf(bio_err, "Invalid request\n"); + return 1; + } + have_post = 1; + } + /* Look for end of headers */ + if ((inbuf[0] == '\r') || (inbuf[0] == '\n')) + break; + } + + /* Try to read OCSP request */ + + req = d2i_OCSP_REQUEST_bio(cbio, NULL); + + if (!req) { + BIO_printf(bio_err, "Error parsing OCSP request\n"); + ERR_print_errors(bio_err); + } + *preq = req; + + return 1; + +} + +static int +send_ocsp_response(BIO * cbio, OCSP_RESPONSE * resp) +{ + static const char http_resp[] = + "HTTP/1.0 200 OK\r\nContent-type: application/ocsp-response\r\n" + "Content-Length: %d\r\n\r\n"; + if (!cbio) + return 0; + BIO_printf(cbio, http_resp, i2d_OCSP_RESPONSE(resp, NULL)); + i2d_OCSP_RESPONSE_bio(cbio, resp); + (void) BIO_flush(cbio); + return 1; +} + +static OCSP_RESPONSE * +query_responder(BIO * err, BIO * cbio, char *path, + STACK_OF(CONF_VALUE) * headers, + OCSP_REQUEST * req, int req_timeout) +{ + int fd; + int rv; + int i; + OCSP_REQ_CTX *ctx = NULL; + OCSP_RESPONSE *rsp = NULL; + struct pollfd pfd[1]; + + if (req_timeout != -1) + BIO_set_nbio(cbio, 1); + + rv = BIO_do_connect(cbio); + + if ((rv <= 0) && ((req_timeout == -1) || !BIO_should_retry(cbio))) { + BIO_puts(err, "Error connecting BIO\n"); + return NULL; + } + if (BIO_get_fd(cbio, &fd) < 0) { + BIO_puts(err, "Can't get connection fd\n"); + goto err; + } + if (req_timeout != -1 && rv <= 0) { + pfd[0].fd = fd; + pfd[0].events = POLLOUT; + rv = poll(pfd, 1, req_timeout * 1000); + if (rv == 0) { + BIO_puts(err, "Timeout on connect\n"); + return NULL; + } + if (rv == -1) { + BIO_puts(err, "Poll error\n"); + return NULL; + } + } + ctx = OCSP_sendreq_new(cbio, path, NULL, -1); + if (!ctx) + return NULL; + + for (i = 0; i < sk_CONF_VALUE_num(headers); i++) { + CONF_VALUE *hdr = sk_CONF_VALUE_value(headers, i); + if (!OCSP_REQ_CTX_add1_header(ctx, hdr->name, hdr->value)) + goto err; + } + + if (!OCSP_REQ_CTX_set1_req(ctx, req)) + goto err; + + for (;;) { + rv = OCSP_sendreq_nbio(&rsp, ctx); + if (rv != -1) + break; + if (req_timeout == -1) + continue; + pfd[0].fd = fd; + if (BIO_should_read(cbio)) + pfd[0].events = POLLIN; + else if (BIO_should_write(cbio)) + pfd[0].events = POLLOUT; + else { + BIO_puts(err, "Unexpected retry condition\n"); + goto err; + } + rv = poll(pfd, 1, req_timeout * 1000); + if (rv == 0) { + BIO_puts(err, "Timeout on request\n"); + break; + } + if (rv == -1 || (pfd[0].revents & (POLLERR|POLLNVAL))) { + BIO_puts(err, "Poll error\n"); + break; + } + } +err: + if (ctx) + OCSP_REQ_CTX_free(ctx); + + return rsp; +} + +OCSP_RESPONSE * +process_responder(BIO * err, OCSP_REQUEST * req, + char *host, char *path, char *port, int use_ssl, + STACK_OF(CONF_VALUE) * headers, + int req_timeout) +{ + BIO *cbio = NULL; + SSL_CTX *ctx = NULL; + OCSP_RESPONSE *resp = NULL; + cbio = BIO_new_connect(host); + if (!cbio) { + BIO_printf(err, "Error creating connect BIO\n"); + goto end; + } + if (port) + BIO_set_conn_port(cbio, port); + if (use_ssl == 1) { + BIO *sbio; + ctx = SSL_CTX_new(SSLv23_client_method()); + if (ctx == NULL) { + BIO_printf(err, "Error creating SSL context.\n"); + goto end; + } + SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); + sbio = BIO_new_ssl(ctx, 1); + cbio = BIO_push(sbio, cbio); + } + resp = query_responder(err, cbio, path, headers, req, req_timeout); + if (!resp) + BIO_printf(bio_err, "Error querying OCSP responder\n"); +end: + if (cbio) + BIO_free_all(cbio); + if (ctx) + SSL_CTX_free(ctx); + return resp; +} + +#endif diff --git a/bin/openssl/openssl.1 b/bin/openssl/openssl.1 new file mode 100644 index 0000000000..a48788bb08 --- /dev/null +++ b/bin/openssl/openssl.1 @@ -0,0 +1,6114 @@ +.\" $OpenBSD: openssl.1,v 1.84 2017/01/03 22:14:41 jmc Exp $ +.\" ==================================================================== +.\" Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" 3. All advertising materials mentioning features or use of this +.\" software must display the following acknowledgment: +.\" "This product includes software developed by the OpenSSL Project +.\" for use in the OpenSSL Toolkit. (http://www.openssl.org/)" +.\" +.\" 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to +.\" endorse or promote products derived from this software without +.\" prior written permission. For written permission, please contact +.\" openssl-core@openssl.org. +.\" +.\" 5. Products derived from this software may not be called "OpenSSL" +.\" nor may "OpenSSL" appear in their names without prior written +.\" permission of the OpenSSL Project. +.\" +.\" 6. Redistributions of any form whatsoever must retain the following +.\" acknowledgment: +.\" "This product includes software developed by the OpenSSL Project +.\" for use in the OpenSSL Toolkit (http://www.openssl.org/)" +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY +.\" EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR +.\" ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +.\" OF THE POSSIBILITY OF SUCH DAMAGE. +.\" ==================================================================== +.\" +.\" This product includes cryptographic software written by Eric Young +.\" (eay@cryptsoft.com). This product includes software written by Tim +.\" Hudson (tjh@cryptsoft.com). +.\" +.\" +.\" Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) +.\" All rights reserved. +.\" +.\" This package is an SSL implementation written +.\" by Eric Young (eay@cryptsoft.com). +.\" The implementation was written so as to conform with Netscapes SSL. +.\" +.\" This library is free for commercial and non-commercial use as long as +.\" the following conditions are aheared to. The following conditions +.\" apply to all code found in this distribution, be it the RC4, RSA, +.\" lhash, DES, etc., code; not just the SSL code. The SSL documentation +.\" included with this distribution is covered by the same copyright terms +.\" except that the holder is Tim Hudson (tjh@cryptsoft.com). +.\" +.\" Copyright remains Eric Young's, and as such any Copyright notices in +.\" the code are not to be removed. +.\" If this package is used in a product, Eric Young should be given attribution +.\" as the author of the parts of the library used. +.\" This can be in the form of a textual message at program startup or +.\" in documentation (online or textual) provided with the package. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" "This product includes cryptographic software written by +.\" Eric Young (eay@cryptsoft.com)" +.\" The word 'cryptographic' can be left out if the rouines from the library +.\" being used are not cryptographic related :-). +.\" 4. If you include any Windows specific code (or a derivative thereof) from +.\" the apps directory (application code) you must include an +.\" acknowledgement: +.\" "This product includes software written by Tim Hudson +.\" (tjh@cryptsoft.com)" +.\" +.\" THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" The licence and distribution terms for any publically available version or +.\" derivative of this code cannot be changed. i.e. this code cannot simply be +.\" copied and put under another distribution licence +.\" [including the GNU Public Licence.] +.\" +.\" OPENSSL +.\" +.Dd $Mdocdate: January 3 2017 $ +.Dt OPENSSL 1 +.Os +.Sh NAME +.Nm openssl +.Nd OpenSSL command line tool +.Sh SYNOPSIS +.Nm +.Cm command +.Op Ar command_opts +.Op Ar command_args +.Pp +.Nm +.Cm list-standard-commands | +.Cm list-message-digest-commands | +.Cm list-cipher-commands | +.Cm list-cipher-algorithms | +.Cm list-message-digest-algorithms | +.Cm list-public-key-algorithms +.Pp +.Nm +.Cm no- Ns Ar command +.Sh DESCRIPTION +.Nm OpenSSL +is a cryptography toolkit implementing the +Transport Layer Security +.Pq TLS v1 +network protocol, +as well as related cryptography standards. +.Pp +The +.Nm +program is a command line tool for using the various +cryptography functions of +.Nm openssl Ns 's +crypto library from the shell. +.Pp +The pseudo-commands +.Cm list-standard-commands , list-message-digest-commands , +and +.Cm list-cipher-commands +output a list +.Pq one entry per line +of the names of all standard commands, message digest commands, +or cipher commands, respectively, that are available in the present +.Nm +utility. +.Pp +The pseudo-commands +.Cm list-cipher-algorithms +and +.Cm list-message-digest-algorithms +list all cipher and message digest names, +one entry per line. +Aliases are listed as: +.Pp +.D1 from => to +.Pp +The pseudo-command +.Cm list-public-key-algorithms +lists all supported public key algorithms. +.Pp +The pseudo-command +.Cm no- Ns Ar command +tests whether a command of the +specified name is available. +If +.Ar command +does not exist, +it returns 0 +and prints +.Cm no- Ns Ar command ; +otherwise it returns 1 and prints +.Ar command . +In both cases, the output goes to stdout and nothing is printed to stderr. +Additional command line arguments are always ignored. +Since for each cipher there is a command of the same name, +this provides an easy way for shell scripts to test for the +availability of ciphers in the +.Nm +program. +.Pp +.Sy Note : +.Cm no- Ns Ar command +is not able to detect pseudo-commands such as +.Cm quit , +.Cm list- Ns Ar ... Ns Cm -commands , +or +.Cm no- Ns Ar command +itself. +.Sh ASN1PARSE +.nr nS 1 +.Nm "openssl asn1parse" +.Op Fl i +.Op Fl dlimit Ar number +.Op Fl dump +.Op Fl genconf Ar file +.Op Fl genstr Ar str +.Op Fl in Ar file +.Op Fl inform Cm der | pem | txt +.Op Fl length Ar number +.Op Fl noout +.Op Fl offset Ar number +.Op Fl oid Ar file +.Op Fl out Ar file +.Op Fl strparse Ar offset +.nr nS 0 +.Pp +The +.Nm asn1parse +command is a diagnostic utility that can parse ASN.1 structures. +It can also be used to extract data from ASN.1 formatted data. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl dlimit Ar number +Dump the first +.Ar number +bytes of unknown data in hex form. +.It Fl dump +Dump unknown data in hex form. +.It Fl genconf Ar file , Fl genstr Ar str +Generate encoded data based on string +.Ar str , +file +.Ar file , +or both, using the format described in +.Xr ASN1_generate_nconf 3 . +If only +.Ar file +is present then the string is obtained from the default section +using the name +.Dq asn1 . +The encoded data is passed through the ASN.1 parser and printed out as +though it came from a file; +the contents can thus be examined and written to a file using the +.Fl out +option. +.It Fl i +Indent the output according to the +.Qq depth +of the structures. +.It Fl in Ar file +The input file to read from, or standard input if not specified. +.It Fl inform Cm der | pem | txt +The input format. +.It Fl length Ar number +Number of bytes to parse; the default is until end of file. +.It Fl noout +Do not output the parsed version of the input file. +.It Fl offset Ar number +Starting offset to begin parsing; the default is start of file. +.It Fl oid Ar file +A file containing additional object identifiers +.Pq OIDs . +If an OID +.Pq object identifier +is not part of +.Nm openssl Ns 's +internal table it will be represented in +numerical form +.Pq for example 1.2.3.4 . +.Pp +Each line consists of three columns: +the first column is the OID in numerical format and should be followed by +whitespace. +The second column is the +.Qq short name , +which is a single word followed by whitespace. +The final column is the rest of the line and is the +.Qq long name . +.Nm asn1parse +displays the long name. +.It Fl out Ar file +The DER-encoded output file; the default is no encoded output +(useful when combined with +.Fl strparse ) . +.It Fl strparse Ar offset +Parse the content octets of the ASN.1 object starting at +.Ar offset . +This option can be used multiple times to +.Qq drill down +into a nested structure. +.El +.Sh CA +.nr nS 1 +.Nm "openssl ca" +.Op Fl batch +.Op Fl cert Ar file +.Op Fl config Ar file +.Op Fl crl_CA_compromise Ar time +.Op Fl crl_compromise Ar time +.Op Fl crl_hold Ar instruction +.Op Fl crl_reason Ar reason +.Op Fl crldays Ar days +.Op Fl crlexts Ar section +.Op Fl crlhours Ar hours +.Op Fl days Ar arg +.Op Fl enddate Ar date +.Op Fl extensions Ar section +.Op Fl extfile Ar section +.Op Fl gencrl +.Op Fl in Ar file +.Op Fl infiles +.Op Fl key Ar keyfile +.Op Fl keyfile Ar arg +.Op Fl keyform Ar pem +.Op Fl md Ar arg +.Op Fl msie_hack +.Op Fl name Ar section +.Op Fl noemailDN +.Op Fl notext +.Op Fl out Ar file +.Op Fl outdir Ar dir +.Op Fl passin Ar arg +.Op Fl policy Ar arg +.Op Fl preserveDN +.Op Fl revoke Ar file +.Op Fl spkac Ar file +.Op Fl ss_cert Ar file +.Op Fl startdate Ar date +.Op Fl status Ar serial +.Op Fl subj Ar arg +.Op Fl updatedb +.Op Fl verbose +.nr nS 0 +.Pp +The +.Nm ca +command is a minimal certificate authority (CA) application. +It can be used to sign certificate requests in a variety of forms +and generate certificate revocation lists (CRLs). +It also maintains a text database of issued certificates and their status. +.Pp +The options relevant to CAs are as follows: +.Bl -tag -width "XXXX" +.It Fl batch +Batch mode. +In this mode no questions will be asked +and all certificates will be certified automatically. +.It Fl cert Ar file +The CA certificate file. +.It Fl config Ar file +Specify an alternative configuration file. +.It Fl days Ar arg +The number of days to certify the certificate for. +.It Fl enddate Ar date +Set the expiry date. +The format of the date is YYMMDDHHMMSSZ +.Pq the same as an ASN.1 UTCTime structure . +.It Fl extensions Ar section +The section of the configuration file containing certificate extensions +to be added when a certificate is issued (defaults to +.Cm x509_extensions +unless the +.Fl extfile +option is used). +If no extension section is present, a V1 certificate is created. +If the extension section is present +.Pq even if it is empty , +then a V3 certificate is created. +.It Fl extfile Ar file +An additional configuration +.Ar file +to read certificate extensions from +(using the default section unless the +.Fl extensions +option is also used). +.It Fl in Ar file +An input +.Ar file +containing a single certificate request to be signed by the CA. +.It Fl infiles +If present, this should be the last option; all subsequent arguments +are assumed to be the names of files containing certificate requests. +.It Fl key Ar keyfile +The password used to encrypt the private key. +Since on some systems the command line arguments are visible, +this option should be used with caution. +.It Fl keyfile Ar file +The private key to sign requests with. +.It Fl keyform Ar pem +Private key file format. +.It Fl md Ar alg +The message digest to use. +Possible values include +.Ar md5 +and +.Ar sha1 . +This option also applies to CRLs. +.It Fl msie_hack +This is a legacy option to make +.Nm ca +work with very old versions of the IE certificate enrollment control +.Qq certenr3 . +It used UniversalStrings for almost everything. +Since the old control has various security bugs, +its use is strongly discouraged. +The newer control +.Qq Xenroll +does not need this option. +.It Fl name Ar section +Specifies the configuration file +.Ar section +to use (overrides +.Cm default_ca +in the +.Cm ca +section). +.It Fl noemailDN +The DN of a certificate can contain the EMAIL field if present in the +request DN, however it is good policy just having the email set into +the +.Cm altName +extension of the certificate. +When this option is set, the EMAIL field is removed from the certificate's +subject and set only in the, eventually present, extensions. +The +.Ar email_in_dn +keyword can be used in the configuration file to enable this behaviour. +.It Fl notext +Don't output the text form of a certificate to the output file. +.It Fl out Ar file +The output file to output certificates to. +The default is standard output. +The certificate details will also be printed out to this file. +.It Fl outdir Ar directory +The +.Ar directory +to output certificates to. +The certificate will be written to a file consisting of the +serial number in hex with +.Qq .pem +appended. +.It Fl passin Ar arg +The key password source. +.It Fl policy Ar arg +Define the CA +.Qq policy +to use. +The policy section in the configuration file +consists of a set of variables corresponding to certificate DN fields. +The values may be one of +.Qq match +(the value must match the same field in the CA certificate), +.Qq supplied +(the value must be present), or +.Qq optional +(the value may be present). +Any fields not mentioned in the policy section +are silently deleted, unless the +.Fl preserveDN +option is set, +but this can be regarded more of a quirk than intended behaviour. +.It Fl preserveDN +Normally, the DN order of a certificate is the same as the order of the +fields in the relevant policy section. +When this option is set, the order is the same as the request. +This is largely for compatibility with the older IE enrollment control +which would only accept certificates if their DNs matched the order of the +request. +This is not needed for Xenroll. +.It Fl spkac Ar file +A file containing a single Netscape signed public key and challenge, +and additional field values to be signed by the CA. +This will usually come from the +KEYGEN tag in an HTML form to create a new private key. +It is, however, possible to create SPKACs using the +.Nm spkac +utility. +.Pp +The file should contain the variable SPKAC set to the value of +the SPKAC and also the required DN components as name value pairs. +If it's necessary to include the same component twice, +then it can be preceded by a number and a +.Sq \&. . +.It Fl ss_cert Ar file +A single self-signed certificate to be signed by the CA. +.It Fl startdate Ar date +Set the start date. +The format of the date is YYMMDDHHMMSSZ +.Pq the same as an ASN.1 UTCTime structure . +.It Fl status Ar serial +Show the status of the certificate with serial number +.Ar serial . +.It Fl updatedb +Update database for expired certificates. +.It Fl verbose +Print extra details about the operations being performed. +.El +.Pp +The options relevant to CRLs are as follows: +.Bl -tag -width "XXXX" +.It Fl crl_CA_compromise Ar time +This is the same as +.Fl crl_compromise , +except the revocation reason is set to CACompromise. +.It Fl crl_compromise Ar time +Set the revocation reason to keyCompromise and the compromise time to +.Ar time . +.Ar time +should be in GeneralizedTime format, i.e. YYYYMMDDHHMMSSZ. +.It Fl crl_hold Ar instruction +Set the CRL revocation reason code to certificateHold and the hold +instruction to +.Ar instruction +which must be an OID. +Although any OID can be used, only holdInstructionNone +(the use of which is discouraged by RFC 2459), holdInstructionCallIssuer or +holdInstructionReject will normally be used. +.It Fl crl_reason Ar reason +Revocation reason, where +.Ar reason +is one of: +unspecified, keyCompromise, CACompromise, affiliationChanged, superseded, +cessationOfOperation, certificateHold or removeFromCRL. +The matching of +.Ar reason +is case insensitive. +Setting any revocation reason will make the CRL v2. +In practice, removeFromCRL is not particularly useful because it is only used +in delta CRLs which are not currently implemented. +.It Fl crldays Ar num +The number of days before the next CRL is due. +This is the days from now to place in the CRL +.Cm nextUpdate +field. +.It Fl crlexts Ar section +The +.Ar section +of the configuration file containing CRL extensions to include. +If no CRL extension section is present then a V1 CRL is created; +if the CRL extension section is present +(even if it is empty) +then a V2 CRL is created. +The CRL extensions specified are CRL extensions and not CRL entry extensions. +It should be noted that some software can't handle V2 CRLs. +.It Fl crlhours Ar num +The number of hours before the next CRL is due. +.It Fl gencrl +Generate a CRL based on information in the index file. +.It Fl revoke Ar file +A +.Ar file +containing a certificate to revoke. +.It Fl subj Ar arg +Supersedes the subject name given in the request. +The +.Ar arg +must be formatted as +.Ar /type0=value0/type1=value1/type2=... ; +characters may be escaped by +.Sq \e +.Pq backslash , +no spaces are skipped. +.El +.Pp +Many of the options can be set in the +.Cm ca +section of the configuration file +(or in the default section of the configuration file), +specified using +.Cm default_ca +or +.Fl name . +The options +.Cm preserve +and +.Cm msie_hack +are read directly from the +.Cm ca +section. +.Pp +Many of the configuration file options are identical to command line +options. +Where the option is present in the configuration file and the command line, +the command line value is used. +Where an option is described as mandatory, then it must be present in +the configuration file or the command line equivalent +.Pq if any +used. +.Bl -tag -width "XXXX" +.It Cm certificate +The same as +.Fl cert . +It gives the file containing the CA certificate. +Mandatory. +.It Cm copy_extensions +Determines how extensions in certificate requests should be handled. +If set to +.Cm none +or this option is not present, then extensions are +ignored and not copied to the certificate. +If set to +.Cm copy , +then any extensions present in the request that are not already present +are copied to the certificate. +If set to +.Cm copyall , +then all extensions in the request are copied to the certificate: +if the extension is already present in the certificate it is deleted first. +.Pp +The +.Cm copy_extensions +option should be used with caution. +If care is not taken, it can be a security risk. +For example, if a certificate request contains a +.Cm basicConstraints +extension with CA:TRUE and the +.Cm copy_extensions +value is set to +.Cm copyall +and the user does not spot +this when the certificate is displayed, then this will hand the requestor +a valid CA certificate. +.Pp +This situation can be avoided by setting +.Cm copy_extensions +to +.Cm copy +and including +.Cm basicConstraints +with CA:FALSE in the configuration file. +Then if the request contains a +.Cm basicConstraints +extension, it will be ignored. +.Pp +The main use of this option is to allow a certificate request to supply +values for certain extensions such as +.Cm subjectAltName . +.It Cm crl_extensions +The same as +.Fl crlexts . +.It Cm crlnumber +A text file containing the next CRL number to use in hex. +The CRL number will be inserted in the CRLs only if this file exists. +If this file is present, it must contain a valid CRL number. +.It Cm database +The text database file to use. +Mandatory. +This file must be present, though initially it will be empty. +.It Cm default_crl_hours , default_crl_days +The same as the +.Fl crlhours +and +.Fl crldays +options. +These will only be used if neither command line option is present. +At least one of these must be present to generate a CRL. +.It Cm default_days +The same as the +.Fl days +option. +The number of days to certify a certificate for. +.It Cm default_enddate +The same as the +.Fl enddate +option. +Either this option or +.Cm default_days +.Pq or the command line equivalents +must be present. +.It Cm default_md +The same as the +.Fl md +option. +The message digest to use. +Mandatory. +.It Cm default_startdate +The same as the +.Fl startdate +option. +The start date to certify a certificate for. +If not set, the current time is used. +.It Cm email_in_dn +The same as +.Fl noemailDN . +If the EMAIL field is to be removed from the DN of the certificate, +simply set this to +.Qq no . +If not present, the default is to allow for the EMAIL field in the +certificate's DN. +.It Cm msie_hack +The same as +.Fl msie_hack . +.It Cm name_opt , cert_opt +These options allow the format used to display the certificate details +when asking the user to confirm signing. +All the options supported by the +.Nm x509 +utilities' +.Fl nameopt +and +.Fl certopt +switches can be used here, except that +.Cm no_signame +and +.Cm no_sigdump +are permanently set and cannot be disabled +(this is because the certificate signature cannot be displayed because +the certificate has not been signed at this point). +.Pp +For convenience, the value +.Cm ca_default +is accepted by both to produce a reasonable output. +.Pp +If neither option is present, the format used in earlier versions of +.Nm openssl +is used. +Use of the old format is strongly discouraged +because it only displays fields mentioned in the +.Cm policy +section, +mishandles multicharacter string types and does not display extensions. +.It Cm new_certs_dir +The same as the +.Fl outdir +command line option. +It specifies the directory where new certificates will be placed. +Mandatory. +.It Cm oid_file +This specifies a file containing additional object identifiers. +Each line of the file should consist of the numerical form of the +object identifier followed by whitespace, then the short name followed +by whitespace and finally the long name. +.It Cm oid_section +This specifies a section in the configuration file containing extra +object identifiers. +Each line should consist of the short name of the object identifier +followed by +.Sq = +and the numerical form. +The short and long names are the same when this option is used. +.It Cm policy +The same as +.Fl policy . +Mandatory. +.It Cm preserve +The same as +.Fl preserveDN . +.It Cm private_key +Same as the +.Fl keyfile +option. +The file containing the CA private key. +Mandatory. +.It Cm serial +A text file containing the next serial number to use in hex. +Mandatory. +This file must be present and contain a valid serial number. +.It Cm unique_subject +If the value +.Cm yes +is given, the valid certificate entries in the +database must have unique subjects. +If the value +.Cm no +is given, +several valid certificate entries may have the exact same subject. +The default value is +.Cm yes . +.It Cm x509_extensions +The same as +.Fl extensions . +.El +.Sh CIPHERS +.Nm openssl ciphers +.Op Fl hVv +.Op Fl tls1 +.Op Ar cipherlist +.Pp +The +.Nm ciphers +command converts +.Nm openssl +cipher lists into ordered SSL cipher preference lists. +It can be used as a way to determine the appropriate cipher list. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl h , \&? +Print a brief usage message. +.It Fl tls1 +Only include TLS v1 ciphers. +.It Fl V +Verbose. +List ciphers with a complete description of protocol version, +key exchange, authentication, encryption and mac algorithms, +any key size restrictions, +and cipher suite codes (hex format). +.It Fl v +Like +.Fl V , +but without cipher suite codes. +.It Ar cipherlist +A cipher list to convert to a cipher preference list. +If it is not included, the default cipher list will be used. +.Pp +The cipher list consists of one or more cipher strings +separated by colons. +Commas or spaces are also acceptable separators, but colons are normally used. +.Pp +The actual cipher string can take several different forms: +.Pp +It can consist of a single cipher suite, such as RC4-SHA. +.Pp +It can represent a list of cipher suites containing a certain algorithm, +or cipher suites of a certain type. +For example SHA1 represents all cipher suites using the digest algorithm SHA1. +.Pp +Lists of cipher suites can be combined in a single cipher string using the +.Sq + +character +(logical AND operation). +For example, SHA1+DES represents all cipher suites +containing the SHA1 and DES algorithms. +.Pp +Each cipher string can be optionally preceded by the characters +.Sq \&! , +.Sq - , +or +.Sq + . +If +.Sq !\& +is used, then the ciphers are permanently deleted from the list. +The ciphers deleted can never reappear in the list even if they are +explicitly stated. +If +.Sq - +is used, then the ciphers are deleted from the list, but some or +all of the ciphers can be added again by later options. +If +.Sq + +is used, then the ciphers are moved to the end of the list. +This option doesn't add any new ciphers, it just moves matching existing ones. +.Pp +If none of these characters is present, the string is just interpreted +as a list of ciphers to be appended to the current preference list. +If the list includes any ciphers already present, they will be ignored; +that is, they will not be moved to the end of the list. +.Pp +Additionally, the cipher string +.Cm @STRENGTH +can be used at any point to sort the current cipher list in order of +encryption algorithm key length. +.El +.Pp +The following is a list of all permitted cipher strings and their meanings. +.Bl -tag -width "XXXX" +.It Cm DEFAULT +The default cipher list. +This is determined at compile time and is currently +.Cm ALL:!aNULL:!eNULL:!SSLv2 . +This must be the first cipher string specified. +.It Cm COMPLEMENTOFDEFAULT +The ciphers included in +.Cm ALL , +but not enabled by default. +Currently this is +.Cm ADH . +Note that this rule does not cover +.Cm eNULL , +which is not included by +.Cm ALL +(use +.Cm COMPLEMENTOFALL +if necessary). +.It Cm ALL +All cipher suites except the +.Cm eNULL +ciphers, which must be explicitly enabled. +.It Cm COMPLEMENTOFALL +The cipher suites not enabled by +.Cm ALL , +currently being +.Cm eNULL . +.It Cm HIGH +.Qq High +encryption cipher suites. +This currently means those with key lengths larger than 128 bits. +.It Cm MEDIUM +.Qq Medium +encryption cipher suites, currently those using 128-bit encryption. +.It Cm LOW +.Qq Low +encryption cipher suites, currently those using 64- or 56-bit encryption +algorithms. +.It Cm eNULL , NULL +The +.Qq NULL +ciphers; that is, those offering no encryption. +Because these offer no encryption at all and are a security risk, +they are disabled unless explicitly included. +.It Cm aNULL +The cipher suites offering no authentication. +This is currently the anonymous DH algorithms. +These cipher suites are vulnerable to a +.Qq man in the middle +attack, so their use is normally discouraged. +.It Cm kRSA , RSA +Cipher suites using RSA key exchange. +.It Cm kEDH +Cipher suites using ephemeral DH key agreement. +.It Cm aRSA +Cipher suites using RSA authentication, i.e. the certificates carry RSA keys. +.It Cm aDSS , DSS +Cipher suites using DSS authentication, i.e. the certificates carry DSS keys. +.It Cm TLSv1 +TLS v1.0 cipher suites. +.It Cm DH +Cipher suites using DH, including anonymous DH. +.It Cm ADH +Anonymous DH cipher suites. +.It Cm AES +Cipher suites using AES. +.It Cm 3DES +Cipher suites using triple DES. +.It Cm DES +Cipher suites using DES +.Pq not triple DES . +.It Cm RC4 +Cipher suites using RC4. +.It Cm CAMELLIA +Cipher suites using Camellia. +.It Cm CHACHA20 +Cipher suites using ChaCha20. +.It Cm IDEA +Cipher suites using IDEA. +.It Cm MD5 +Cipher suites using MD5. +.It Cm SHA1 , SHA +Cipher suites using SHA1. +.El +.Sh CRL +.nr nS 1 +.Nm "openssl crl" +.Op Fl CAfile Ar file +.Op Fl CApath Ar dir +.Op Fl fingerprint +.Op Fl hash +.Op Fl in Ar file +.Op Fl inform Cm der | pem +.Op Fl issuer +.Op Fl lastupdate +.Op Fl nextupdate +.Op Fl noout +.Op Fl out Ar file +.Op Fl outform Cm der | pem +.Op Fl text +.nr nS 0 +.Pp +The +.Nm crl +command processes CRL files in DER or PEM format. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl CAfile Ar file +Verify the signature on a CRL by looking up the issuing certificate in +.Ar file . +.It Fl CApath Ar directory +Verify the signature on a CRL by looking up the issuing certificate in +.Ar dir . +This directory must be a standard certificate directory, +i.e. a hash of each subject name (using +.Cm x509 Fl hash ) +should be linked to each certificate. +.It Fl fingerprint +Print the CRL fingerprint. +.It Fl hash +Output a hash of the issuer name. +This can be used to look up CRLs in a directory by issuer name. +.It Fl in Ar file +The input file to read from, or standard input if not specified. +.It Fl inform Cm der | pem +The input format. +.It Fl issuer +Output the issuer name. +.It Fl lastupdate +Output the +.Cm lastUpdate +field. +.It Fl nextupdate +Output the +.Cm nextUpdate +field. +.It Fl noout +Do not output the encoded version of the CRL. +.It Fl out Ar file +The output file to write to, or standard output if not specified. +.It Fl outform Cm der | pem +The output format. +.It Fl text +Print the CRL in plain text. +.El +.Sh CRL2PKCS7 +.nr nS 1 +.Nm "openssl crl2pkcs7" +.Op Fl certfile Ar file +.Op Fl in Ar file +.Op Fl inform Cm der | pem +.Op Fl nocrl +.Op Fl out Ar file +.Op Fl outform Cm der | pem +.nr nS 0 +.Pp +The +.Nm crl2pkcs7 +command takes an optional CRL and one or more +certificates and converts them into a PKCS#7 degenerate +.Qq certificates only +structure. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl certfile Ar file +Add the certificates in PEM +.Ar file +to the PKCS#7 structure. +This option can be used more than once +to read certificates from multiple files. +.It Fl in Ar file +Read the CRL from +.Ar file , +or standard input if not specified. +.It Fl inform Cm der | pem +The input format. +.It Fl nocrl +Normally, a CRL is included in the output file. +With this option, no CRL is +included in the output file and a CRL is not read from the input file. +.It Fl out Ar file +Write the PKCS#7 structure to +.Ar file , +or standard output if not specified. +.It Fl outform Cm der | pem +The output format. +.El +.Sh DGST +.nr nS 1 +.Nm "openssl dgst" +.Op Fl cd +.Op Fl binary +.Op Fl Ar digest +.Op Fl hex +.Op Fl hmac Ar key +.Op Fl keyform Cm pem +.Op Fl mac Ar algorithm +.Op Fl macopt Ar nm : Ns Ar v +.Op Fl out Ar file +.Op Fl passin Ar arg +.Op Fl prverify Ar file +.Op Fl sign Ar file +.Op Fl signature Ar file +.Op Fl sigopt Ar nm : Ns Ar v +.Op Fl verify Ar file +.Op Ar +.nr nS 0 +.Pp +The digest functions output the message digest of a supplied +.Ar file +or +.Ar files +in hexadecimal form. +They can also be used for digital signing and verification. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl binary +Output the digest or signature in binary form. +.It Fl c +Print the digest in two-digit groups separated by colons. +.It Fl d +Print BIO debugging information. +.It Fl Ar digest +Use the specified message +.Ar digest . +The default is MD5. +The available digests can be displayed using +.Nm openssl +.Cm list-message-digest-commands . +The following are equivalent: +.Nm openssl dgst +.Fl md5 +and +.Nm openssl +.Cm md5 . +.It Fl hex +Digest is to be output as a hex dump. +This is the default case for a +.Qq normal +digest as opposed to a digital signature. +.It Fl hmac Ar key +Create a hashed MAC using +.Ar key . +.It Fl keyform Cm pem +Specifies the key format to sign the digest with. +.It Fl mac Ar algorithm +Create a keyed Message Authentication Code (MAC). +The most popular MAC algorithm is HMAC (hash-based MAC), +but there are other MAC algorithms which are not based on hash. +MAC keys and other options should be set via the +.Fl macopt +parameter. +.It Fl macopt Ar nm : Ns Ar v +Passes options to the MAC algorithm, specified by +.Fl mac . +The following options are supported by HMAC: +.Bl -tag -width Ds +.It Cm key : Ns Ar string +Specifies the MAC key as an alphanumeric string +(use if the key contain printable characters only). +String length must conform to any restrictions of the MAC algorithm. +.It Cm hexkey : Ns Ar string +Specifies the MAC key in hexadecimal form (two hex digits per byte). +Key length must conform to any restrictions of the MAC algorithm. +.El +.It Fl out Ar file +The output file to write to, +or standard output if not specified. +.It Fl passin Ar arg +The key password source. +.It Fl prverify Ar file +Verify the signature using the private key in +.Ar file . +The output is either +.Qq Verification OK +or +.Qq Verification Failure . +.It Fl sign Ar file +Digitally sign the digest using the private key in +.Ar file . +.It Fl signature Ar file +The actual signature to verify. +.It Fl sigopt Ar nm : Ns Ar v +Pass options to the signature algorithm during sign or verify operations. +The names and values of these options are algorithm-specific. +.It Fl verify Ar file +Verify the signature using the public key in +.Ar file . +The output is either +.Qq Verification OK +or +.Qq Verification Failure . +.It Ar +File or files to digest. +If no files are specified then standard input is used. +.El +.Sh DHPARAM +.nr nS 1 +.Nm "openssl dhparam" +.Op Fl 2 | 5 +.Op Fl C +.Op Fl check +.Op Fl dsaparam +.Op Fl in Ar file +.Op Fl inform Cm der | pem +.Op Fl noout +.Op Fl out Ar file +.Op Fl outform Cm der | pem +.Op Fl text +.Op Ar numbits +.nr nS 0 +.Pp +The +.Nm dhparam +command is used to manipulate DH parameter files. +Only the older PKCS#3 DH is supported, +not the newer X9.42 DH. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl 2 , 5 +The generator to use; +2 is the default. +If present, the input file is ignored and parameters are generated instead. +.It Fl C +Convert the parameters into C code. +The parameters can then be loaded by calling the +.No get_dh Ns Ar numbits +function. +.It Fl check +Check the DH parameters. +.It Fl dsaparam +Read or create DSA parameters, +converted to DH format on output. +Otherwise, +.Qq strong +primes +.Pq such that (p-1)/2 is also prime +will be used for DH parameter generation. +.Pp +DH parameter generation with the +.Fl dsaparam +option is much faster, +and the recommended exponent length is shorter, +which makes DH key exchange more efficient. +Beware that with such DSA-style DH parameters, +a fresh DH key should be created for each use to +avoid small-subgroup attacks that may be possible otherwise. +.It Fl in Ar file +The input file to read from, +or standard input if not specified. +.It Fl inform Cm der | pem +The input format. +.It Fl noout +Do not output the encoded version of the parameters. +.It Fl out Ar file +The output file to write to, +or standard output if not specified. +.It Fl outform Cm der | pem +The output format. +.It Fl text +Print the DH parameters in plain text. +.It Ar numbits +Generate a parameter set of size +.Ar numbits . +It must be the last option. +If not present, a value of 2048 is used. +If this value is present, the input file is ignored and +parameters are generated instead. +.El +.Sh DSA +.nr nS 1 +.Nm "openssl dsa" +.Oo +.Fl aes128 | aes192 | aes256 | +.Fl des | des3 +.Oc +.Op Fl in Ar file +.Op Fl inform Cm der | pem +.Op Fl modulus +.Op Fl noout +.Op Fl out Ar file +.Op Fl outform Cm der | pem +.Op Fl passin Ar arg +.Op Fl passout Ar arg +.Op Fl pubin +.Op Fl pubout +.Op Fl text +.nr nS 0 +.Pp +The +.Nm dsa +command processes DSA keys. +They can be converted between various forms and their components printed out. +.Pp +.Sy Note : +This command uses the traditional +.Nm SSLeay +compatible format for private key encryption: +newer applications should use the more secure PKCS#8 format using the +.Nm pkcs8 +command. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Xo +.Fl aes128 | aes192 | aes256 | +.Fl des | des3 +.Xc +Encrypt the private key with the AES, DES, or the triple DES +ciphers, respectively, before outputting it. +A pass phrase is prompted for. +If none of these options are specified, the key is written in plain text. +This means that using the +.Nm dsa +utility to read an encrypted key with no encryption option can be used to +remove the pass phrase from a key, +or by setting the encryption options it can be used to add or change +the pass phrase. +These options can only be used with PEM format output files. +.It Fl in Ar file +The input file to read from, +or standard input if not specified. +If the key is encrypted, a pass phrase will be prompted for. +.It Fl inform Cm der | pem +The input format. +.It Fl modulus +Print the value of the public key component of the key. +.It Fl noout +Do not output the encoded version of the key. +.It Fl out Ar file +The output file to write to, +or standard output if not specified. +If any encryption options are set then a pass phrase will be +prompted for. +.It Fl outform Cm der | pem +The output format. +.It Fl passin Ar arg +The key password source. +.It Fl passout Ar arg +The output file password source. +.It Fl pubin +Read in a public key, not a private key. +.It Fl pubout +Output a public key, not a private key. +Automatically set if the input is a public key. +.It Fl text +Print the public/private key in plain text. +.El +.Sh DSAPARAM +.nr nS 1 +.Nm "openssl dsaparam" +.Op Fl C +.Op Fl genkey +.Op Fl in Ar file +.Op Fl inform Cm der | pem +.Op Fl noout +.Op Fl out Ar file +.Op Fl outform Cm der | pem +.Op Fl text +.Op Ar numbits +.nr nS 0 +.Pp +The +.Nm dsaparam +command is used to manipulate or generate DSA parameter files. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl C +Convert the parameters into C code. +The parameters can then be loaded by calling the +.No get_dsa Ns Ar XXX +function. +.It Fl genkey +Generate a DSA key either using the specified or generated +parameters. +.It Fl in Ar file +The input file to read from, +or standard input if not specified. +If the +.Ar numbits +parameter is included, then this option is ignored. +.It Fl inform Cm der | pem +The input format. +.It Fl noout +Do not output the encoded version of the parameters. +.It Fl out Ar file +The output file to write to, +or standard output if not specified. +.It Fl outform Cm der | pem +The output format. +.It Fl text +Print the DSA parameters in plain text. +.It Ar numbits +Generate a parameter set of size +.Ar numbits . +If this option is included, the input file is ignored. +.El +.Sh EC +.nr nS 1 +.Nm "openssl ec" +.Op Fl conv_form Ar arg +.Op Fl des +.Op Fl des3 +.Op Fl in Ar file +.Op Fl inform Cm der | pem +.Op Fl noout +.Op Fl out Ar file +.Op Fl outform Cm der | pem +.Op Fl param_enc Ar arg +.Op Fl param_out +.Op Fl passin Ar arg +.Op Fl passout Ar arg +.Op Fl pubin +.Op Fl pubout +.Op Fl text +.nr nS 0 +.Pp +The +.Nm ec +command processes EC keys. +They can be converted between various +forms and their components printed out. +.Nm openssl +uses the private key format specified in +.Dq SEC 1: Elliptic Curve Cryptography +.Pq Lk http://www.secg.org/ . +To convert an +EC private key into the PKCS#8 private key format use the +.Nm pkcs8 +command. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl conv_form Ar arg +Specify how the points on the elliptic curve are converted +into octet strings. +Possible values are: +.Cm compressed +(the default), +.Cm uncompressed , +and +.Cm hybrid . +For more information regarding +the point conversion forms see the X9.62 standard. +Note: +Due to patent issues the +.Cm compressed +option is disabled by default for binary curves +and can be enabled by defining the preprocessor macro +.Dv OPENSSL_EC_BIN_PT_COMP +at compile time. +.It Fl des | des3 +Encrypt the private key with DES, triple DES, or +any other cipher supported by +.Nm openssl . +A pass phrase is prompted for. +If none of these options is specified the key is written in plain text. +This means that using the +.Nm ec +utility to read in an encrypted key with no +encryption option can be used to remove the pass phrase from a key, +or by setting the encryption options +it can be used to add or change the pass phrase. +These options can only be used with PEM format output files. +.It Fl in Ar file +The input file to read a key from, +or standard input if not specified. +If the key is encrypted a pass phrase will be prompted for. +.It Fl inform Cm der | pem +The input format. +.It Fl noout +Do not output the encoded version of the key. +.It Fl out Ar file +The output filename to write to, +or standard output if not specified. +If any encryption options are set then a pass phrase will be prompted for. +.It Fl outform Cm der | pem +The output format. +.It Fl param_enc Ar arg +Specify how the elliptic curve parameters are encoded. +Possible value are: +.Cm named_curve , +i.e. the EC parameters are specified by an OID; or +.Cm explicit , +where the EC parameters are explicitly given +(see RFC 3279 for the definition of the EC parameter structures). +The default value is +.Cm named_curve . +Note: the +.Cm implicitlyCA +alternative, +as specified in RFC 3279, +is currently not implemented. +.It Fl passin Ar arg +The key password source. +.It Fl passout Ar arg +The output file password source. +.It Fl pubin +Read in a public key, not a private key. +.It Fl pubout +Output a public key, not a private key. +Automatically set if the input is a public key. +.It Fl text +Print the public/private key in plain text. +.El +.Sh ECPARAM +.nr nS 1 +.Nm "openssl ecparam" +.Op Fl C +.Op Fl check +.Op Fl conv_form Ar arg +.Op Fl genkey +.Op Fl in Ar file +.Op Fl inform Cm der | pem +.Op Fl list_curves +.Op Fl name Ar arg +.Op Fl no_seed +.Op Fl noout +.Op Fl out Ar file +.Op Fl outform Cm der | pem +.Op Fl param_enc Ar arg +.Op Fl text +.nr nS 0 +.Pp +The +.Nm ecparam +command is used to manipulate or generate EC parameter files. +.Nm openssl +is not able to generate new groups so +.Nm ecparam +can only create EC parameters from known (named) curves. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl C +Convert the EC parameters into C code. +The parameters can then be loaded by calling the +.No get_ec_group_ Ns Ar XXX +function. +.It Fl check +Validate the elliptic curve parameters. +.It Fl conv_form Ar arg +Specify how the points on the elliptic curve are converted +into octet strings. +Possible values are: +.Cm compressed +(the default), +.Cm uncompressed , +and +.Cm hybrid . +For more information regarding +the point conversion forms see the X9.62 standard. +Note: +Due to patent issues the +.Cm compressed +option is disabled by default for binary curves +and can be enabled by defining the preprocessor macro +.Dv OPENSSL_EC_BIN_PT_COMP +at compile time. +.It Fl genkey +Generate an EC private key using the specified parameters. +.It Fl in Ar file +The input file to read from, +or standard input if not specified. +.It Fl inform Cm der | pem +The input format. +.It Fl list_curves +Print a list of all +currently implemented EC parameter names and exit. +.It Fl name Ar arg +Use the EC parameters with the specified "short" name. +.It Fl no_seed +Do not include the seed for the parameter generation +in the ECParameters structure (see RFC 3279). +.It Fl noout +Do not output the encoded version of the parameters. +.It Fl out Ar file +The output file to write to, +or standard output if not specified. +.It Fl outform Cm der | pem +The output format. +.It Fl param_enc Ar arg +Specify how the elliptic curve parameters are encoded. +Possible value are: +.Cm named_curve , +i.e. the EC parameters are specified by an OID, or +.Cm explicit , +where the EC parameters are explicitly given +(see RFC 3279 for the definition of the EC parameter structures). +The default value is +.Cm named_curve . +Note: the +.Cm implicitlyCA +alternative, as specified in RFC 3279, +is currently not implemented. +.It Fl text +Print the EC parameters in plain text. +.El +.Sh ENC +.nr nS 1 +.Nm "openssl enc" +.Fl ciphername +.Op Fl AadePp +.Op Fl base64 +.Op Fl bufsize Ar number +.Op Fl debug +.Op Fl in Ar file +.Op Fl iv Ar IV +.Op Fl K Ar key +.Op Fl k Ar password +.Op Fl kfile Ar file +.Op Fl md Ar digest +.Op Fl none +.Op Fl nopad +.Op Fl nosalt +.Op Fl out Ar file +.Op Fl pass Ar arg +.Op Fl S Ar salt +.Op Fl salt +.nr nS 0 +.Pp +The symmetric cipher commands allow data to be encrypted or decrypted +using various block and stream ciphers using keys based on passwords +or explicitly provided. +Base64 encoding or decoding can also be performed either by itself +or in addition to the encryption or decryption. +The program can be called either as +.Nm openssl Ar ciphername +or +.Nm openssl enc - Ns Ar ciphername . +.Pp +Some of the ciphers do not have large keys and others have security +implications if not used correctly. +All the block ciphers normally use PKCS#5 padding, +also known as standard block padding. +If padding is disabled, the input data must be a multiple of the cipher +block length. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl A +If the +.Fl a +option is set, then base64 process the data on one line. +.It Fl a , base64 +Base64 process the data. +This means that if encryption is taking place, the data is base64-encoded +after encryption. +If decryption is set, the input data is base64-decoded before +being decrypted. +.It Fl bufsize Ar number +Set the buffer size for I/O. +.It Fl d +Decrypt the input data. +.It Fl debug +Debug the BIOs used for I/O. +.It Fl e +Encrypt the input data. +This is the default. +.It Fl in Ar file +The input file to read from, +or standard input if not specified. +.It Fl iv Ar IV +The actual +.Ar IV +.Pq initialisation vector +to use: +this must be represented as a string comprised only of hex digits. +When only the +.Ar key +is specified using the +.Fl K +option, +the IV must explicitly be defined. +When a password is being specified using one of the other options, +the IV is generated from this password. +.It Fl K Ar key +The actual +.Ar key +to use: +this must be represented as a string comprised only of hex digits. +If only the key is specified, +the IV must also be specified using the +.Fl iv +option. +When both a +.Ar key +and a +.Ar password +are specified, the +.Ar key +given with the +.Fl K +option will be used and the IV generated from the password will be taken. +It probably does not make much sense to specify both +.Ar key +and +.Ar password . +.It Fl k Ar password +The +.Ar password +to derive the key from. +Superseded by the +.Fl pass +option. +.It Fl kfile Ar file +Read the password to derive the key from the first line of +.Ar file . +Superseded by the +.Fl pass +option. +.It Fl md Ar digest +Use +.Ar digest +to create a key from a pass phrase. +.Ar digest +may be one of +.Cm md5 +or +.Cm sha1 . +.It Fl none +Use NULL cipher (no encryption or decryption of input). +.It Fl nopad +Disable standard block padding. +.It Fl nosalt +Don't use a salt in the key derivation routines. +This option should never be used +since it makes it possible to perform efficient dictionary +attacks on the password and to attack stream cipher encrypted data. +.It Fl out Ar file +The output file to write to, +or standard output if not specified. +.It Fl P +Print out the salt, key, and IV used, then immediately exit; +don't do any encryption or decryption. +.It Fl p +Print out the salt, key, and IV used. +.It Fl pass Ar arg +The password source. +.It Fl S Ar salt +The actual +.Ar salt +to use: +this must be represented as a string comprised only of hex digits. +.It Fl salt +Use a salt in the key derivation routines (the default). +When the salt is being used +the first eight bytes of the encrypted data are reserved for the salt: +it is randomly generated when encrypting a file and read from the +encrypted file when it is decrypted. +.El +.Sh ERRSTR +.Nm openssl errstr +.Op Fl stats +.Ar errno ... +.Pp +The +.Nm errstr +command performs error number to error string conversion, +generating a human-readable string representing the error code +.Ar errno . +The string is obtained through the +.Xr ERR_error_string_n 3 +function and has the following format: +.Pp +.Dl error:[error code]:[library name]:[function name]:[reason string] +.Pp +.Bq error code +is an 8-digit hexadecimal number. +The remaining fields +.Bq library name , +.Bq function name , +and +.Bq reason string +are all ASCII text. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl stats +Print debugging statistics about various aspects of the hash table. +.El +.Sh GENDSA +.nr nS 1 +.Nm "openssl gendsa" +.Oo +.Fl aes128 | aes192 | aes256 | +.Fl des | des3 +.Oc +.Op Fl out Ar file +.Op Ar paramfile +.nr nS 0 +.Pp +The +.Nm gendsa +command generates a DSA private key from a DSA parameter file +(typically generated by the +.Nm openssl dsaparam +command). +DSA key generation is little more than random number generation so it is +much quicker than, +for example, +RSA key generation. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Xo +.Fl aes128 | aes192 | aes256 | +.Fl des | des3 +.Xc +Encrypt the private key with the AES, DES, +or the triple DES ciphers, respectively, before outputting it. +A pass phrase is prompted for. +If none of these options are specified, no encryption is used. +.It Fl out Ar file +The output file to write to, +or standard output if not specified. +.It Ar paramfile +Specify the DSA parameter file to use. +The parameters in this file determine the size of the private key. +.El +.Sh GENPKEY +.nr nS 1 +.Nm "openssl genpkey" +.Op Fl algorithm Ar alg +.Op Ar cipher +.Op Fl genparam +.Op Fl out Ar file +.Op Fl outform Cm der | pem +.Op Fl paramfile Ar file +.Op Fl pass Ar arg +.Op Fl pkeyopt Ar opt : Ns Ar value +.Op Fl text +.nr nS 0 +.Pp +The +.Nm genpkey +command generates private keys. +The use of this +program is encouraged over the algorithm specific utilities +because additional algorithm options can be used. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl algorithm Ar alg +The public key algorithm to use, +such as RSA, DSA, or DH. +This option must precede any +.Fl pkeyopt +options. +The options +.Fl paramfile +and +.Fl algorithm +are mutually exclusive. +.It Ar cipher +Encrypt the private key with the supplied cipher. +Any algorithm name accepted by +.Xr EVP_get_cipherbyname 3 +is acceptable. +.It Fl genparam +Generate a set of parameters instead of a private key. +This option must precede any +.Fl algorithm , +.Fl paramfile , +or +.Fl pkeyopt +options. +.It Fl out Ar file +The output file to write to, +or standard output if not specified. +.It Fl outform Cm der | pem +The output format. +.It Fl paramfile Ar file +Some public key algorithms generate a private key based on a set of parameters, +which can be supplied using this option. +If this option is used the public key +algorithm used is determined by the parameters. +This option must precede any +.Fl pkeyopt +options. +The options +.Fl paramfile +and +.Fl algorithm +are mutually exclusive. +.It Fl pass Ar arg +The output file password source. +.It Fl pkeyopt Ar opt : Ns Ar value +Set the public key algorithm option +.Ar opt +to +.Ar value , +as follows: +.Bl -tag -width Ds -offset indent +.It rsa_keygen_bits : Ns Ar numbits +(RSA) +The number of bits in the generated key. +The default is 2048. +.It rsa_keygen_pubexp : Ns Ar value +(RSA) +The RSA public exponent value. +This can be a large decimal or hexadecimal value if preceded by 0x. +The default is 65537. +.It dsa_paramgen_bits : Ns Ar numbits +(DSA) +The number of bits in the generated parameters. +The default is 1024. +.It dh_paramgen_prime_len : Ns Ar numbits +(DH) +The number of bits in the prime parameter +.Ar p . +.It dh_paramgen_generator : Ns Ar value +(DH) +The value to use for the generator +.Ar g . +.It ec_paramgen_curve : Ns Ar curve +(EC) +The EC curve to use. +.El +.It Fl text +Print the private/public key in plain text. +.El +.Sh GENRSA +.nr nS 1 +.Nm "openssl genrsa" +.Op Fl 3 | f4 +.Op Fl aes128 | aes192 | aes256 | des | des3 +.Op Fl out Ar file +.Op Fl passout Ar arg +.Op Ar numbits +.nr nS 0 +.Pp +The +.Nm genrsa +command generates an RSA private key, +which essentially involves the generation of two prime numbers. +When generating the key, +various symbols will be output to indicate the progress of the generation. +A +.Sq \&. +represents each number which has passed an initial sieve test; +.Sq + +means a number has passed a single round of the Miller-Rabin primality test. +A newline means that the number has passed all the prime tests +(the actual number depends on the key size). +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl 3 | f4 +The public exponent to use, either 3 or 65537. +The default is 65537. +.It Fl aes128 | aes192 | aes256 | des | des3 +Encrypt the private key with the AES, DES, +or the triple DES ciphers, respectively, before outputting it. +If none of these options are specified, no encryption is used. +If encryption is used, a pass phrase is prompted for, +if it is not supplied via the +.Fl passout +option. +.It Fl out Ar file +The output file to write to, +or standard output if not specified. +.It Fl passout Ar arg +The output file password source. +.It Ar numbits +The size of the private key to generate in bits. +This must be the last option specified. +The default is 2048. +.El +.Sh NSEQ +.Nm openssl nseq +.Op Fl in Ar file +.Op Fl out Ar file +.Op Fl toseq +.Pp +The +.Nm nseq +command takes a file containing a Netscape certificate sequence +(an alternative to the standard PKCS#7 format) +and prints out the certificates contained in it, +or takes a file of certificates +and converts it into a Netscape certificate sequence. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl in Ar file +The input file to read from, +or standard input if not specified. +.It Fl out Ar file +The output file to write to, +or standard output if not specified. +.It Fl toseq +Normally, a Netscape certificate sequence will be input and the output +is the certificates contained in it. +With the +.Fl toseq +option the situation is reversed: +a Netscape certificate sequence is created from a file of certificates. +.El +.Sh OCSP +.nr nS 1 +.Nm "openssl ocsp" +.Op Fl CA Ar file +.Op Fl CAfile Ar file +.Op Fl CApath Ar directory +.Op Fl cert Ar file +.Op Fl dgst Ar alg +.Op Fl host Ar hostname : Ns Ar port +.Op Fl index Ar indexfile +.Op Fl issuer Ar file +.Op Fl ndays Ar days +.Op Fl nmin Ar minutes +.Op Fl no_cert_checks +.Op Fl no_cert_verify +.Op Fl no_certs +.Op Fl no_chain +.Op Fl no_intern +.Op Fl no_nonce +.Op Fl no_signature_verify +.Op Fl nonce +.Op Fl noverify +.Op Fl nrequest Ar number +.Op Fl out Ar file +.Op Fl path Ar path +.Op Fl port Ar portnum +.Op Fl req_text +.Op Fl reqin Ar file +.Op Fl reqout Ar file +.Op Fl resp_key_id +.Op Fl resp_no_certs +.Op Fl resp_text +.Op Fl respin Ar file +.Op Fl respout Ar file +.Op Fl rkey Ar file +.Op Fl rother Ar file +.Op Fl rsigner Ar file +.Op Fl serial Ar number +.Op Fl sign_other Ar file +.Op Fl signer Ar file +.Op Fl signkey Ar file +.Op Fl status_age Ar age +.Op Fl text +.Op Fl trust_other +.Op Fl url Ar responder_url +.Op Fl VAfile Ar file +.Op Fl validity_period Ar nsec +.Op Fl verify_other Ar file +.nr nS 0 +.Pp +The Online Certificate Status Protocol (OCSP) +enables applications to determine the (revocation) state +of an identified certificate (RFC 2560). +.Pp +The +.Nm ocsp +command performs many common OCSP tasks. +It can be used to print out requests and responses, +create requests and send queries to an OCSP responder, +and behave like a mini OCSP server itself. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl CAfile Ar file , Fl CApath Ar directory +A file or path containing trusted CA certificates, +used to verify the signature on the OCSP response. +.It Fl cert Ar file +Add the certificate +.Ar file +to the request. +The issuer certificate is taken from the previous +.Fl issuer +option, or an error occurs if no issuer certificate is specified. +.It Fl dgst Ar alg +Use the digest algorithm +.Ar alg +for certificate identification in the OCSP request. +By default SHA-1 is used. +.It Xo +.Fl host Ar hostname : Ns Ar port , +.Fl path Ar path +.Xc +Send +the OCSP request to +.Ar hostname +on +.Ar port . +.Fl path +specifies the HTTP path name to use, or +.Pa / +by default. +.It Fl issuer Ar file +The current issuer certificate, in PEM format. +Can be used multiple times and must come before any +.Fl cert +options. +.It Fl no_cert_checks +Don't perform any additional checks on the OCSP response signer's certificate. +That is, do not make any checks to see if the signer's certificate is +authorised to provide the necessary status information: +as a result this option should only be used for testing purposes. +.It Fl no_cert_verify +Don't verify the OCSP response signer's certificate at all. +Since this option allows the OCSP response to be signed by any certificate, +it should only be used for testing purposes. +.It Fl no_certs +Don't include any certificates in the signed request. +.It Fl no_chain +Do not use certificates in the response as additional untrusted CA +certificates. +.It Fl no_intern +Ignore certificates contained in the OCSP response +when searching for the signer's certificate. +The signer's certificate must be specified with either the +.Fl verify_other +or +.Fl VAfile +options. +.It Fl no_signature_verify +Don't check the signature on the OCSP response. +Since this option tolerates invalid signatures on OCSP responses, +it will normally only be used for testing purposes. +.It Fl nonce , no_nonce +Add an OCSP nonce extension to a request, +or disable an OCSP nonce addition. +Normally, if an OCSP request is input using the +.Fl respin +option no nonce is added: +using the +.Fl nonce +option will force the addition of a nonce. +If an OCSP request is being created (using the +.Fl cert +and +.Fl serial +options) +a nonce is automatically added; specifying +.Fl no_nonce +overrides this. +.It Fl noverify +Don't attempt to verify the OCSP response signature or the nonce values. +This is normally only be used for debugging +since it disables all verification of the responder's certificate. +.It Fl out Ar file +Specify the output file to write to, +or standard output if not specified. +.It Fl req_text , resp_text , text +Print out the text form of the OCSP request, response, or both, respectively. +.It Fl reqin Ar file , Fl respin Ar file +Read an OCSP request or response file from +.Ar file . +These options are ignored +if an OCSP request or response creation is implied by other options +(for example with the +.Fl serial , cert , +and +.Fl host +options). +.It Fl reqout Ar file , Fl respout Ar file +Write out the DER-encoded certificate request or response to +.Ar file . +.It Fl serial Ar num +Same as the +.Fl cert +option except the certificate with serial number +.Ar num +is added to the request. +The serial number is interpreted as a decimal integer unless preceded by +.Sq 0x . +Negative integers can also be specified +by preceding the value with a minus sign. +.It Fl sign_other Ar file +Additional certificates to include in the signed request. +.It Fl signer Ar file , Fl signkey Ar file +Sign the OCSP request using the certificate specified in the +.Fl signer +option and the private key specified by the +.Fl signkey +option. +If the +.Fl signkey +option is not present, then the private key is read from the same file +as the certificate. +If neither option is specified, the OCSP request is not signed. +.It Fl trust_other +The certificates specified by the +.Fl verify_other +option should be explicitly trusted and no additional checks will be +performed on them. +This is useful when the complete responder certificate chain is not available +or trusting a root CA is not appropriate. +.It Fl url Ar responder_url +Specify the responder URL. +Both HTTP and HTTPS +.Pq SSL/TLS +URLs can be specified. +.It Fl VAfile Ar file +A file containing explicitly trusted responder certificates. +Equivalent to the +.Fl verify_other +and +.Fl trust_other +options. +.It Fl validity_period Ar nsec , Fl status_age Ar age +The range of times, in seconds, which will be tolerated in an OCSP response. +Each certificate status response includes a notBefore time +and an optional notAfter time. +The current time should fall between these two values, +but the interval between the two times may be only a few seconds. +In practice the OCSP responder and clients' clocks may not be precisely +synchronised and so such a check may fail. +To avoid this the +.Fl validity_period +option can be used to specify an acceptable error range in seconds, +the default value being 5 minutes. +.Pp +If the notAfter time is omitted from a response, +it means that new status information is immediately available. +In this case the age of the notBefore field is checked +to see it is not older than +.Ar age +seconds old. +By default, this additional check is not performed. +.It Fl verify_other Ar file +A file containing additional certificates to search +when attempting to locate the OCSP response signing certificate. +Some responders omit the actual signer's certificate from the response, +so this can be used to supply the necessary certificate. +.El +.Pp +The options for the OCSP server are as follows: +.Bl -tag -width "XXXX" +.It Fl CA Ar file +CA certificate corresponding to the revocation information in +.Ar indexfile . +.It Fl index Ar indexfile +.Ar indexfile +is a text index file in ca format +containing certificate revocation information. +.Pp +If this option is specified, +.Nm ocsp +is in responder mode, otherwise it is in client mode. +The requests the responder processes can be either specified on +the command line (using the +.Fl issuer +and +.Fl serial +options), supplied in a file (using the +.Fl respin +option), or via external OCSP clients (if +.Ar port +or +.Ar url +is specified). +.Pp +If this option is present, then the +.Fl CA +and +.Fl rsigner +options must also be present. +.It Fl nmin Ar minutes , Fl ndays Ar days +Number of +.Ar minutes +or +.Ar days +when fresh revocation information is available: +used in the nextUpdate field. +If neither option is present, +the nextUpdate field is omitted, +meaning fresh revocation information is immediately available. +.It Fl nrequest Ar number +Exit after receiving +.Ar number +requests (the default is unlimited). +.It Fl port Ar portnum +Port to listen for OCSP requests on. +May also be specified using the +.Fl url +option. +.It Fl resp_key_id +Identify the signer certificate using the key ID; +the default is to use the subject name. +.It Fl resp_no_certs +Don't include any certificates in the OCSP response. +.It Fl rkey Ar file +The private key to sign OCSP responses with; +if not present, the file specified in the +.Fl rsigner +option is used. +.It Fl rother Ar file +Additional certificates to include in the OCSP response. +.It Fl rsigner Ar file +The certificate to sign OCSP responses with. +.El +.Pp +Initially the OCSP responder certificate is located and the signature on +the OCSP request checked using the responder certificate's public key. +Then a normal certificate verify is performed on the OCSP responder certificate +building up a certificate chain in the process. +The locations of the trusted certificates used to build the chain can be +specified by the +.Fl CAfile +and +.Fl CApath +options or they will be looked for in the standard +.Nm openssl +certificates directory. +.Pp +If the initial verify fails, the OCSP verify process halts with an error. +Otherwise the issuing CA certificate in the request is compared to the OCSP +responder certificate: if there is a match then the OCSP verify succeeds. +.Pp +Otherwise the OCSP responder certificate's CA is checked against the issuing +CA certificate in the request. +If there is a match and the OCSPSigning extended key usage is present +in the OCSP responder certificate, then the OCSP verify succeeds. +.Pp +Otherwise the root CA of the OCSP responder's CA is checked to see if it +is trusted for OCSP signing. +If it is, the OCSP verify succeeds. +.Pp +If none of these checks is successful, the OCSP verify fails. +What this effectively means is that if the OCSP responder certificate is +authorised directly by the CA it is issuing revocation information about +(and it is correctly configured), +then verification will succeed. +.Pp +If the OCSP responder is a global responder, +which can give details about multiple CAs +and has its own separate certificate chain, +then its root CA can be trusted for OCSP signing. +Alternatively, the responder certificate itself can be explicitly trusted +with the +.Fl VAfile +option. +.Sh PASSWD +.nr nS 1 +.Nm "openssl passwd" +.Op Fl 1 | apr1 | crypt +.Op Fl in Ar file +.Op Fl noverify +.Op Fl quiet +.Op Fl reverse +.Op Fl salt Ar string +.Op Fl stdin +.Op Fl table +.Op Ar password +.nr nS 0 +.Pp +The +.Nm passwd +command computes the hash of a password. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl 1 +Use the MD5 based +.Bx +password algorithm +.Qq 1 . +.It Fl apr1 +Use the +.Qq apr1 +algorithm +.Po +Apache variant of the +.Bx +algorithm +.Pc . +.It Fl crypt +Use the +.Qq crypt +algorithm (the default). +.It Fl in Ar file +Read passwords from +.Ar file . +.It Fl noverify +Don't verify when reading a password from the terminal. +.It Fl quiet +Don't output warnings when passwords given on the command line are truncated. +.It Fl reverse +Switch table columns. +This only makes sense in conjunction with the +.Fl table +option. +.It Fl salt Ar string +Use the salt specified by +.Ar string . +When reading a password from the terminal, this implies +.Fl noverify . +.It Fl stdin +Read passwords from standard input. +.It Fl table +In the output list, prepend the cleartext password and a TAB character +to each password hash. +.El +.Sh PKCS7 +.nr nS 1 +.Nm "openssl pkcs7" +.Op Fl in Ar file +.Op Fl inform Cm der | pem +.Op Fl noout +.Op Fl out Ar file +.Op Fl outform Cm der | pem +.Op Fl print_certs +.Op Fl text +.nr nS 0 +.Pp +The +.Nm pkcs7 +command processes PKCS#7 files in DER or PEM format. +The PKCS#7 routines only understand PKCS#7 v 1.5 as specified in RFC 2315. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl in Ar file +The input file to read from, +or standard input if not specified. +.It Fl inform Cm der | pem +The input format. +.It Fl noout +Don't output the encoded version of the PKCS#7 structure +(or certificates if +.Fl print_certs +is set). +.It Fl out Ar file +The output to write to, +or standard output if not specified. +.It Fl outform Cm der | pem +The output format. +.It Fl print_certs +Print any certificates or CRLs contained in the file, +preceded by their subject and issuer names in a one-line format. +.It Fl text +Print certificate details in full rather than just subject and issuer names. +.El +.Sh PKCS8 +.nr nS 1 +.Nm "openssl pkcs8" +.Op Fl embed +.Op Fl in Ar file +.Op Fl inform Cm der | pem +.Op Fl nocrypt +.Op Fl noiter +.Op Fl nooct +.Op Fl nsdb +.Op Fl out Ar file +.Op Fl outform Cm der | pem +.Op Fl passin Ar arg +.Op Fl passout Ar arg +.Op Fl topk8 +.Op Fl v1 Ar alg +.Op Fl v2 Ar alg +.nr nS 0 +.Pp +The +.Nm pkcs8 +command processes private keys +(both encrypted and unencrypted) +in PKCS#8 format +with a variety of PKCS#5 (v1.5 and v2.0) and PKCS#12 algorithms. +The default encryption is only 56 bits; +keys encrypted using PKCS#5 v2.0 algorithms and high iteration counts +are more secure. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl embed +Generate DSA keys in a broken format. +The DSA parameters are embedded inside the PrivateKey structure. +In this form the OCTET STRING contains an ASN.1 SEQUENCE consisting of +two structures: +a SEQUENCE containing the parameters and an ASN.1 INTEGER containing +the private key. +.It Fl in Ar file +The input file to read from, +or standard input if not specified. +If the key is encrypted, a pass phrase will be prompted for. +.It Fl inform Cm der | pem +The input format. +.It Fl nocrypt +Generate an unencrypted PrivateKeyInfo structure. +This option does not encrypt private keys at all +and should only be used when absolutely necessary. +.It Fl noiter +Use an iteration count of 1. +See the +.Sx PKCS12 +section below for a detailed explanation of this option. +.It Fl nooct +Generate RSA private keys in a broken format that some software uses. +Specifically the private key should be enclosed in an OCTET STRING, +but some software just includes the structure itself without the +surrounding OCTET STRING. +.It Fl nsdb +Generate DSA keys in a broken format compatible with Netscape +private key databases. +The PrivateKey contains a SEQUENCE +consisting of the public and private keys, respectively. +.It Fl out Ar file +The output file to write to, +or standard output if none is specified. +If any encryption options are set, a pass phrase will be prompted for. +.It Fl outform Cm der | pem +The output format. +.It Fl passin Ar arg +The key password source. +.It Fl passout Ar arg +The output file password source. +.It Fl topk8 +Read a traditional format private key and write a PKCS#8 format key. +.It Fl v1 Ar alg +Specify a PKCS#5 v1.5 or PKCS#12 algorithm to use. +.Pp +.Bl -tag -width "XXXX" -compact +.It PBE-MD5-DES +56-bit DES. +.It PBE-SHA1-RC2-64 | PBE-MD5-RC2-64 | PBE-SHA1-DES +64-bit RC2 or 56-bit DES. +.It PBE-SHA1-RC4-128 | PBE-SHA1-RC4-40 | PBE-SHA1-3DES +.It PBE-SHA1-2DES | PBE-SHA1-RC2-128 | PBE-SHA1-RC2-40 +PKCS#12 password-based encryption algorithm, +which allow strong encryption algorithms like triple DES or 128-bit RC2. +.El +.It Fl v2 Ar alg +Use PKCS#5 v2.0 algorithms. +Supports algorithms such as 168-bit triple DES or 128-bit RC2, +however not many implementations support PKCS#5 v2.0 yet +(if using private keys with +.Nm openssl +this doesn't matter). +.Pp +.Ar alg +is the encryption algorithm to use; +valid values include des, des3, and rc2. +It is recommended that des3 is used. +.El +.Sh PKCS12 +.nr nS 1 +.Nm "openssl pkcs12" +.Op Fl aes128 | aes192 | aes256 | des | des3 +.Op Fl cacerts +.Op Fl CAfile Ar file +.Op Fl caname Ar name +.Op Fl CApath Ar directory +.Op Fl certfile Ar file +.Op Fl certpbe Ar alg +.Op Fl chain +.Op Fl clcerts +.Op Fl CSP Ar name +.Op Fl descert +.Op Fl export +.Op Fl in Ar file +.Op Fl info +.Op Fl inkey Ar file +.Op Fl keyex +.Op Fl keypbe Ar alg +.Op Fl keysig +.Op Fl macalg Ar alg +.Op Fl maciter +.Op Fl name Ar name +.Op Fl nocerts +.Op Fl nodes +.Op Fl noiter +.Op Fl nokeys +.Op Fl nomac +.Op Fl nomaciter +.Op Fl nomacver +.Op Fl noout +.Op Fl out Ar file +.Op Fl passin Ar arg +.Op Fl passout Ar arg +.Op Fl twopass +.nr nS 0 +.Pp +The +.Nm pkcs12 +command allows PKCS#12 files +.Pq sometimes referred to as PFX files +to be created and parsed. +By default, a PKCS#12 file is parsed; +a PKCS#12 file can be created by using the +.Fl export +option. +.Pp +The options for parsing a PKCS12 file are as follows: +.Bl -tag -width "XXXX" +.It Fl aes128 | aes192 | aes256 | des | des3 +Encrypt private keys +using AES, DES, or triple DES, respectively. +The default is triple DES. +.It Fl cacerts +Only output CA certificates +.Pq not client certificates . +.It Fl clcerts +Only output client certificates +.Pq not CA certificates . +.It Fl in Ar file +The input file to read from, +or standard input if not specified. +.It Fl info +Output additional information about the PKCS#12 file structure, +algorithms used, and iteration counts. +.It Fl nocerts +Do not output certificates. +.It Fl nodes +Do not encrypt private keys. +.It Fl nokeys +Do not output private keys. +.It Fl nomacver +Do not attempt to verify the integrity MAC before reading the file. +.It Fl noout +Do not output the keys and certificates to the output file +version of the PKCS#12 file. +.It Fl out Ar file +The output file to write to, +or standard output if not specified. +.It Fl passin Ar arg +The key password source. +.It Fl passout Ar arg +The output file password source. +.It Fl twopass +Prompt for separate integrity and encryption passwords: most software +always assumes these are the same so this option will render such +PKCS#12 files unreadable. +.El +.Pp +The options for PKCS12 file creation are as follows: +.Bl -tag -width "XXXX" +.It Fl CAfile Ar file +CA storage as a file. +.It Fl CApath Ar directory +CA storage as a directory. +The directory must be a standard certificate directory: +that is, a hash of each subject name (using +.Nm x509 Fl hash ) +should be linked to each certificate. +.It Fl caname Ar name +Specify the +.Qq friendly name +for other certificates. +May be used multiple times to specify names for all certificates +in the order they appear. +.It Fl certfile Ar file +A file to read additional certificates from. +.It Fl certpbe Ar alg , Fl keypbe Ar alg +Specify the algorithm used to encrypt the private key and +certificates to be selected. +Any PKCS#5 v1.5 or PKCS#12 PBE algorithm name can be used. +If a cipher name +(as output by the +.Cm list-cipher-algorithms +command) is specified then it +is used with PKCS#5 v2.0. +For interoperability reasons it is advisable to only use PKCS#12 algorithms. +.It Fl chain +Include the entire certificate chain of the user certificate. +The standard CA store is used for this search. +If the search fails, it is considered a fatal error. +.It Fl CSP Ar name +Write +.Ar name +as a Microsoft CSP name. +.It Fl descert +Encrypt the certificate using triple DES; this may render the PKCS#12 +file unreadable by some +.Qq export grade +software. +By default, the private key is encrypted using triple DES and the +certificate using 40-bit RC2. +.It Fl export +Create a PKCS#12 file (rather than parsing one). +.It Fl in Ar file +The input file to read from, +or standard input if not specified. +The order doesn't matter but one private key and its corresponding +certificate should be present. +If additional certificates are present, they will also be included +in the PKCS#12 file. +.It Fl inkey Ar file +File to read a private key from. +If not present, a private key must be present in the input file. +.It Fl keyex | keysig +Specify whether the private key is to be used for key exchange or just signing. +Normally, +.Qq export grade +software will only allow 512-bit RSA keys to be +used for encryption purposes, but arbitrary length keys for signing. +The +.Fl keysig +option marks the key for signing only. +Signing only keys can be used for S/MIME signing, authenticode +(ActiveX control signing) +and SSL client authentication. +.It Fl macalg Ar alg +Specify the MAC digest algorithm. +The default is SHA1. +.It Fl maciter +Included for compatibility only: +it used to be needed to use MAC iterations counts +but they are now used by default. +.It Fl name Ar name +Specify the +.Qq friendly name +for the certificate and private key. +This name is typically displayed in list boxes by software importing the file. +.It Fl nomac +Don't attempt to provide the MAC integrity. +.It Fl nomaciter , noiter +Affect the iteration counts on the MAC and key algorithms. +.Pp +To discourage attacks by using large dictionaries of common passwords, +the algorithm that derives keys from passwords can have an iteration count +applied to it: this causes a certain part of the algorithm to be repeated +and slows it down. +The MAC is used to check the file integrity but since it will normally +have the same password as the keys and certificates it could also be attacked. +By default, both MAC and encryption iteration counts are set to 2048; +using these options the MAC and encryption iteration counts can be set to 1. +Since this reduces the file security you should not use these options +unless you really have to. +Most software supports both MAC and key iteration counts. +.It Fl out Ar file +The output file to write to, +or standard output if not specified. +.It Fl passin Ar arg +The key password source. +.It Fl passout Ar arg +The output file password source. +.El +.Sh PKEY +.nr nS 1 +.Nm "openssl pkey" +.Op Ar cipher +.Op Fl in Ar file +.Op Fl inform Cm der | pem +.Op Fl noout +.Op Fl out Ar file +.Op Fl outform Cm der | pem +.Op Fl passin Ar arg +.Op Fl passout Ar arg +.Op Fl pubin +.Op Fl pubout +.Op Fl text +.Op Fl text_pub +.nr nS 0 +.Pp +The +.Nm pkey +command processes public or private keys. +They can be converted between various forms +and their components printed out. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Ar cipher +Encrypt the private key with the specified cipher. +Any algorithm name accepted by +.Xr EVP_get_cipherbyname 3 +is acceptable, such as +.Cm des3 . +.It Fl in Ar file +The input file to read from, +or standard input if not specified. +If the key is encrypted a pass phrase will be prompted for. +.It Fl inform Cm der | pem +The input format. +.It Fl noout +Do not output the encoded version of the key. +.It Fl out Ar file +The output file to write to, +or standard output if not specified. +If any encryption options are set then a pass phrase +will be prompted for. +.It Fl outform Cm der | pem +The output format. +.It Fl passin Ar arg +The key password source. +.It Fl passout Ar arg +The output file password source. +.It Fl pubin +Read in a public key, not a private key. +.It Fl pubout +Output a public key, not a private key. +Automatically set if the input is a public key. +.It Fl text +Print the public/private key in plain text. +.It Fl text_pub +Print out only public key components +even if a private key is being processed. +.El +.Sh PKEYPARAM +.Cm openssl pkeyparam +.Op Fl in Ar file +.Op Fl noout +.Op Fl out Ar file +.Op Fl text +.Pp +The +.Nm pkeyparam +command processes public or private keys. +The key type is determined by the PEM headers. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl in Ar file +The input file to read from, +or standard input if not specified. +.It Fl noout +Do not output the encoded version of the parameters. +.It Fl out Ar file +The output file to write to, +or standard output if not specified. +.It Fl text +Print the parameters in plain text. +.El +.Sh PKEYUTL +.nr nS 1 +.Nm "openssl pkeyutl" +.Op Fl asn1parse +.Op Fl certin +.Op Fl decrypt +.Op Fl derive +.Op Fl encrypt +.Op Fl hexdump +.Op Fl in Ar file +.Op Fl inkey Ar file +.Op Fl keyform Cm der | pem +.Op Fl out Ar file +.Op Fl passin Ar arg +.Op Fl peerform Cm der | pem +.Op Fl peerkey Ar file +.Op Fl pkeyopt Ar opt : Ns Ar value +.Op Fl pubin +.Op Fl rev +.Op Fl sigfile Ar file +.Op Fl sign +.Op Fl verify +.Op Fl verifyrecover +.nr nS 0 +.Pp +The +.Nm pkeyutl +command can be used to perform public key operations using +any supported algorithm. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl asn1parse +ASN.1 parse the output data. +This is useful when combined with the +.Fl verifyrecover +option when an ASN.1 structure is signed. +.It Fl certin +The input is a certificate containing a public key. +.It Fl decrypt +Decrypt the input data using a private key. +.It Fl derive +Derive a shared secret using the peer key. +.It Fl encrypt +Encrypt the input data using a public key. +.It Fl hexdump +Hex dump the output data. +.It Fl in Ar file +The input file to read from, +or standard input if not specified. +.It Fl inkey Ar file +The input key file. +By default it should be a private key. +.It Fl keyform Cm der | pem +The key format. +.It Fl out Ar file +The output file to write to, +or standard output if not specified. +.It Fl passin Ar arg +The key password source. +.It Fl peerform Cm der | pem +The peer key format. +.It Fl peerkey Ar file +The peer key file, used by key derivation (agreement) operations. +.It Fl pkeyopt Ar opt : Ns Ar value +Set the public key algorithm option +.Ar opt +to +.Ar value . +Unless otherwise mentioned, all algorithms support the format +.Ar digest : Ns Ar alg , +which specifies the digest to use +for sign, verify, and verifyrecover operations. +The value +.Ar alg +should represent a digest name as used in the +.Xr EVP_get_digestbyname 3 +function. +.Pp +The RSA algorithm supports the +encrypt, decrypt, sign, verify, and verifyrecover operations in general. +Some padding modes only support some of these +operations however. +.Bl -tag -width Ds +.It rsa_padding_mode : Ns Ar mode +This sets the RSA padding mode. +Acceptable values for +.Ar mode +are +.Cm pkcs1 +for PKCS#1 padding; +.Cm none +for no padding; +.Cm oaep +for OAEP mode; +.Cm x931 +for X9.31 mode; +and +.Cm pss +for PSS. +.Pp +In PKCS#1 padding if the message digest is not set then the supplied data is +signed or verified directly instead of using a DigestInfo structure. +If a digest is set then a DigestInfo +structure is used and its length +must correspond to the digest type. +For oeap mode only encryption and decryption is supported. +For x931 if the digest type is set it is used to format the block data; +otherwise the first byte is used to specify the X9.31 digest ID. +Sign, verify, and verifyrecover can be performed in this mode. +For pss mode only sign and verify are supported and the digest type must be +specified. +.It rsa_pss_saltlen : Ns Ar len +For pss +mode only this option specifies the salt length. +Two special values are supported: +-1 sets the salt length to the digest length. +When signing -2 sets the salt length to the maximum permissible value. +When verifying -2 causes the salt length to be automatically determined +based on the PSS block structure. +.El +.Pp +The DSA algorithm supports the sign and verify operations. +Currently there are no additional options other than +.Ar digest . +Only the SHA1 digest can be used and this digest is assumed by default. +.Pp +The DH algorithm supports the derive operation +and no additional options. +.Pp +The EC algorithm supports the sign, verify, and derive operations. +The sign and verify operations use ECDSA and derive uses ECDH. +Currently there are no additional options other than +.Ar digest . +Only the SHA1 digest can be used and this digest is assumed by default. +.It Fl pubin +The input file is a public key. +.It Fl rev +Reverse the order of the input buffer. +.It Fl sigfile Ar file +Signature file (verify operation only). +.It Fl sign +Sign the input data and output the signed result. +This requires a private key. +.It Fl verify +Verify the input data against the signature file and indicate if the +verification succeeded or failed. +.It Fl verifyrecover +Verify the input data and output the recovered data. +.El +.Sh PRIME +.Cm openssl prime +.Op Fl bits Ar n +.Op Fl checks Ar n +.Op Fl generate +.Op Fl hex +.Op Fl safe +.Ar p +.Pp +The +.Nm prime +command is used to generate prime numbers, +or to check numbers for primality. +Results are probabilistic: +they have an exceedingly high likelihood of being correct, +but are not guaranteed. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl bits Ar n +Specify the number of bits in the generated prime number. +Must be used in conjunction with +.Fl generate . +.It Fl checks Ar n +Perform a Miller-Rabin probabilistic primality test with +.Ar n +iterations. +The default is 20. +.It Fl generate +Generate a pseudo-random prime number. +Must be used in conjunction with +.Fl bits . +.It Fl hex +Output in hex format. +.It Fl safe +Generate only +.Qq safe +prime numbers +(i.e. a prime p so that (p-1)/2 is also prime). +.It Ar p +Test if number +.Ar p +is prime. +.El +.Sh RAND +.nr nS 1 +.Nm "openssl rand" +.Op Fl base64 +.Op Fl hex +.Op Fl out Ar file +.Ar num +.nr nS 0 +.Pp +The +.Nm rand +command outputs +.Ar num +pseudo-random bytes. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl base64 +Perform base64 encoding on the output. +.It Fl hex +Specify hexadecimal output. +.It Fl out Ar file +The output file to write to, +or standard output if not specified. +.El +.Sh REQ +.nr nS 1 +.Nm "openssl req" +.Op Fl asn1-kludge +.Op Fl batch +.Op Fl config Ar file +.Op Fl days Ar n +.Op Fl extensions Ar section +.Op Fl in Ar file +.Op Fl inform Cm der | pem +.Op Fl key Ar keyfile +.Op Fl keyform Cm der | pem +.Op Fl keyout Ar file +.Op Fl md4 | md5 | sha1 +.Op Fl modulus +.Op Fl nameopt Ar option +.Op Fl new +.Op Fl newhdr +.Op Fl newkey Ar arg +.Op Fl no-asn1-kludge +.Op Fl nodes +.Op Fl noout +.Op Fl out Ar file +.Op Fl outform Cm der | pem +.Op Fl passin Ar arg +.Op Fl passout Ar arg +.Op Fl pubkey +.Op Fl reqexts Ar section +.Op Fl reqopt Ar option +.Op Fl set_serial Ar n +.Op Fl subj Ar arg +.Op Fl subject +.Op Fl text +.Op Fl utf8 +.Op Fl verbose +.Op Fl verify +.Op Fl x509 +.nr nS 0 +.Pp +The +.Nm req +command primarily creates and processes certificate requests +in PKCS#10 format. +It can additionally create self-signed certificates, +for use as root CAs, for example. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl asn1-kludge +Produce requests in an invalid format for certain picky CAs. +Very few CAs still require the use of this option. +.It Fl batch +Non-interactive mode. +.It Fl config Ar file +Specify an alternative configuration file. +.It Fl days Ar n +Specify the number of days to certify the certificate for. +The default is 30 days. +Used with the +.Fl x509 +option. +.It Fl extensions Ar section , Fl reqexts Ar section +Specify alternative sections to include certificate +extensions (with +.Fl x509 ) +or certificate request extensions, +allowing several different sections to be used in the same configuration file. +.It Fl in Ar file +The input file to read a request from, +or standard input if not specified. +A request is only read if the creation options +.Fl new +and +.Fl newkey +are not specified. +.It Fl inform Cm der | pem +The input format. +.It Fl key Ar keyfile +The file to read the private key from. +It also accepts PKCS#8 format private keys for PEM format files. +.It Fl keyform Cm der | pem +The format of the private key file specified in the +.Fl key +argument. +The default is +.Cm pem . +.It Fl keyout Ar file +The file to write the newly created private key to. +If this option is not specified, +the filename present in the configuration file is used. +.It Fl md5 | sha1 | sha256 +The message digest to sign the request with. +This overrides the digest algorithm specified in the configuration file. +.Pp +Some public key algorithms may override this choice. +For instance, DSA signatures always use SHA1. +.It Fl modulus +Print the value of the modulus of the public key contained in the request. +.It Fl nameopt Ar option , Fl reqopt Ar option +Determine how the subject or issuer names are displayed. +.Ar option +can be a single option or multiple options separated by commas. +Alternatively, these options may be used more than once to set multiple options. +See the +.Sx X509 +section below for details. +.It Fl new +Generate a new certificate request. +The user is prompted for the relevant field values. +The actual fields prompted for and their maximum and minimum sizes +are specified in the configuration file and any requested extensions. +.Pp +If the +.Fl key +option is not used, it will generate a new RSA private +key using information specified in the configuration file. +.It Fl newhdr +Add the word NEW to the PEM file header and footer lines +on the outputed request. +Some software and CAs need this. +.It Fl newkey Ar arg +Create a new certificate request and a new private key. +The argument takes one of several forms. +.Pp +.No rsa : Ns Ar nbits +generates an RSA key +.Ar nbits +in size. +If +.Ar nbits +is omitted +the default key size is used. +.Pp +.No dsa : Ns Ar file +generates a DSA key using the parameters in +.Ar file . +.Pp +.No param : Ns Ar file +generates a key using the parameters or certificate in +.Ar file . +.Pp +All other algorithms support the form +.Ar algorithm : Ns Ar file , +where file may be an algorithm parameter file, +created by the +.Cm genpkey -genparam +command or an X.509 certificate for a key with appropriate algorithm. +.Ar file +can be omitted, +in which case any parameters can be specified via the +.Fl pkeyopt +option. +.It Fl no-asn1-kludge +Reverse the effect of +.Fl asn1-kludge . +.It Fl nodes +Do not encrypt the private key. +.It Fl noout +Do not output the encoded version of the request. +.It Fl out Ar file +The output file to write to, +or standard output if not spceified. +.It Fl outform Cm der | pem +The output format. +.It Fl passin Ar arg +The key password source. +.It Fl passout Ar arg +The output file password source. +.It Fl pubkey +Output the public key. +.It Fl reqopt Ar option +Customise the output format used with +.Fl text . +The +.Ar option +argument can be a single option or multiple options separated by commas. +See also the discussion of +.Fl certopt +in the +.Nm x509 +command. +.It Fl set_serial Ar n +Serial number to use when outputting a self-signed certificate. +This may be specified as a decimal value or a hex value if preceded by +.Sq 0x . +It is possible to use negative serial numbers but this is not recommended. +.It Fl subj Ar arg +Replaces the subject field of an input request +with the specified data and output the modified request. +.Ar arg +must be formatted as /type0=value0/type1=value1/type2=...; +characters may be escaped by +.Sq \e +(backslash); +no spaces are skipped. +.It Fl subject +Print the request subject (or certificate subject if +.Fl x509 +is specified). +.It Fl text +Print the certificate request in plain text. +.It Fl utf8 +Interpret field values as UTF8 strings, not ASCII. +.It Fl verbose +Print extra details about the operations being performed. +.It Fl verify +Verify the signature on the request. +.It Fl x509 +Output a self-signed certificate instead of a certificate request. +This is typically used to generate a test certificate or a self-signed root CA. +The extensions added to the certificate (if any) +are specified in the configuration file. +Unless specified using the +.Fl set_serial +option, 0 is used for the serial number. +.El +.Pp +The configuration options are specified in the +.Qq req +section of the configuration file. +The options available are as follows: +.Bl -tag -width "XXXX" +.It Cm attributes +The section containing any request attributes: its format +is the same as +.Cm distinguished_name . +Typically these may contain the challengePassword or unstructuredName types. +They are currently ignored by the +.Nm openssl +request signing utilities, but some CAs might want them. +.It Cm default_bits +The default key size, in bits. +The default is 2048. +It is used if the +.Fl new +option is used and can be overridden by using the +.Fl newkey +option. +.It Cm default_keyfile +The default file to write a private key to, +or standard output if not specified. +It can be overridden by the +.Fl keyout +option. +.It Cm default_md +The digest algorithm to use. +Possible values include +.Cm md5 , +.Cm sha1 +and +.Cm sha256 +(the default). +It can be overridden on the command line. +.It Cm distinguished_name +The section containing the distinguished name fields to +prompt for when generating a certificate or certificate request. +The format is described below. +.It Cm encrypt_key +If set to +.Qq no +and a private key is generated, it is not encrypted. +It is equivalent to the +.Fl nodes +option. +For compatibility, +.Cm encrypt_rsa_key +is an equivalent option. +.It Cm input_password | output_password +The passwords for the input private key file (if present) +and the output private key file (if one will be created). +The command line options +.Fl passin +and +.Fl passout +override the configuration file values. +.It Cm oid_file +A file containing additional OBJECT IDENTIFIERS. +Each line of the file should consist of the numerical form of the +object identifier, followed by whitespace, then the short name followed +by whitespace and finally the long name. +.It Cm oid_section +Specify a section in the configuration file containing extra +object identifiers. +Each line should consist of the short name of the +object identifier followed by +.Sq = +and the numerical form. +The short and long names are the same when this option is used. +.It Cm prompt +If set to +.Qq no , +it disables prompting of certificate fields +and just takes values from the config file directly. +It also changes the expected format of the +.Cm distinguished_name +and +.Cm attributes +sections. +.It Cm req_extensions +The configuration file section containing a list of +extensions to add to the certificate request. +It can be overridden by the +.Fl reqexts +option. +.It Cm string_mask +Limit the string types for encoding certain fields. +The following values may be used, limiting strings to the indicated types: +.Bl -tag -width "MASK:number" +.It Cm utf8only +UTF8String. +This is the default, as recommended by PKIX in RFC 2459. +.It Cm default +PrintableString, IA5String, T61String, BMPString, UTF8String. +.It Cm pkix +PrintableString, IA5String, BMPString, UTF8String. +Inspired by the PKIX recommendation in RFC 2459 for certificates +generated before 2004, but differs by also permitting IA5String. +.It Cm nombstr +PrintableString, IA5String, T61String, UniversalString. +A workaround for some ancient software that had problems +with the variable-sized BMPString and UTF8String types. +.It Cm MASK : Ns Ar number +An explicit bitmask of permitted types, where +.Ar number +is a C-style hex, decimal, or octal number that's a bit-wise OR of +.Dv B_ASN1_* +values from +.In openssl/asn1.h . +.El +.It Cm utf8 +If set to +.Qq yes , +field values are interpreted as UTF8 strings. +.It Cm x509_extensions +The configuration file section containing a list of +extensions to add to a certificate generated when the +.Fl x509 +switch is used. +It can be overridden by the +.Fl extensions +command line switch. +.El +.Pp +There are two separate formats for the distinguished name and attribute +sections. +If the +.Fl prompt +option is set to +.Qq no , +then these sections just consist of field names and values. +If the +.Fl prompt +option is absent or not set to +.Qq no , +then the file contains field prompting information of the form: +.Bd -unfilled -offset indent +fieldName="prompt" +fieldName_default="default field value" +fieldName_min= 2 +fieldName_max= 4 +.Ed +.Pp +.Qq fieldName +is the field name being used, for example +.Cm commonName +(or CN). +The +.Qq prompt +string is used to ask the user to enter the relevant details. +If the user enters nothing, the default value is used; +if no default value is present, the field is omitted. +A field can still be omitted if a default value is present, +if the user just enters the +.Sq \&. +character. +.Pp +The number of characters entered must be between the +fieldName_min and fieldName_max limits: +there may be additional restrictions based on the field being used +(for example +.Cm countryName +can only ever be two characters long and must fit in a +.Cm PrintableString ) . +.Pp +Some fields (such as +.Cm organizationName ) +can be used more than once in a DN. +This presents a problem because configuration files will +not recognize the same name occurring twice. +To avoid this problem, if the +.Cm fieldName +contains some characters followed by a full stop, they will be ignored. +So, for example, a second +.Cm organizationName +can be input by calling it +.Qq 1.organizationName . +.Pp +The actual permitted field names are any object identifier short or +long names. +These are compiled into +.Nm openssl +and include the usual values such as +.Cm commonName , countryName , localityName , organizationName , +.Cm organizationUnitName , stateOrProvinceName . +Additionally, +.Cm emailAddress +is included as well as +.Cm name , surname , givenName , initials +and +.Cm dnQualifier . +.Pp +Additional object identifiers can be defined with the +.Cm oid_file +or +.Cm oid_section +options in the configuration file. +Any additional fields will be treated as though they were a +.Cm DirectoryString . +.Sh RSA +.nr nS 1 +.Nm "openssl rsa" +.Op Fl aes128 | aes192 | aes256 | des | des3 +.Op Fl check +.Op Fl in Ar file +.Op Fl inform Cm der | net | pem +.Op Fl modulus +.Op Fl noout +.Op Fl out Ar file +.Op Fl outform Cm der | net | pem +.Op Fl passin Ar arg +.Op Fl passout Ar arg +.Op Fl pubin +.Op Fl pubout +.Op Fl sgckey +.Op Fl text +.nr nS 0 +.Pp +The +.Nm rsa +command processes RSA keys. +They can be converted between various forms and their components printed out. +.Nm rsa +uses the traditional +.Nm SSLeay +compatible format for private key encryption: +newer applications should use the more secure PKCS#8 format using the +.Nm pkcs8 +utility. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl aes128 | aes192 | aes256 | des | des3 +Encrypt the private key with the AES, DES, +or the triple DES ciphers, respectively, before outputting it. +A pass phrase is prompted for. +If none of these options are specified, the key is written in plain text. +This means that using the +.Nm rsa +utility to read in an encrypted key with no encryption option can be used +to remove the pass phrase from a key, or by setting the encryption options +it can be used to add or change the pass phrase. +These options can only be used with PEM format output files. +.It Fl check +Check the consistency of an RSA private key. +.It Fl in Ar file +The input file to read from, +or standard input if not specified. +If the key is encrypted, a pass phrase will be prompted for. +.It Fl inform Cm der | net | pem +The input format. +.It Fl noout +Do not output the encoded version of the key. +.It Fl modulus +Print the value of the modulus of the key. +.It Fl out Ar file +The output file to write to, +or standard output if not specified. +.It Fl outform Cm der | net | pem +The output format. +.It Fl passin Ar arg +The key password source. +.It Fl passout Ar arg +The output file password source. +.It Fl pubin +Read in a public key, +not a private key. +.It Fl pubout +Output a public key, +not a private key. +Automatically set if the input is a public key. +.It Fl sgckey +Use the modified NET algorithm used with some versions of Microsoft IIS +and SGC keys. +.It Fl text +Print the public/private key components in plain text. +.El +.Sh RSAUTL +.nr nS 1 +.Nm "openssl rsautl" +.Op Fl asn1parse +.Op Fl certin +.Op Fl decrypt +.Op Fl encrypt +.Op Fl hexdump +.Op Fl in Ar file +.Op Fl inkey Ar file +.Op Fl keyform Cm der | pem +.Op Fl oaep | pkcs | raw | ssl +.Op Fl out Ar file +.Op Fl pubin +.Op Fl sign +.Op Fl verify +.nr nS 0 +.Pp +The +.Nm rsautl +command can be used to sign, verify, encrypt and decrypt +data using the RSA algorithm. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl asn1parse +Asn1parse the output data; this is useful when combined with the +.Fl verify +option. +.It Fl certin +The input is a certificate containing an RSA public key. +.It Fl decrypt +Decrypt the input data using an RSA private key. +.It Fl encrypt +Encrypt the input data using an RSA public key. +.It Fl hexdump +Hex dump the output data. +.It Fl in Ar file +The input to read from, +or standard input if not specified. +.It Fl inkey Ar file +The input key file; by default an RSA private key. +.It Fl keyform Cm der | pem +The private ket format. +The default is +.Cm pem . +.It Fl oaep | pkcs | raw | ssl +The padding to use: +PKCS#1 OAEP, PKCS#1 v1.5 (the default), or no padding, respectively. +For signatures, only +.Fl pkcs +and +.Fl raw +can be used. +.It Fl out Ar file +The output file to write to, +or standard output if not specified. +.It Fl pubin +The input file is an RSA public key. +.It Fl sign +Sign the input data and output the signed result. +This requires an RSA private key. +.It Fl verify +Verify the input data and output the recovered data. +.El +.Sh S_CLIENT +.nr nS 1 +.Nm "openssl s_client" +.Op Fl 4 | 6 +.Op Fl bugs +.Op Fl CAfile Ar file +.Op Fl CApath Ar directory +.Op Fl cert Ar file +.Op Fl check_ss_sig +.Op Fl cipher Ar cipherlist +.Op Fl connect Ar host Ns Op : Ns Ar port +.Op Fl crl_check +.Op Fl crl_check_all +.Op Fl crlf +.Op Fl debug +.Op Fl extended_crl +.Op Fl ign_eof +.Op Fl ignore_critical +.Op Fl issuer_checks +.Op Fl key Ar keyfile +.Op Fl msg +.Op Fl nbio +.Op Fl nbio_test +.Op Fl no_ticket +.Op Fl no_tls1 +.Op Fl no_tls1_1 +.Op Fl no_tls1_2 +.Op Fl pause +.Op Fl policy_check +.Op Fl prexit +.Op Fl proxy Ar host : Ns Ar port +.Op Fl psk Ar key +.Op Fl psk_identity Ar identity +.Op Fl quiet +.Op Fl reconnect +.Op Fl servername Ar name +.Op Fl showcerts +.Op Fl starttls Ar protocol +.Op Fl state +.Op Fl tls1 +.Op Fl tls1_1 +.Op Fl tls1_2 +.Op Fl tlsextdebug +.Op Fl verify Ar depth +.Op Fl x509_strict +.Op Fl xmpphost Ar host +.nr nS 0 +.Pp +The +.Nm s_client +command implements a generic SSL/TLS client which connects +to a remote host using SSL/TLS. +.Pp +If a connection is established with an SSL server, any data received +from the server is displayed and any key presses will be sent to the +server. +When used interactively (which means neither +.Fl quiet +nor +.Fl ign_eof +have been given), the session will be renegotiated if the line begins with an +.Cm R ; +if the line begins with a +.Cm Q +or if end of file is reached, the connection will be closed down. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl 4 +Attempt connections using IPv4 only. +.It Fl 6 +Attempt connections using IPv6 only. +.It Fl bugs +Enable various workarounds for buggy implementations. +.It Fl CAfile Ar file +A +.Ar file +containing trusted certificates to use during server authentication +and to use when attempting to build the client certificate chain. +.It Fl CApath Ar directory +The +.Ar directory +to use for server certificate verification. +This directory must be in +.Qq hash format ; +see +.Fl verify +for more information. +These are also used when building the client certificate chain. +.It Fl cert Ar file +The certificate to use, if one is requested by the server. +The default is not to use a certificate. +.It Xo +.Fl check_ss_sig , +.Fl crl_check , +.Fl crl_check_all , +.Fl extended_crl , +.Fl ignore_critical , +.Fl issuer_checks , +.Fl policy_check , +.Fl x509_strict +.Xc +Set various certificate chain validation options. +See the +.Nm verify +command for details. +.It Fl cipher Ar cipherlist +Modify the cipher list sent by the client. +Although the server determines which cipher suite is used, it should take +the first supported cipher in the list sent by the client. +See the +.Nm ciphers +command for more information. +.It Fl connect Ar host Ns Op : Ns Ar port +The +.Ar host +and +.Ar port +to connect to. +If not specified, an attempt is made to connect to the local host +on port 4433. +Alternatively, the host and port pair may be separated using a forward-slash +character, +which is useful for numeric IPv6 addresses. +.It Fl crlf +Translate a line feed from the terminal into CR+LF, +as required by some servers. +.It Fl debug +Print extensive debugging information, including a hex dump of all traffic. +.It Fl ign_eof +Inhibit shutting down the connection when end of file is reached in the input. +.It Fl key Ar keyfile +The private key to use. +If not specified, the certificate file will be used. +.It Fl msg +Show all protocol messages with hex dump. +.It Fl nbio +Turn on non-blocking I/O. +.It Fl nbio_test +Test non-blocking I/O. +.It Fl no_tls1 | no_tls1_1 | no_tls1_2 +Disable the use of TLS1.0, 1.1, and 1.2, respectively. +.It Fl no_ticket +Disable RFC 4507 session ticket support. +.It Fl pause +Pause 1 second between each read and write call. +.It Fl prexit +Print session information when the program exits. +This will always attempt +to print out information even if the connection fails. +Normally, information will only be printed out once if the connection succeeds. +This option is useful because the cipher in use may be renegotiated +or the connection may fail because a client certificate is required or is +requested only after an attempt is made to access a certain URL. +Note that the output produced by this option is not always accurate +because a connection might never have been established. +.It Fl proxy Ar host : Ns Ar port +Use the HTTP proxy at +.Ar host +and +.Ar port . +The connection to the proxy is done in cleartext and the +.Fl connect +argument is given to the proxy. +If not specified, localhost is used as final destination. +After that, switch the connection through the proxy to the destination +to TLS. +.It Fl psk Ar key +Use the PSK key +.Ar key +when using a PSK cipher suite. +The key is given as a hexadecimal number without the leading 0x, +for example -psk 1a2b3c4d. +.It Fl psk_identity Ar identity +Use the PSK +.Ar identity +when using a PSK cipher suite. +.It Fl quiet +Inhibit printing of session and certificate information. +This implicitly turns on +.Fl ign_eof +as well. +.It Fl reconnect +Reconnect to the same server 5 times using the same session ID; this can +be used as a test that session caching is working. +.It Fl servername Ar name +Include the TLS Server Name Indication (SNI) extension in the ClientHello +message, using the specified server +.Ar name . +.It Fl showcerts +Display the whole server certificate chain: normally only the server +certificate itself is displayed. +.It Fl starttls Ar protocol +Send the protocol-specific messages to switch to TLS for communication. +.Ar protocol +is a keyword for the intended protocol. +Currently, the supported keywords are +.Qq ftp , +.Qq imap , +.Qq smtp , +.Qq pop3 , +and +.Qq xmpp . +.It Fl state +Print the SSL session states. +.It Fl tls1 | tls1_1 | tls1_2 +Permit only TLS1.0, 1.1, or 1.2, respectively. +.It Fl tlsextdebug +Print a hex dump of any TLS extensions received from the server. +.It Fl verify Ar depth +Turn on server certificate verification, +with a maximum length of +.Ar depth . +Currently the verify operation continues after errors so all the problems +with a certificate chain can be seen. +As a side effect the connection will never fail due to a server +certificate verify failure. +.It Fl xmpphost Ar hostname +When used with +.Fl starttls Ar xmpp , +specify the host for the "to" attribute of the stream element. +If this option is not specified then the host specified with +.Fl connect +will be used. +.El +.Sh S_SERVER +.nr nS 1 +.Nm "openssl s_server" +.Op Fl accept Ar port +.Op Fl bugs +.Op Fl CAfile Ar file +.Op Fl CApath Ar directory +.Op Fl cert Ar file +.Op Fl cipher Ar cipherlist +.Op Fl context Ar id +.Op Fl crl_check +.Op Fl crl_check_all +.Op Fl crlf +.Op Fl dcert Ar file +.Op Fl debug +.Op Fl dhparam Ar file +.Op Fl dkey Ar file +.Op Fl hack +.Op Fl HTTP +.Op Fl id_prefix Ar arg +.Op Fl key Ar keyfile +.Op Fl msg +.Op Fl nbio +.Op Fl nbio_test +.Op Fl no_dhe +.Op Fl no_tls1 +.Op Fl no_tls1_1 +.Op Fl no_tls1_2 +.Op Fl no_tmp_rsa +.Op Fl nocert +.Op Fl psk Ar key +.Op Fl psk_hint Ar hint +.Op Fl quiet +.Op Fl serverpref +.Op Fl state +.Op Fl tls1 +.Op Fl tls1_1 +.Op Fl tls1_2 +.Op Fl Verify Ar depth +.Op Fl verify Ar depth +.Op Fl WWW +.Op Fl www +.nr nS 0 +.Pp +The +.Nm s_server +command implements a generic SSL/TLS server which listens +for connections on a given port using SSL/TLS. +.Pp +If a connection request is established with a client and neither the +.Fl www +nor the +.Fl WWW +option has been used, then any data received +from the client is displayed and any key presses are sent to the client. +Certain single letter commands perform special operations: +.Pp +.Bl -tag -width "XXXX" -compact +.It Ic P +Send plain text, which should cause the client to disconnect. +.It Ic Q +End the current SSL connection and exit. +.It Ic q +End the current SSL connection, but still accept new connections. +.It Ic R +Renegotiate the SSL session and request a client certificate. +.It Ic r +Renegotiate the SSL session. +.It Ic S +Print out some session cache status information. +.El +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl accept Ar port +Listen on TCP +.Ar port +for connections. +The default is port 4433. +.It Fl bugs +Enable various workarounds for buggy implementations. +.It Fl CAfile Ar file +A +.Ar file +containing trusted certificates to use during client authentication +and to use when attempting to build the server certificate chain. +The list is also used in the list of acceptable client CAs passed to the +client when a certificate is requested. +.It Fl CApath Ar directory +The +.Ar directory +to use for client certificate verification. +This directory must be in +.Qq hash format ; +see +.Fl verify +for more information. +These are also used when building the server certificate chain. +.It Fl cert Ar file +The certificate to use: most server's cipher suites require the use of a +certificate and some require a certificate with a certain public key type. +For example, the DSS cipher suites require a certificate containing a DSS +(DSA) key. +If not specified, the file +.Pa server.pem +will be used. +.It Fl cipher Ar cipherlist +Modify the cipher list used by the server. +This allows the cipher list used by the server to be modified. +When the client sends a list of supported ciphers, the first client cipher +also included in the server list is used. +Because the client specifies the preference order, the order of the server +cipherlist is irrelevant. +See the +.Nm ciphers +command for more information. +.It Fl context Ar id +Set the SSL context ID. +It can be given any string value. +.It Fl crl_check , crl_check_all +Check the peer certificate has not been revoked by its CA. +The CRLs are appended to the certificate file. +.Fl crl_check_all +checks all CRLs of all CAs in the chain. +.It Fl crlf +Translate a line feed from the terminal into CR+LF. +.It Fl dcert Ar file , Fl dkey Ar file +Specify an additional certificate and private key; these behave in the +same manner as the +.Fl cert +and +.Fl key +options except there is no default if they are not specified +(no additional certificate or key is used). +By using RSA and DSS certificates and keys, +a server can support clients which only support RSA or DSS cipher suites +by using an appropriate certificate. +.It Fl debug +Print extensive debugging information, including a hex dump of all traffic. +.It Fl dhparam Ar file +The DH parameter file to use. +The ephemeral DH cipher suites generate keys +using a set of DH parameters. +If not specified, an attempt is made to +load the parameters from the server certificate file. +If this fails, a static set of parameters hard coded into the +.Nm s_server +program will be used. +.It Fl hack +Enables a further workaround for some early Netscape SSL code. +.It Fl HTTP +Emulate a simple web server. +Pages are resolved relative to the current directory. +For example if the URL +.Pa https://myhost/page.html +is requested, the file +.Pa ./page.html +will be loaded. +The files loaded are assumed to contain a complete and correct HTTP +response (lines that are part of the HTTP response line and headers +must end with CRLF). +.It Fl id_prefix Ar arg +Generate SSL/TLS session IDs prefixed by +.Ar arg . +This is mostly useful for testing any SSL/TLS code +that wish to deal with multiple servers, +when each of which might be generating a unique range of session IDs. +.It Fl key Ar keyfile +The private key to use. +If not specified, the certificate file will be used. +.It Fl msg +Show all protocol messages with hex dump. +.It Fl nbio +Turn on non-blocking I/O. +.It Fl nbio_test +Test non-blocking I/O. +.It Fl no_dhe +Disable ephemeral DH cipher suites. +.It Fl no_tls1 | no_tls1_1 | no_tls1_2 +Disable the use of TLS1.0, 1.1, and 1.2, respectively. +.It Fl no_tmp_rsa +Disable temporary RSA key generation. +.It Fl nocert +Do not use a certificate. +This restricts the cipher suites available to the anonymous ones +(currently just anonymous DH). +.It Fl psk Ar key +Use the PSK key +.Ar key +when using a PSK cipher suite. +The key is given as a hexadecimal number without the leading 0x, +for example -psk 1a2b3c4d. +.It Fl psk_hint Ar hint +Use the PSK identity hint +.Ar hint +when using a PSK cipher suite. +.It Fl quiet +Inhibit printing of session and certificate information. +.It Fl serverpref +Use server's cipher preferences. +.It Fl state +Print the SSL session states. +.It Fl tls1 | tls1_1 | tls1_2 +Permit only TLS1.0, 1.1, or 1.2, respectively. +.It Fl WWW +Emulate a simple web server. +Pages are resolved relative to the current directory. +For example if the URL +.Pa https://myhost/page.html +is requested, the file +.Pa ./page.html +will be loaded. +.It Fl www +Send a status message to the client when it connects, +including information about the ciphers used and various session parameters. +The output is in HTML format so this option will normally be used with a +web browser. +.It Fl Verify Ar depth , Fl verify Ar depth +Request a certificate chain from the client, +with a maximum length of +.Ar depth . +With +.Fl Verify , +the client must supply a certificate or an error occurs; +with +.Fl verify , +a certificate is requested but the client does not have to send one. +.El +.Sh S_TIME +.nr nS 1 +.Nm "openssl s_time" +.Op Fl bugs +.Op Fl CAfile Ar file +.Op Fl CApath Ar directory +.Op Fl cert Ar file +.Op Fl cipher Ar cipherlist +.Op Fl connect Ar host Ns Op : Ns Ar port +.Op Fl key Ar keyfile +.Op Fl nbio +.Op Fl new +.Op Fl no_shutdown +.Op Fl reuse +.Op Fl time Ar seconds +.Op Fl verify Ar depth +.Op Fl www Ar page +.nr nS 0 +.Pp +The +.Nm s_time +command implements a generic SSL/TLS client which connects to a +remote host using SSL/TLS. +It can request a page from the server and includes +the time to transfer the payload data in its timing measurements. +It measures the number of connections within a given timeframe, +the amount of data transferred +.Pq if any , +and calculates the average time spent for one connection. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl bugs +Enable various workarounds for buggy implementations. +.It Fl CAfile Ar file +A +.Ar file +containing trusted certificates to use during server authentication +and to use when attempting to build the client certificate chain. +.It Fl CApath Ar directory +The directory to use for server certificate verification. +This directory must be in +.Qq hash format ; +see +.Nm verify +for more information. +These are also used when building the client certificate chain. +.It Fl cert Ar file +The certificate to use, if one is requested by the server. +The default is not to use a certificate. +.It Fl cipher Ar cipherlist +Modify the cipher list sent by the client. +Although the server determines which cipher suite is used, +it should take the first supported cipher in the list sent by the client. +See the +.Nm ciphers +command for more information. +.It Fl connect Ar host Ns Op : Ns Ar port +The host and port to connect to. +.It Fl key Ar keyfile +The private key to use. +If not specified, the certificate file will be used. +.It Fl nbio +Turn on non-blocking I/O. +.It Fl new +Perform the timing test using a new session ID for each connection. +If neither +.Fl new +nor +.Fl reuse +are specified, +they are both on by default and executed in sequence. +.It Fl no_shutdown +Shut down the connection without sending a +.Qq close notify +shutdown alert to the server. +.It Fl reuse +Perform the timing test using the same session ID for each connection. +If neither +.Fl new +nor +.Fl reuse +are specified, +they are both on by default and executed in sequence. +.It Fl time Ar seconds +Limit +.Nm s_time +benchmarks to the number of +.Ar seconds . +The default is 30 seconds. +.It Fl verify Ar depth +Turn on server certificate verification, +with a maximum length of +.Ar depth . +Currently the verify operation continues after errors, so all the problems +with a certificate chain can be seen. +As a side effect, +the connection will never fail due to a server certificate verify failure. +.It Fl www Ar page +The page to GET from the server. +A value of +.Sq / +gets the index.htm[l] page. +If this parameter is not specified, +.Nm s_time +will only perform the handshake to establish SSL connections +but not transfer any payload data. +.El +.Sh SESS_ID +.nr nS 1 +.Nm "openssl sess_id" +.Op Fl cert +.Op Fl context Ar ID +.Op Fl in Ar file +.Op Fl inform Cm der | pem +.Op Fl noout +.Op Fl out Ar file +.Op Fl outform Cm der | pem +.Op Fl text +.nr nS 0 +.Pp +The +.Nm sess_id +program processes the encoded version of the SSL session structure and +optionally prints out SSL session details +(for example the SSL session master key) +in human-readable format. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl cert +If a certificate is present in the session, +it will be output using this option; +if the +.Fl text +option is also present, then it will be printed out in text form. +.It Fl context Ar ID +Set the session +.Ar ID . +The ID can be any string of characters. +.It Fl in Ar file +The input file to read from, +or standard input if not specified. +.It Fl inform Cm der | pem +The input format. +.Cm der +uses an ASN.1 DER-encoded format containing session details. +The precise format can vary from one version to the next. +.Cm pem +is the default format: it consists of the DER +format base64-encoded with additional header and footer lines. +.It Fl noout +Do not output the encoded version of the session. +.It Fl out Ar file +The output file to write to, +or standard output if not specified. +.It Fl outform Cm der | pem +The output format. +.It Fl text +Print the various public or private key components in plain text, +in addition to the encoded version. +.El +.Pp +The output of +.Nm sess_id +is composed as follows: +.Pp +.Bl -tag -width "Verify return code " -offset 3n -compact +.It Protocol +The protocol in use. +.It Cipher +The actual raw SSL or TLS cipher code. +.It Session-ID +The SSL session ID, in hex format. +.It Session-ID-ctx +The session ID context, in hex format. +.It Master-Key +The SSL session master key. +.It Key-Arg +The key argument; this is only used in SSL v2. +.It Start Time +The session start time. +.Ux +format. +.It Timeout +The timeout, in seconds. +.It Verify return code +The return code when a certificate is verified. +.El +.Pp +Since the SSL session output contains the master key, it is possible to read +the contents of an encrypted session using this information. +Therefore appropriate security precautions +should be taken if the information is being output by a +.Qq real +application. +This is, however, strongly discouraged and should only be used for +debugging purposes. +.Sh SMIME +.nr nS 1 +.Nm "openssl smime" +.Oo +.Fl aes128 | aes192 | aes256 | des | +.Fl des3 | rc2-40 | rc2-64 | rc2-128 +.Oc +.Op Fl binary +.Op Fl CAfile Ar file +.Op Fl CApath Ar directory +.Op Fl certfile Ar file +.Op Fl check_ss_sig +.Op Fl content Ar file +.Op Fl crl_check +.Op Fl crl_check_all +.Op Fl decrypt +.Op Fl encrypt +.Op Fl extended_crl +.Op Fl from Ar addr +.Op Fl ignore_critical +.Op Fl in Ar file +.Op Fl indef +.Op Fl inform Cm der | pem | smime +.Op Fl inkey Ar file +.Op Fl issuer_checks +.Op Fl keyform Cm pem +.Op Fl md Ar digest +.Op Fl noattr +.Op Fl nocerts +.Op Fl nochain +.Op Fl nodetach +.Op Fl noindef +.Op Fl nointern +.Op Fl nosigs +.Op Fl noverify +.Op Fl out Ar file +.Op Fl outform Cm der | pem | smime +.Op Fl passin Ar arg +.Op Fl pk7out +.Op Fl policy_check +.Op Fl recip Ar file +.Op Fl resign +.Op Fl sign +.Op Fl signer Ar file +.Op Fl stream +.Op Fl subject Ar s +.Op Fl text +.Op Fl to Ar addr +.Op Fl verify +.Op Fl x509_strict +.Op Ar cert.pem ... +.nr nS 0 +.Pp +The +.Nm smime +command handles S/MIME mail. +It can encrypt, decrypt, sign, and verify S/MIME messages. +.Pp +The MIME message must be sent without any blank lines between the +headers and the output. +Some mail programs will automatically add a blank line. +Piping the mail directly to an MTA is one way to +achieve the correct format. +.Pp +The supplied message to be signed or encrypted must include the necessary +MIME headers or many S/MIME clients won't display it properly (if at all). +Use the +.Fl text +option to automatically add plain text headers. +.Pp +A +.Qq signed and encrypted +message is one where a signed message is then encrypted. +This can be produced by encrypting an already signed message. +.Pp +There are a number of operations that can be performed, as follows: +.Bl -tag -width "XXXX" +.It Fl decrypt +Decrypt mail using the supplied certificate and private key. +The input file is an encrypted mail message in MIME format. +The decrypted mail is written to the output file. +.It Fl encrypt +Encrypt mail for the given recipient certificates. +The input is the message to be encrypted. +The output file is the encrypted mail, in MIME format. +.It Fl pk7out +Take an input message and write out a PEM-encoded PKCS#7 structure. +.It Fl resign +Resign a message: take an existing message and one or more new signers. +.It Fl sign +Sign mail using the supplied certificate and private key. +The input file is the message to be signed. +The signed message, in MIME format, is written to the output file. +.It Fl verify +Verify signed mail. +The input is a signed mail message and the output is the signed data. +Both clear text and opaque signing is supported. +.El +.Pp +The remaining options are as follows: +.Bl -tag -width "XXXX" +.It Xo +.Fl aes128 | aes192 | aes256 | des | +.Fl des3 | rc2-40 | rc2-64 | rc2-128 +.Xc +The encryption algorithm to use. +128-, 192-, or 256-bit AES, DES (56 bits), triple DES (168 bits), +or 40-, 64-, or 128-bit RC2, respectively; +if not specified, 40-bit RC2 is +used. +Only used with +.Fl encrypt . +.It Fl binary +Normally, the input message is converted to +.Qq canonical +format which uses CR/LF as end of line, +as required by the S/MIME specification. +When this option is present no translation occurs. +This is useful when handling binary data which may not be in MIME format. +.It Fl CAfile Ar file +A +.Ar file +containing trusted CA certificates; only used with +.Fl verify . +.It Fl CApath Ar directory +A +.Ar directory +containing trusted CA certificates; only used with +.Fl verify . +This directory must be a standard certificate directory: +that is, a hash of each subject name (using +.Nm x509 -hash ) +should be linked to each certificate. +.It Ar cert.pem ... +One or more certificates of message recipients: used when encrypting +a message. +.It Fl certfile Ar file +Allows additional certificates to be specified. +When signing, these will be included with the message. +When verifying, these will be searched for the signers' certificates. +The certificates should be in PEM format. +.It Xo +.Fl check_ss_sig , +.Fl crl_check , +.Fl crl_check_all , +.Fl extended_crl , +.Fl ignore_critical , +.Fl issuer_checks , +.Fl policy_check , +.Fl x509_strict +.Xc +Set various certificate chain validation options. +See the +.Nm verify +command for details. +.It Fl content Ar file +A file containing the detached content. +This is only useful with the +.Fl verify +option, +and only usable if the PKCS#7 structure is using the detached +signature form where the content is not included. +This option will override any content if the input format is S/MIME +and it uses the multipart/signed MIME content type. +.It Xo +.Fl from Ar addr , +.Fl subject Ar s , +.Fl to Ar addr +.Xc +The relevant mail headers. +These are included outside the signed +portion of a message so they may be included manually. +When signing, many S/MIME +mail clients check that the signer's certificate email +address matches the From: address. +.It Fl in Ar file +The input file to read from. +.It Fl indef +Enable streaming I/O for encoding operations. +This permits single pass processing of data without +the need to hold the entire contents in memory, +potentially supporting very large files. +Streaming is automatically set for S/MIME signing with detached +data if the output format is SMIME; +it is currently off by default for all other operations. +.It Fl inform Cm der | pem | smime +The input format. +.It Fl inkey Ar file +The private key to use when signing or decrypting, +which must match the corresponding certificate. +If this option is not specified, the private key must be included +in the certificate file specified with +the +.Fl recip +or +.Fl signer +file. +When signing, +this option can be used multiple times to specify successive keys. +.It Fl keyform Cm pem +Input private key format. +.It Fl md Ar digest +The digest algorithm to use when signing or resigning. +If not present then the default digest algorithm for the signing key is used +(usually SHA1). +.It Fl noattr +Do not include attributes. +.It Fl nocerts +Do not include the signer's certificate. +This will reduce the size of the signed message but the verifier must +have a copy of the signer's certificate available locally (passed using the +.Fl certfile +option, for example). +.It Fl nochain +Do not do chain verification of signers' certificates: that is, +don't use the certificates in the signed message as untrusted CAs. +.It Fl nodetach +When signing a message use opaque signing: this form is more resistant +to translation by mail relays but it cannot be read by mail agents that +do not support S/MIME. +Without this option cleartext signing with the MIME type +multipart/signed is used. +.It Fl noindef +Disable streaming I/O where it would produce an encoding of indefinite length +(currently has no effect). +.It Fl nointern +Only use certificates specified in the +.Fl certfile . +The supplied certificates can still be used as untrusted CAs. +.It Fl nosigs +Do not try to verify the signatures on the message. +.It Fl noverify +Do not verify the signer's certificate of a signed message. +.It Fl out Ar file +The output file to write to. +.It Fl outform Cm der | pem | smime +The output format. +The default is smime, which writes an S/MIME format message. +.Cm pem +and +.Cm der +change this to write PEM and DER format PKCS#7 structures instead. +This currently only affects the output format of the PKCS#7 +structure; if no PKCS#7 structure is being output (for example with +.Fl verify +or +.Fl decrypt ) +this option has no effect. +.It Fl passin Ar arg +The key password source. +.It Fl recip Ar file +The recipients certificate when decrypting a message. +This certificate +must match one of the recipients of the message or an error occurs. +.It Fl signer Ar file +A signing certificate when signing or resigning a message; +this option can be used multiple times if more than one signer is required. +If a message is being verified, the signer's certificates will be +written to this file if the verification was successful. +.It Fl stream +The same as +.Fl indef . +.It Fl text +Add plain text (text/plain) MIME +headers to the supplied message if encrypting or signing. +If decrypting or verifying, it strips off text headers: +if the decrypted or verified message is not of MIME type text/plain +then an error occurs. +.El +.Pp +The exit codes for +.Nm smime +are as follows: +.Pp +.Bl -tag -width "XXXX" -offset 3n -compact +.It 0 +The operation was completely successful. +.It 1 +An error occurred parsing the command options. +.It 2 +One of the input files could not be read. +.It 3 +An error occurred creating the file or when reading the message. +.It 4 +An error occurred decrypting or verifying the message. +.It 5 +An error occurred writing certificates. +.El +.Sh SPEED +.nr nS 1 +.Nm "openssl speed" +.Op Ar algorithm +.Op Fl decrypt +.Op Fl elapsed +.Op Fl evp Ar algorithm +.Op Fl mr +.Op Fl multi Ar number +.nr nS 0 +.Pp +The +.Nm speed +command is used to test the performance of cryptographic algorithms. +.Bl -tag -width "XXXX" +.It Ar algorithm +Perform the test using +.Ar algorithm . +The default is to test all algorithms. +.It Fl decrypt +Time decryption instead of encryption; +must be used with +.Fl evp . +.It Fl elapsed +Measure time in real time instead of CPU user time. +.It Fl evp Ar algorithm +Perform the test using one of the algorithms accepted by +.Xr EVP_get_cipherbyname 3 . +.It Fl mr +Produce machine readable output. +.It Fl multi Ar number +Run +.Ar number +benchmarks in parallel. +.El +.Sh SPKAC +.nr nS 1 +.Nm "openssl spkac" +.Op Fl challenge Ar string +.Op Fl in Ar file +.Op Fl key Ar keyfile +.Op Fl noout +.Op Fl out Ar file +.Op Fl passin Ar arg +.Op Fl pubkey +.Op Fl spkac Ar spkacname +.Op Fl spksect Ar section +.Op Fl verify +.nr nS 0 +.Pp +The +.Nm spkac +command processes signed public key and challenge (SPKAC) files. +It can print out their contents, verify the signature, +and produce its own SPKACs from a supplied private key. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl challenge Ar string +The challenge string, if an SPKAC is being created. +.It Fl in Ar file +The input file to read from, +or standard input if not specified. +Ignored if the +.Fl key +option is used. +.It Fl key Ar keyfile +Create an SPKAC file using the private key in +.Ar keyfile . +The +.Fl in , noout , spksect , +and +.Fl verify +options are ignored, if present. +.It Fl noout +Do not output the text version of the SPKAC. +.It Fl out Ar file +The output file to write to, +or standard output if not specified. +.It Fl passin Ar arg +The key password source. +.It Fl pubkey +Output the public key of an SPKAC. +.It Fl spkac Ar spkacname +An alternative name for the variable containing the SPKAC. +The default is "SPKAC". +This option affects both generated and input SPKAC files. +.It Fl spksect Ar section +An alternative name for the +.Ar section +containing the SPKAC. +.It Fl verify +Verify the digital signature on the supplied SPKAC. +.El +.Sh TS +.nr nS 1 +.Nm "openssl ts" +.Fl query +.Op Fl md4 | md5 | ripemd160 | sha1 +.Op Fl cert +.Op Fl config Ar configfile +.Op Fl data Ar file_to_hash +.Op Fl digest Ar digest_bytes +.Op Fl in Ar request.tsq +.Op Fl no_nonce +.Op Fl out Ar request.tsq +.Op Fl policy Ar object_id +.Op Fl text +.nr nS 0 +.Pp +.nr nS 1 +.Nm "openssl ts" +.Fl reply +.Op Fl chain Ar certs_file.pem +.Op Fl config Ar configfile +.Op Fl in Ar response.tsr +.Op Fl inkey Ar private.pem +.Op Fl out Ar response.tsr +.Op Fl passin Ar arg +.Op Fl policy Ar object_id +.Op Fl queryfile Ar request.tsq +.Op Fl section Ar tsa_section +.Op Fl signer Ar tsa_cert.pem +.Op Fl text +.Op Fl token_in +.Op Fl token_out +.nr nS 0 +.Pp +.nr nS 1 +.Nm "openssl ts" +.Fl verify +.Op Fl CAfile Ar trusted_certs.pem +.Op Fl CApath Ar trusted_cert_path +.Op Fl data Ar file_to_hash +.Op Fl digest Ar digest_bytes +.Op Fl in Ar response.tsr +.Op Fl queryfile Ar request.tsq +.Op Fl token_in +.Op Fl untrusted Ar cert_file.pem +.nr nS 0 +.Pp +The +.Nm ts +command is a basic Time Stamping Authority (TSA) client and server +application as specified in RFC 3161 (Time-Stamp Protocol, TSP). +A TSA can be part of a PKI deployment and its role is to provide long +term proof of the existence of specific data. +Here is a brief description of the protocol: +.Bl -enum +.It +The TSA client computes a one-way hash value for a data file and sends +the hash to the TSA. +.It +The TSA attaches the current date and time to the received hash value, +signs them and sends the time stamp token back to the client. +By creating this token the TSA certifies the existence of the original +data file at the time of response generation. +.It +The TSA client receives the time stamp token and verifies the +signature on it. +It also checks if the token contains the same hash +value that it had sent to the TSA. +.El +.Pp +There is one DER-encoded protocol data unit defined for transporting a time +stamp request to the TSA and one for sending the time stamp response +back to the client. +The +.Nm ts +command has three main functions: +creating a time stamp request based on a data file; +creating a time stamp response based on a request; +and verifying if a response corresponds +to a particular request or a data file. +.Pp +There is no support for sending the requests/responses automatically +over HTTP or TCP yet as suggested in RFC 3161. +Users must send the requests either by FTP or email. +.Pp +The +.Fl query +switch can be used for creating and printing a time stamp +request with the following options: +.Bl -tag -width Ds +.It Fl cert +Expect the TSA to include its signing certificate in the response. +.It Fl config Ar configfile +Specify an alternative configuration file. +Only the OID section is used. +.It Fl data Ar file_to_hash +The data file for which the time stamp request needs to be created. +The default is standard input. +.It Fl digest Ar digest_bytes +Specify the message imprint explicitly without the data file. +The imprint must be specified in a hexadecimal format, +two characters per byte, +the bytes optionally separated by colons. +The number of bytes must match the message digest algorithm in use. +.It Fl in Ar request.tsq +A previously created time stamp request in DER +format that will be printed into the output file. +Useful for examining the content of a request in human-readable format. +.It Fl md4 | md5 | ripemd160 | sha | sha1 +The message digest to apply to the data file. +It supports all the message digest algorithms that are supported by the +.Nm dgst +command. +The default is SHA-1. +.It Fl no_nonce +Specify no nonce in the request. +The default, to include a 64-bit long pseudo-random nonce, +is recommended to protect against replay attacks. +.It Fl out Ar request.tsq +The output file to write to, +or standard output if not specified. +.It Fl policy Ar object_id +The policy that the client expects the TSA to use for creating the +time stamp token. +Either dotted OID notation or OID names defined +in the config file can be used. +If no policy is requested the TSA uses its own default policy. +.It Fl text +Output in human-readable text format instead of DER. +.El +.Pp +A time stamp response (TimeStampResp) consists of a response status +and the time stamp token itself (ContentInfo), +if the token generation was successful. +The +.Fl reply +command is for creating a time stamp +response or time stamp token based on a request and printing the +response/token in human-readable format. +If +.Fl token_out +is not specified the output is always a time stamp response (TimeStampResp), +otherwise it is a time stamp token (ContentInfo). +.Bl -tag -width Ds +.It Fl chain Ar certs_file.pem +The collection of PEM certificates +that will be included in the response +in addition to the signer certificate if the +.Fl cert +option was used for the request. +This file is supposed to contain the certificate chain +for the signer certificate from its issuer upwards. +The +.Fl reply +command does not build a certificate chain automatically. +.It Fl config Ar configfile +Specify an alternative configuration file. +.It Fl in Ar response.tsr +Specify a previously created time stamp response (or time stamp token, if +.Fl token_in +is also specified) +in DER format that will be written to the output file. +This option does not require a request; +it is useful, for example, +to examine the content of a response or token +or to extract the time stamp token from a response. +If the input is a token and the output is a time stamp response a default +.Qq granted +status info is added to the token. +.It Fl inkey Ar private.pem +The signer private key of the TSA in PEM format. +Overrides the +.Cm signer_key +config file option. +.It Fl out Ar response.tsr +The response is written to this file. +The format and content of the file depends on other options (see +.Fl text +and +.Fl token_out ) . +The default is stdout. +.It Fl passin Ar arg +The key password source. +.It Fl policy Ar object_id +The default policy to use for the response. +Either dotted OID notation or OID names defined +in the config file can be used. +If no policy is requested the TSA uses its own default policy. +.It Fl queryfile Ar request.tsq +The file containing a DER-encoded time stamp request. +.It Fl section Ar tsa_section +The config file section containing the settings for response generation. +.It Fl signer Ar tsa_cert.pem +The PEM signer certificate of the TSA. +The TSA signing certificate must have exactly one extended key usage +assigned to it: timeStamping. +The extended key usage must also be critical, +otherwise the certificate is going to be refused. +Overrides the +.Cm signer_cert +variable of the config file. +.It Fl text +Output in human-readable text format instead of DER. +.It Fl token_in +The input is a DER-encoded time stamp token (ContentInfo) +instead of a time stamp response (TimeStampResp). +.It Fl token_out +The output is a time stamp token (ContentInfo) +instead of a time stamp response (TimeStampResp). +.El +.Pp +The +.Fl verify +command is for verifying if a time stamp response or time stamp token +is valid and matches a particular time stamp request or data file. +The +.Fl verify +command does not use the configuration file. +.Bl -tag -width Ds +.It Fl CAfile Ar trusted_certs.pem +The file containing a set of trusted self-signed PEM CA certificates. +See +.Nm verify +for additional details. +Either this option or +.Fl CApath +must be specified. +.It Fl CApath Ar trusted_cert_path +The directory containing the trused CA certificates of the client. +See +.Nm verify +for additional details. +Either this option or +.Fl CAfile +must be specified. +.It Fl data Ar file_to_hash +The response or token must be verified against +.Ar file_to_hash . +The file is hashed with the message digest algorithm specified in the token. +The +.Fl digest +and +.Fl queryfile +options must not be specified with this one. +.It Fl digest Ar digest_bytes +The response or token must be verified against the message digest specified +with this option. +The number of bytes must match the message digest algorithm +specified in the token. +The +.Fl data +and +.Fl queryfile +options must not be specified with this one. +.It Fl in Ar response.tsr +The time stamp response that needs to be verified, in DER format. +This option in mandatory. +.It Fl queryfile Ar request.tsq +The original time stamp request, in DER format. +The +.Fl data +and +.Fl digest +options must not be specified with this one. +.It Fl token_in +The input is a DER-encoded time stamp token (ContentInfo) +instead of a time stamp response (TimeStampResp). +.It Fl untrusted Ar cert_file.pem +Additional untrusted PEM certificates which may be needed +when building the certificate chain for the TSA's signing certificate. +This file must contain the TSA signing certificate and +all intermediate CA certificates unless the response includes them. +.El +.Pp +Options specified on the command line always override +the settings in the config file: +.Bl -tag -width Ds +.It Cm tsa Ar section , Cm default_tsa +This is the main section and it specifies the name of another section +that contains all the options for the +.Fl reply +option. +This section can be overridden with the +.Fl section +command line switch. +.It Cm oid_file +See +.Nm ca +for a description. +.It Cm oid_section +See +.Nm ca +for a description. +.It Cm serial +The file containing the hexadecimal serial number of the +last time stamp response created. +This number is incremented by 1 for each response. +If the file does not exist at the time of response generation +a new file is created with serial number 1. +This parameter is mandatory. +.It Cm signer_cert +TSA signing certificate, in PEM format. +The same as the +.Fl signer +command line option. +.It Cm certs +A set of PEM-encoded certificates that need to be +included in the response. +The same as the +.Fl chain +command line option. +.It Cm signer_key +The private key of the TSA, in PEM format. +The same as the +.Fl inkey +command line option. +.It Cm default_policy +The default policy to use when the request does not mandate any policy. +The same as the +.Fl policy +command line option. +.It Cm other_policies +Comma separated list of policies that are also acceptable by the TSA +and used only if the request explicitly specifies one of them. +.It Cm digests +The list of message digest algorithms that the TSA accepts. +At least one algorithm must be specified. +This parameter is mandatory. +.It Cm accuracy +The accuracy of the time source of the TSA in seconds, milliseconds +and microseconds. +For example, secs:1, millisecs:500, microsecs:100. +If any of the components is missing, +zero is assumed for that field. +.It Cm clock_precision_digits +The maximum number of digits, which represent the fraction of seconds, +that need to be included in the time field. +The trailing zeroes must be removed from the time, +so there might actually be fewer digits +or no fraction of seconds at all. +The maximum value is 6; +the default is 0. +.It Cm ordering +If this option is yes, +the responses generated by this TSA can always be ordered, +even if the time difference between two responses is less +than the sum of their accuracies. +The default is no. +.It Cm tsa_name +Set this option to yes if the subject name of the TSA must be included in +the TSA name field of the response. +The default is no. +.It Cm ess_cert_id_chain +The SignedData objects created by the TSA always contain the +certificate identifier of the signing certificate in a signed +attribute (see RFC 2634, Enhanced Security Services). +If this option is set to yes and either the +.Cm certs +variable or the +.Fl chain +option is specified then the certificate identifiers of the chain will also +be included in the SigningCertificate signed attribute. +If this variable is set to no, +only the signing certificate identifier is included. +The default is no. +.El +.Sh VERIFY +.nr nS 1 +.Nm "openssl verify" +.Op Fl CAfile Ar file +.Op Fl CApath Ar directory +.Op Fl check_ss_sig +.Op Fl crl_check +.Op Fl crl_check_all +.Op Fl explicit_policy +.Op Fl extended_crl +.Op Fl help +.Op Fl ignore_critical +.Op Fl inhibit_any +.Op Fl inhibit_map +.Op Fl issuer_checks +.Op Fl policy_check +.Op Fl purpose Ar purpose +.Op Fl untrusted Ar file +.Op Fl verbose +.Op Fl x509_strict +.Op Ar certificates +.nr nS 0 +.Pp +The +.Nm verify +command verifies certificate chains. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl check_ss_sig +Verify the signature on the self-signed root CA. +This is disabled by default +because it doesn't add any security. +.It Fl CAfile Ar file +A +.Ar file +of trusted certificates. +The +.Ar file +should contain multiple certificates in PEM format, concatenated together. +.It Fl CApath Ar directory +A +.Ar directory +of trusted certificates. +The certificates, or symbolic links to them, +should have names of the form +.Ar hash Ns .0 , +where +.Ar hash +is the hashed certificate subject name +(see the +.Fl hash +option of the +.Nm x509 +utility). +.It Fl crl_check +Check end entity certificate validity by attempting to look up a valid CRL. +If a valid CRL cannot be found an error occurs. +.It Fl crl_check_all +Check the validity of all certificates in the chain by attempting +to look up valid CRLs. +.It Fl explicit_policy +Set policy variable require-explicit-policy (RFC 3280). +.It Fl extended_crl +Enable extended CRL features such as indirect CRLs and alternate CRL +signing keys. +.It Fl help +Print a usage message. +.It Fl ignore_critical +Ignore critical extensions instead of rejecting the certificate. +.It Fl inhibit_any +Set policy variable inhibit-any-policy (RFC 3280). +.It Fl inhibit_map +Set policy variable inhibit-policy-mapping (RFC 3280). +.It Fl issuer_checks +Print diagnostics relating to searches for the issuer certificate +of the current certificate +showing why each candidate issuer certificate was rejected. +The presence of rejection messages +does not itself imply that anything is wrong: +during the normal verify process several rejections may take place. +.It Fl policy_check +Enable certificate policy processing. +.It Fl purpose Ar purpose +The intended use for the certificate. +Without this option no chain verification will be done. +Currently accepted uses are +.Cm sslclient , sslserver , +.Cm nssslserver , smimesign , +.Cm smimeencrypt , crlsign , +.Cm any , +and +.Cm ocsphelper . +.It Fl untrusted Ar file +A +.Ar file +of untrusted certificates. +The +.Ar file +should contain multiple certificates. +.It Fl verbose +Print extra information about the operations being performed. +.It Fl x509_strict +Disable workarounds for broken certificates which have to be disabled +for strict X.509 compliance. +.It Ar certificates +One or more PEM +.Ar certificates +to verify. +If no certificate files are included, an attempt is made to read +a certificate from standard input. +If the first certificate filename begins with a dash, +use a lone dash to mark the last option. +.El +.Pp +The +.Nm verify +program uses the same functions as the internal SSL and S/MIME verification, +with one crucial difference: +wherever possible an attempt is made to continue after an error, +whereas normally the verify operation would halt on the first error. +This allows all the problems with a certificate chain to be determined. +.Pp +The verify operation consists of a number of separate steps. +Firstly a certificate chain is built up starting from the supplied certificate +and ending in the root CA. +It is an error if the whole chain cannot be built up. +The chain is built up by looking up the issuer's certificate of the current +certificate. +If a certificate is found which is its own issuer, it is assumed +to be the root CA. +.Pp +All certificates whose subject name matches the issuer name +of the current certificate are subject to further tests. +The relevant authority key identifier components of the current certificate +(if present) must match the subject key identifier (if present) +and issuer and serial number of the candidate issuer; +in addition the +.Cm keyUsage +extension of the candidate issuer (if present) must permit certificate signing. +.Pp +The lookup first looks in the list of untrusted certificates and if no match +is found the remaining lookups are from the trusted certificates. +The root CA is always looked up in the trusted certificate list: +if the certificate to verify is a root certificate, +then an exact match must be found in the trusted list. +.Pp +The second operation is to check every untrusted certificate's extensions for +consistency with the supplied purpose. +If the +.Fl purpose +option is not included, then no checks are done. +The supplied or +.Qq leaf +certificate must have extensions compatible with the supplied purpose +and all other certificates must also be valid CA certificates. +The precise extensions required are described in more detail in +the +.Nm X509 +section below. +.Pp +The third operation is to check the trust settings on the root CA. +The root CA should be trusted for the supplied purpose. +A certificate with no trust settings is considered to be valid for +all purposes. +.Pp +The final operation is to check the validity of the certificate chain. +The validity period is checked against the current system time and the +.Cm notBefore +and +.Cm notAfter +dates in the certificate. +The certificate signatures are also checked at this point. +.Pp +If all operations complete successfully, the certificate is considered +valid. +If any operation fails then the certificate is not valid. +When a verify operation fails, the output messages can be somewhat cryptic. +The general form of the error message is: +.Bd -literal +server.pem: /C=AU/ST=Queensland/O=CryptSoft Pty Ltd/CN=Test CA (1024-bit) +error 24 at 1 depth lookup:invalid CA certificate +.Ed +.Pp +The first line contains the name of the certificate being verified, followed by +the subject name of the certificate. +The second line contains the error number and the depth. +The depth is the number of the certificate being verified when a +problem was detected starting with zero for the certificate being verified +itself, then 1 for the CA that signed the certificate and so on. +Finally a text version of the error number is presented. +.Pp +An exhaustive list of the error codes and messages is shown below; this also +includes the name of the error code as defined in the header file +.In openssl/x509_vfy.h . +Some of the error codes are defined but never returned: these are described as +.Qq unused . +.Bl -tag -width "XXXX" +.It 0 X509_V_OK +The operation was successful. +.It 2 X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT +The issuer certificate of an untrusted certificate could not be found. +.It 3 X509_V_ERR_UNABLE_TO_GET_CRL +The CRL of a certificate could not be found. +.It 4 X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE +The certificate signature could not be decrypted. +This means that the actual signature value could not be determined +rather than it not matching the expected value. +This is only meaningful for RSA keys. +.It 5 X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE +The CRL signature could not be decrypted. +This means that the actual signature value could not be determined +rather than it not matching the expected value. +Unused. +.It 6 X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY +The public key in the certificate +.Cm SubjectPublicKeyInfo +could not be read. +.It 7 X509_V_ERR_CERT_SIGNATURE_FAILURE +The signature of the certificate is invalid. +.It 8 X509_V_ERR_CRL_SIGNATURE_FAILURE +The signature of the certificate is invalid. +.It 9 X509_V_ERR_CERT_NOT_YET_VALID +The certificate is not yet valid: the +.Cm notBefore +date is after the current time. +.It 10 X509_V_ERR_CERT_HAS_EXPIRED +The certificate has expired; that is, the +.Cm notAfter +date is before the current time. +.It 11 X509_V_ERR_CRL_NOT_YET_VALID +The CRL is not yet valid. +.It 12 X509_V_ERR_CRL_HAS_EXPIRED +The CRL has expired. +.It 13 X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD +The certificate +.Cm notBefore +field contains an invalid time. +.It 14 X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD +The certificate +.Cm notAfter +field contains an invalid time. +.It 15 X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD +The CRL +.Cm lastUpdate +field contains an invalid time. +.It 16 X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD +The CRL +.Cm nextUpdate +field contains an invalid time. +.It 17 X509_V_ERR_OUT_OF_MEM +An error occurred trying to allocate memory. +This should never happen. +.It 18 X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT +The passed certificate is self-signed and the same certificate cannot be +found in the list of trusted certificates. +.It 19 X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN +The certificate chain could be built up using the untrusted certificates but +the root could not be found locally. +.It 20 X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY +The issuer certificate of a locally looked up certificate could not be found. +This normally means the list of trusted certificates is not complete. +.It 21 X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE +No signatures could be verified because the chain contains only one +certificate and it is not self-signed. +.It 22 X509_V_ERR_CERT_CHAIN_TOO_LONG +The certificate chain length is greater than the supplied maximum depth. +Unused. +.It 23 X509_V_ERR_CERT_REVOKED +The certificate has been revoked. +.It 24 X509_V_ERR_INVALID_CA +A CA certificate is invalid. +Either it is not a CA or its extensions are not consistent +with the supplied purpose. +.It 25 X509_V_ERR_PATH_LENGTH_EXCEEDED +The +.Cm basicConstraints +pathlength parameter has been exceeded. +.It 26 X509_V_ERR_INVALID_PURPOSE +The supplied certificate cannot be used for the specified purpose. +.It 27 X509_V_ERR_CERT_UNTRUSTED +The root CA is not marked as trusted for the specified purpose. +.It 28 X509_V_ERR_CERT_REJECTED +The root CA is marked to reject the specified purpose. +.It 29 X509_V_ERR_SUBJECT_ISSUER_MISMATCH +The current candidate issuer certificate was rejected because its subject name +did not match the issuer name of the current certificate. +Only displayed when the +.Fl issuer_checks +option is set. +.It 30 X509_V_ERR_AKID_SKID_MISMATCH +The current candidate issuer certificate was rejected because its subject key +identifier was present and did not match the authority key identifier current +certificate. +Only displayed when the +.Fl issuer_checks +option is set. +.It 31 X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH +The current candidate issuer certificate was rejected because its issuer name +and serial number were present and did not match the authority key identifier +of the current certificate. +Only displayed when the +.Fl issuer_checks +option is set. +.It 32 X509_V_ERR_KEYUSAGE_NO_CERTSIGN +The current candidate issuer certificate was rejected because its +.Cm keyUsage +extension does not permit certificate signing. +.It 50 X509_V_ERR_APPLICATION_VERIFICATION +An application specific error. +Unused. +.El +.Sh VERSION +.Nm openssl version +.Op Fl abdfopv +.Pp +The +.Nm version +command is used to print out version information about +.Nm openssl . +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl a +All information: this is the same as setting all the other flags. +.It Fl b +The date the current version of +.Nm openssl +was built. +.It Fl d +.Ev OPENSSLDIR +setting. +.It Fl f +Compilation flags. +.It Fl o +Option information: various options set when the library was built. +.It Fl p +Platform setting. +.It Fl v +The current +.Nm openssl +version. +.El +.Sh X509 +.nr nS 1 +.Nm "openssl x509" +.Op Fl C +.Op Fl addreject Ar arg +.Op Fl addtrust Ar arg +.Op Fl alias +.Op Fl CA Ar file +.Op Fl CAcreateserial +.Op Fl CAform Cm der | pem +.Op Fl CAkey Ar file +.Op Fl CAkeyform Cm der | pem +.Op Fl CAserial Ar file +.Op Fl certopt Ar option +.Op Fl checkend Ar arg +.Op Fl clrext +.Op Fl clrreject +.Op Fl clrtrust +.Op Fl dates +.Op Fl days Ar arg +.Op Fl email +.Op Fl enddate +.Op Fl extensions Ar section +.Op Fl extfile Ar file +.Op Fl fingerprint +.Op Fl hash +.Op Fl in Ar file +.Op Fl inform Cm der | net | pem +.Op Fl issuer +.Op Fl issuer_hash +.Op Fl issuer_hash_old +.Op Fl keyform Cm der | pem +.Op Fl md5 | sha1 +.Op Fl modulus +.Op Fl nameopt Ar option +.Op Fl noout +.Op Fl ocsp_uri +.Op Fl ocspid +.Op Fl out Ar file +.Op Fl outform Cm der | net | pem +.Op Fl passin Ar arg +.Op Fl pubkey +.Op Fl purpose +.Op Fl req +.Op Fl serial +.Op Fl set_serial Ar n +.Op Fl setalias Ar arg +.Op Fl signkey Ar file +.Op Fl startdate +.Op Fl subject +.Op Fl subject_hash +.Op Fl subject_hash_old +.Op Fl text +.Op Fl trustout +.Op Fl x509toreq +.nr nS 0 +.Pp +The +.Nm x509 +command is a multi-purpose certificate utility. +It can be used to display certificate information, convert certificates to +various forms, sign certificate requests like a +.Qq mini CA , +or edit certificate trust settings. +.Pp +The following are x509 input, output, and general purpose options: +.Bl -tag -width "XXXX" +.It Fl in Ar file +The input file to read from, +or standard input if not specified. +.It Fl inform Cm der | net | pem +The input format. +Normally, the command will expect an X.509 certificate, +but this can change if other options such as +.Fl req +are present. +.It Fl md5 | sha1 +The digest to use. +This affects any signing or display option that uses a message digest, +such as the +.Fl fingerprint , signkey , +and +.Fl CA +options. +If not specified, MD5 is used. +SHA1 is always used with DSA keys. +.It Fl out Ar file +The output file to write to, +or standard output if none is specified. +.It Fl outform Cm der | net | pem +The output format. +.It Fl passin Ar arg +The key password source. +.El +.Pp +The following are x509 display options: +.Bl -tag -width "XXXX" +.It Fl C +Output the certificate in the form of a C source file. +.It Fl certopt Ar option +Customise the output format used with +.Fl text , +either using a list of comma-separated options or by specifying +.Fl certopt +multiple times. +The default behaviour is to print all fields. +The options are as follows: +.Pp +.Bl -tag -width "no_extensions" -offset indent -compact +.It Cm ca_default +Equivalent to +.Cm no_issuer , no_pubkey , no_header , +.Cm no_version , no_sigdump , +and +.Cm no_signame . +.It Cm compatible +Equivalent to no output options at all. +.It Cm ext_default +Print unsupported certificate extensions. +.It Cm ext_dump +Hex dump unsupported extensions. +.It Cm ext_error +Print an error message for unsupported certificate extensions. +.It Cm ext_parse +ASN.1 parse unsupported extensions. +.It Cm no_aux +Do not print certificate trust information. +.It Cm no_extensions +Do not print X509V3 extensions. +.It Cm no_header +Do not print header (Certificate and Data) information. +.It Cm no_issuer +Do not print the issuer name. +.It Cm no_pubkey +Do not print the public key. +.It Cm no_serial +Do not print the serial number. +.It Cm no_sigdump +Do not give a hexadecimal dump of the certificate signature. +.It Cm no_signame +Do not print the signature algorithm used. +.It Cm no_subject +Do not print the subject name. +.It Cm no_validity +Do not print the +.Cm notBefore +and +.Cm notAfter +(validity) fields. +.It Cm no_version +Do not print the version number. +.El +.It Fl dates +Print the start and expiry date of a certificate. +.It Fl email +Output the email addresses, if any. +.It Fl enddate +Print the expiry date of the certificate; that is, the +.Cm notAfter +date. +.It Fl fingerprint +Print the digest of the DER-encoded version of the whole certificate. +.It Fl hash +A synonym for +.Fl subject_hash . +.It Fl issuer +Print the issuer name. +.It Fl issuer_hash +Print the hash of the certificate issuer name. +.It Fl issuer_hash_old +Print the hash of the certificate issuer name +using the older algorithm as used by +.Nm openssl +versions before 1.0.0. +.It Fl modulus +Print the value of the modulus of the public key contained in the certificate. +.It Fl nameopt Ar option +Customise how the subject or issuer names are displayed, +either using a list of comma-separated options or by specifying +.Fl nameopt +multiple times. +The default behaviour is to use the +.Cm oneline +format. +The options, +which can be preceded by a dash to turn them off, +are as follows: +.Bl -tag -width "XXXX" +.It Cm align +Align field values for a more readable output. +Only usable with +.Ar sep_multiline . +.It Cm compat +Use the old format, +equivalent to specifying no options at all. +.It Cm dn_rev +Reverse the fields of the DN, as required by RFC 2253. +As a side effect, this also reverses the order of multiple AVAs. +.It Cm dump_all +Dump all fields. +When used with +.Ar dump_der , +it allows the DER encoding of the structure to be unambiguously determined. +.It Cm dump_der +Any fields that need to be hexdumped are +dumped using the DER encoding of the field. +Otherwise just the content octets will be displayed. +Both options use the RFC 2253 #XXXX... format. +.It Cm dump_nostr +Dump non-character string types +(for example OCTET STRING); +usually, non-character string types are displayed +as though each content octet represents a single character. +.It Cm dump_unknown +Dump any field whose OID is not recognised by +.Nm openssl . +.It Cm esc_2253 +Escape the +.Qq special +characters required by RFC 2253 in a field that is +.Dq \& ,+"<>; . +Additionally, +.Sq # +is escaped at the beginning of a string +and a space character at the beginning or end of a string. +.It Cm esc_ctrl +Escape control characters. +That is, those with ASCII values less than 0x20 (space) +and the delete (0x7f) character. +They are escaped using the RFC 2253 \eXX notation (where XX are two hex +digits representing the character value). +.It Cm esc_msb +Escape characters with the MSB set; that is, with ASCII values larger than +127. +.It Cm multiline +A multiline format. +Equivalent to +.Cm esc_ctrl , esc_msb , sep_multiline , +.Cm space_eq , lname , +and +.Cm align . +.It Cm no_type +Do not attempt to interpret multibyte characters. +That is, content octets are merely dumped as though one octet +represents each character. +This is useful for diagnostic purposes +but results in rather odd looking output. +.It Cm nofname , sname , lname , oid +Alter how the field name is displayed: +.Cm nofname +does not display the field at all; +.Cm sname +uses the short name form (CN for +.Cm commonName , +for example); +.Cm lname +uses the long form. +.Cm oid +represents the OID in numerical form and is useful for diagnostic purpose. +.It Cm oneline +A one line format which is more readable than +.Cm RFC2253 . +Equivalent to +.Cm esc_2253 , esc_ctrl , esc_msb , utf8 , +.Cm dump_nostr , dump_der , use_quote , sep_comma_plus_spc , +.Cm space_eq , +and +.Cm sname . +.It Cm RFC2253 +Displays names compatible with RFC 2253. +Equivalent to +.Cm esc_2253 , esc_ctrl , +.Cm esc_msb , utf8 , dump_nostr , dump_unknown , +.Cm dump_der , sep_comma_plus , dn_rev , +and +.Cm sname . +.It Cm sep_comma_plus , sep_comma_plus_space , sep_semi_plus_space , sep_multiline +Determine the field separators: +the first character is between RDNs and the second between multiple AVAs +(multiple AVAs are very rare and their use is discouraged). +The options ending in +.Qq space +additionally place a space after the separator to make it more readable. +.Cm sep_multiline +uses a linefeed character for the RDN separator and a spaced +.Sq + +for the AVA separator, +as well as indenting the fields by four characters. +.It Cm show_type +Show the type of the ASN.1 character string. +The type precedes the field contents. +For example +.Qq BMPSTRING: Hello World . +.It Cm space_eq +Place spaces round the +.Sq = +character which follows the field name. +.It Cm use_quote +Escape some characters by surrounding the whole string with +.Sq \&" +characters. +Without the option, all escaping is done with the +.Sq \e +character. +.It Cm utf8 +Convert all strings to UTF8 format first, as required by RFC 2253. +On a UTF8 compatible terminal, +the use of this option (and not setting +.Cm esc_msb ) +may result in the correct display of multibyte characters. +Usually, multibyte characters larger than 0xff +are represented using the format \eUXXXX for 16 bits and \eWXXXXXXXX +for 32 bits, +and any UTF8Strings are converted to their character form first. +.El +.It Fl noout +Do not output the encoded version of the request. +.It Fl ocsp_uri +Print the OCSP responder addresses, if any. +.It Fl ocspid +Print OCSP hash values for the subject name and public key. +.It Fl pubkey +Print the public key. +.It Fl serial +Print the certificate serial number. +.It Fl startdate +Print the start date of the certificate; that is, the +.Cm notBefore +date. +.It Fl subject +Print the subject name. +.It Fl subject_hash +Print the hash of the certificate subject name. +This is used in +.Nm openssl +to form an index to allow certificates in a directory to be looked up +by subject name. +.It Fl subject_hash_old +Print the hash of the certificate subject name +using the older algorithm as used by +.Nm openssl +versions before 1.0.0. +.It Fl text +Print the full certificate in text form. +.El +.Pp +A trusted certificate is a certificate which has several +additional pieces of information attached to it such as the permitted +and prohibited uses of the certificate and an alias. +When a certificate is being verified at least one certificate must be trusted. +By default, a trusted certificate must be stored locally and be a root CA. +The following are x509 trust settings options: +.Bl -tag -width "XXXX" +.It Fl addreject Ar arg +Add a prohibited use. +Accepts the same values as the +.Fl addtrust +option. +.It Fl addtrust Ar arg +Add a trusted certificate use. +Any object name can be used here, but currently only +.Cm clientAuth +(SSL client use), +.Cm serverAuth +(SSL server use), +and +.Cm emailProtection +(S/MIME email) are used. +.It Fl alias +Output the certificate alias. +.It Fl clrreject +Clear all the prohibited or rejected uses of the certificate. +.It Fl clrtrust +Clear all the permitted or trusted uses of the certificate. +.It Fl purpose +Perform tests on the certificate extensions. +The same code is used when verifying untrusted certificates in chains, +so this section is useful if a chain is rejected by the verify code. +.Pp +The +.Cm basicConstraints +extension CA flag is used to determine whether the +certificate can be used as a CA. +If the CA flag is true, it is a CA; +if the CA flag is false, it is not a CA. +All CAs should have the CA flag set to true. +.Pp +If the +.Cm basicConstraints +extension is absent, then the certificate is +considered to be a possible CA; +other extensions are checked according to the intended use of the certificate. +A warning is given in this case because the certificate should really not +be regarded as a CA. +However it is allowed to be a CA to work around some broken software. +.Pp +If the certificate is a V1 certificate +(and thus has no extensions) and it is self-signed, +it is also assumed to be a CA but a warning is again given. +This is to work around the problem of Verisign roots +which are V1 self-signed certificates. +.Pp +If the +.Cm keyUsage +extension is present, then additional restraints are +made on the uses of the certificate. +A CA certificate must have the +.Cm keyCertSign +bit set if the +.Cm keyUsage +extension is present. +.Pp +The extended key usage extension places additional restrictions on the +certificate uses. +If this extension is present, whether critical or not, +the key can only be used for the purposes specified. +.Pp +A complete description of each test is given below. +The comments about +.Cm basicConstraints +and +.Cm keyUsage +and V1 certificates above apply to all CA certificates. +.Bl -tag -width "XXXX" +.It SSL Client +The extended key usage extension must be absent or include the +web client authentication OID. +.Cm keyUsage +must be absent or it must have the +.Cm digitalSignature +bit set. +The Netscape certificate type must be absent +or it must have the SSL client bit set. +.It SSL Client CA +The extended key usage extension must be absent or include the +web client authentication OID. +The Netscape certificate type must be absent +or it must have the SSL CA bit set: +this is used as a workaround if the +.Cm basicConstraints +extension is absent. +.It SSL Server +The extended key usage extension must be absent or include the +web server authentication and/or one of the SGC OIDs. +.Cm keyUsage +must be absent or it must have the +.Cm digitalSignature +set, the +.Cm keyEncipherment +set, or both bits set. +The Netscape certificate type must be absent or have the SSL server bit set. +.It SSL Server CA +The extended key usage extension must be absent or include the +web server authentication and/or one of the SGC OIDs. +The Netscape certificate type must be absent or the SSL CA bit must be set: +this is used as a workaround if the +.Cm basicConstraints +extension is absent. +.It Netscape SSL Server +For Netscape SSL clients to connect to an SSL server; it must have the +.Cm keyEncipherment +bit set if the +.Cm keyUsage +extension is present. +This isn't always valid because some cipher suites use the key for +digital signing. +Otherwise it is the same as a normal SSL server. +.It Common S/MIME Client Tests +The extended key usage extension must be absent or include the +email protection OID. +The Netscape certificate type must be absent or should have the S/MIME bit set. +If the S/MIME bit is not set in Netscape certificate type, then the SSL +client bit is tolerated as an alternative but a warning is shown: +this is because some Verisign certificates don't set the S/MIME bit. +.It S/MIME Signing +In addition to the common S/MIME client tests, the +.Cm digitalSignature +bit must be set if the +.Cm keyUsage +extension is present. +.It S/MIME Encryption +In addition to the common S/MIME tests, the +.Cm keyEncipherment +bit must be set if the +.Cm keyUsage +extension is present. +.It S/MIME CA +The extended key usage extension must be absent or include the +email protection OID. +The Netscape certificate type must be absent +or must have the S/MIME CA bit set: +this is used as a workaround if the +.Cm basicConstraints +extension is absent. +.It CRL Signing +The +.Cm keyUsage +extension must be absent or it must have the CRL signing bit set. +.It CRL Signing CA +The normal CA tests apply, except the +.Cm basicConstraints +extension must be present. +.El +.It Fl setalias Ar arg +Set the alias of the certificate, +allowing the certificate to be referred to using a nickname, +such as +.Qq Steve's Certificate . +.It Fl trustout +Output a trusted certificate +(the default if any trust settings are modified). +An ordinary or trusted certificate can be input, but by default an ordinary +certificate is output and any trust settings are discarded. +.El +.Pp +The +.Nm x509 +utility can be used to sign certificates and requests: +it can thus behave like a mini CA. +The following are x509 signing options: +.Bl -tag -width "XXXX" +.It Fl CA Ar file +The CA certificate to be used for signing. +When this option is present, +.Nm x509 +behaves like a mini CA. +The input file is signed by the CA using this option; +that is, its issuer name is set to the subject name of the CA and it is +digitally signed using the CA's private key. +.Pp +This option is normally combined with the +.Fl req +option. +Without the +.Fl req +option, the input is a certificate which must be self-signed. +.It Fl CAcreateserial +Create the CA serial number file if it does not exist +instead of generating an error. +The file will contain the serial number +.Sq 02 +and the certificate being signed will have +.Sq 1 +as its serial number. +.It Fl CAform Cm der | pem +The format of the CA certificate file. +The default is +.Cm pem . +.It Fl CAkey Ar file +Set the CA private key to sign a certificate with. +Otherwise it is assumed that the CA private key is present +in the CA certificate file. +.It Fl CAkeyform Cm der | pem +The format of the CA private key. +The default is +.Cm pem . +.It Fl CAserial Ar file +Use the serial number in +.Ar file +to sign a certificate. +The file should consist of one line containing an even number of hex digits +with the serial number to use. +After each use the serial number is incremented and written out +to the file again. +.Pp +The default filename consists of the CA certificate file base name with +.Pa .srl +appended. +For example, if the CA certificate file is called +.Pa mycacert.pem , +it expects to find a serial number file called +.Pa mycacert.srl . +.It Fl checkend Ar arg +Check whether the certificate expires in the next +.Ar arg +seconds. +If so, exit with return value 1; +otherwise exit with return value 0. +.It Fl clrext +Delete any extensions from a certificate. +This option is used when a certificate is being created from another +certificate (for example with the +.Fl signkey +or the +.Fl CA +options). +Normally, all extensions are retained. +.It Fl days Ar arg +The number of days to make a certificate valid for. +The default is 30 days. +.It Fl extensions Ar section +The section to add certificate extensions from. +If this option is not specified, the extensions should either be +contained in the unnamed (default) section +or the default section should contain a variable called +.Qq extensions +which contains the section to use. +.It Fl extfile Ar file +File containing certificate extensions to use. +If not specified, no extensions are added to the certificate. +.It Fl keyform Cm der | pem +The format of the private key file used in the +.Fl signkey +option. +.It Fl req +Expect a certificate request on input instead of a certificate. +.It Fl set_serial Ar n +The serial number to use. +This option can be used with either the +.Fl signkey +or +.Fl CA +options. +If used in conjunction with the +.Fl CA +option, the serial number file (as specified by the +.Fl CAserial +or +.Fl CAcreateserial +options) is not used. +.Pp +The serial number can be decimal or hex (if preceded by +.Sq 0x ) . +Negative serial numbers can also be specified but their use is not recommended. +.It Fl signkey Ar file +Self-sign +.Ar file +using the supplied private key. +.Pp +If the input file is a certificate, it sets the issuer name to the +subject name (i.e. makes it self-signed), +changes the public key to the supplied value, +and changes the start and end dates. +The start date is set to the current time and the end date is set to +a value determined by the +.Fl days +option. +Any certificate extensions are retained unless the +.Fl clrext +option is supplied. +.Pp +If the input is a certificate request, a self-signed certificate +is created using the supplied private key using the subject name in +the request. +.It Fl x509toreq +Convert a certificate into a certificate request. +The +.Fl signkey +option is used to pass the required private key. +.El +.Sh COMMON NOTATION +Several commands share a common syntax, +as detailed below. +.Pp +Password arguments, typically specified using +.Fl passin +and +.Fl passout +for input and output passwords, +allow passwords to be obtained from a variety of sources. +Both of these options take a single argument, described below. +If no password argument is given and a password is required, +then the user is prompted to enter one: +this will typically be read from the current terminal with echoing turned off. +.Bl -tag -width "pass:password" -offset indent +.It Cm pass : Ns Ar password +The actual password is +.Ar password . +Since the password is visible to utilities, +this form should only be used where security is not important. +.It Cm env : Ns Ar var +Obtain the password from the environment variable +.Ar var . +Since the environment of other processes is visible, +this option should be used with caution. +.It Cm file : Ns Ar path +The first line of +.Ar path +is the password. +If the same +.Ar path +argument is supplied to +.Fl passin +and +.Fl passout , +then the first line will be used for the input password and the next line +for the output password. +.Ar path +need not refer to a regular file: +it could, for example, refer to a device or named pipe. +.It Cm fd : Ns Ar number +Read the password from the file descriptor +.Ar number . +This can be used to send the data via a pipe, for example. +.It Cm stdin +Read the password from standard input. +.El +.Pp +Input/output formats, +typically specified using +.Fl inform +and +.Fl outform , +indicate the format being read from or written to. +The argument is case insensitive. +.Pp +.Bl -tag -width Ds -offset indent -compact +.It Cm der +Distinguished Encoding Rules (DER) +is a binary format. +.It Cm net +Insecure legacy format. +.It Cm pem +Privacy Enhanced Mail (PEM) +is base64-encoded. +.It Cm smime +An SMIME format message. +.It Cm txt +Plain ASCII text. +.El +.Sh ENVIRONMENT +The following environment variables affect the execution of +.Nm openssl : +.Bl -tag -width "/etc/ssl/openssl.cnf" +.It Ev OPENSSL_CONF +The location of the master configuration file. +.El +.Sh FILES +.Bl -tag -width "/etc/ssl/openssl.cnf" -compact +.It Pa /etc/ssl/ +Default config directory for +.Nm openssl . +.It Pa /etc/ssl/lib/ +Unused. +.It Pa /etc/ssl/private/ +Default private key directory. +.It Pa /etc/ssl/openssl.cnf +Default configuration file for +.Nm openssl . +.It Pa /etc/ssl/x509v3.cnf +Default configuration file for +.Nm x509 +certificates. +.El +.Sh SEE ALSO +.Xr acme-client 1 , +.Xr nc 1 , +.Xr ssl 8 , +.Xr starttls 8 +.Sh STANDARDS +.Rs +.%A T. Dierks +.%A C. Allen +.%D January 1999 +.%R RFC 2246 +.%T The TLS Protocol Version 1.0 +.Re +.Pp +.Rs +.%A M. Wahl +.%A S. Killie +.%A T. Howes +.%D December 1997 +.%R RFC 2253 +.%T Lightweight Directory Access Protocol (v3): UTF-8 String Representation of Distinguished Names +.Re +.Pp +.Rs +.%A B. Kaliski +.%D March 1998 +.%R RFC 2315 +.%T PKCS #7: Cryptographic Message Syntax Version 1.5 +.Re +.Pp +.Rs +.%A R. Housley +.%A W. Ford +.%A W. Polk +.%A D. Solo +.%D January 1999 +.%R RFC 2459 +.%T Internet X.509 Public Key Infrastructure Certificate and CRL Profile +.Re +.Pp +.Rs +.%A M. Myers +.%A R. Ankney +.%A A. Malpani +.%A S. Galperin +.%A C. Adams +.%D June 1999 +.%R RFC 2560 +.%T X.509 Internet Public Key Infrastructure Online Certificate Status Protocol \(en OCSP +.Re +.Pp +.Rs +.%A R. Housley +.%D June 1999 +.%R RFC 2630 +.%T Cryptographic Message Syntax +.Re +.Pp +.Rs +.%A P. Chown +.%D June 2002 +.%R RFC 3268 +.%T Advanced Encryption Standard (AES) Ciphersuites for Transport Layer Security (TLS) +.Re diff --git a/bin/openssl/openssl.c b/bin/openssl/openssl.c new file mode 100644 index 0000000000..346b1d83c7 --- /dev/null +++ b/bin/openssl/openssl.c @@ -0,0 +1,831 @@ +/* $OpenBSD: openssl.c,v 1.25 2017/01/20 08:57:12 deraadt Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include +#include +#include +#include +#include +#include + +#include "apps.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "progs.h" +#include "s_apps.h" + +#define FUNC_TYPE_GENERAL 1 +#define FUNC_TYPE_MD 2 +#define FUNC_TYPE_CIPHER 3 +#define FUNC_TYPE_PKEY 4 +#define FUNC_TYPE_MD_ALG 5 +#define FUNC_TYPE_CIPHER_ALG 6 + +int single_execution = 0; + +typedef struct { + int type; + const char *name; + int (*func)(int argc, char **argv); +} FUNCTION; + +DECLARE_LHASH_OF(FUNCTION); + +FUNCTION functions[] = { + + /* General functions. */ + { FUNC_TYPE_GENERAL, "asn1parse", asn1parse_main }, + { FUNC_TYPE_GENERAL, "ca", ca_main }, + { FUNC_TYPE_GENERAL, "certhash", certhash_main }, + { FUNC_TYPE_GENERAL, "ciphers", ciphers_main }, + { FUNC_TYPE_GENERAL, "crl2pkcs7", crl2pkcs7_main }, + { FUNC_TYPE_GENERAL, "crl", crl_main }, + { FUNC_TYPE_GENERAL, "dgst", dgst_main }, + { FUNC_TYPE_GENERAL, "enc", enc_main }, + { FUNC_TYPE_GENERAL, "errstr", errstr_main }, + { FUNC_TYPE_GENERAL, "genpkey", genpkey_main }, + { FUNC_TYPE_GENERAL, "nseq", nseq_main }, +#ifndef OPENSSL_NO_OCSP + { FUNC_TYPE_GENERAL, "ocsp", ocsp_main }, +#endif + { FUNC_TYPE_GENERAL, "passwd", passwd_main }, + { FUNC_TYPE_GENERAL, "pkcs7", pkcs7_main }, + { FUNC_TYPE_GENERAL, "pkcs8", pkcs8_main }, +#if !defined(OPENSSL_NO_DES) && !defined(OPENSSL_NO_SHA1) + { FUNC_TYPE_GENERAL, "pkcs12", pkcs12_main }, +#endif + { FUNC_TYPE_GENERAL, "pkey", pkey_main }, + { FUNC_TYPE_GENERAL, "pkeyparam", pkeyparam_main }, + { FUNC_TYPE_GENERAL, "pkeyutl", pkeyutl_main }, + { FUNC_TYPE_GENERAL, "prime", prime_main }, + { FUNC_TYPE_GENERAL, "rand", rand_main }, + { FUNC_TYPE_GENERAL, "req", req_main }, + { FUNC_TYPE_GENERAL, "s_client", s_client_main }, + { FUNC_TYPE_GENERAL, "s_server", s_server_main }, + { FUNC_TYPE_GENERAL, "s_time", s_time_main }, + { FUNC_TYPE_GENERAL, "sess_id", sess_id_main }, + { FUNC_TYPE_GENERAL, "smime", smime_main }, +#ifndef OPENSSL_NO_SPEED + { FUNC_TYPE_GENERAL, "speed", speed_main }, +#endif + { FUNC_TYPE_GENERAL, "spkac", spkac_main }, + { FUNC_TYPE_GENERAL, "ts", ts_main }, + { FUNC_TYPE_GENERAL, "verify", verify_main }, + { FUNC_TYPE_GENERAL, "version", version_main }, + { FUNC_TYPE_GENERAL, "x509", x509_main }, + +#ifndef OPENSSL_NO_DH + { FUNC_TYPE_GENERAL, "dh", dh_main }, + { FUNC_TYPE_GENERAL, "dhparam", dhparam_main }, + { FUNC_TYPE_GENERAL, "gendh", gendh_main }, +#endif +#ifndef OPENSSL_NO_DSA + { FUNC_TYPE_GENERAL, "dsa", dsa_main }, + { FUNC_TYPE_GENERAL, "dsaparam", dsaparam_main }, + { FUNC_TYPE_GENERAL, "gendsa", gendsa_main }, +#endif +#ifndef OPENSSL_NO_EC + { FUNC_TYPE_GENERAL, "ec", ec_main }, + { FUNC_TYPE_GENERAL, "ecparam", ecparam_main }, +#endif +#ifndef OPENSSL_NO_RSA + { FUNC_TYPE_GENERAL, "genrsa", genrsa_main }, + { FUNC_TYPE_GENERAL, "rsa", rsa_main }, + { FUNC_TYPE_GENERAL, "rsautl", rsautl_main }, +#endif + + /* Message Digests. */ +#ifndef OPENSSL_NO_GOST + { FUNC_TYPE_MD, "gost-mac", dgst_main }, + { FUNC_TYPE_MD, "md_gost94", dgst_main }, + { FUNC_TYPE_MD, "streebog256", dgst_main }, + { FUNC_TYPE_MD, "streebog512", dgst_main }, +#endif +#ifndef OPENSSL_NO_MD4 + { FUNC_TYPE_MD, "md4", dgst_main }, +#endif +#ifndef OPENSSL_NO_MD5 + { FUNC_TYPE_MD, "md5", dgst_main }, +#endif +#ifndef OPENSSL_NO_RIPEMD160 + { FUNC_TYPE_MD, "ripemd160", dgst_main }, +#endif +#ifndef OPENSSL_NO_SHA1 + { FUNC_TYPE_MD, "sha1", dgst_main }, +#endif +#ifndef OPENSSL_NO_SHA224 + { FUNC_TYPE_MD, "sha224", dgst_main }, +#endif +#ifndef OPENSSL_NO_SHA256 + { FUNC_TYPE_MD, "sha256", dgst_main }, +#endif +#ifndef OPENSSL_NO_SHA384 + { FUNC_TYPE_MD, "sha384", dgst_main }, +#endif +#ifndef OPENSSL_NO_SHA512 + { FUNC_TYPE_MD, "sha512", dgst_main }, +#endif +#ifndef OPENSSL_NO_WHIRLPOOL + { FUNC_TYPE_MD, "whirlpool", dgst_main }, +#endif + + /* Ciphers. */ + { FUNC_TYPE_CIPHER, "base64", enc_main }, +#ifndef OPENSSL_NO_AES + { FUNC_TYPE_CIPHER, "aes-128-cbc", enc_main }, + { FUNC_TYPE_CIPHER, "aes-128-ecb", enc_main }, + { FUNC_TYPE_CIPHER, "aes-192-cbc", enc_main }, + { FUNC_TYPE_CIPHER, "aes-192-ecb", enc_main }, + { FUNC_TYPE_CIPHER, "aes-256-cbc", enc_main }, + { FUNC_TYPE_CIPHER, "aes-256-ecb", enc_main }, +#endif +#ifndef OPENSSL_NO_BF + { FUNC_TYPE_CIPHER, "bf", enc_main }, + { FUNC_TYPE_CIPHER, "bf-cbc", enc_main }, + { FUNC_TYPE_CIPHER, "bf-ecb", enc_main }, + { FUNC_TYPE_CIPHER, "bf-cfb", enc_main }, + { FUNC_TYPE_CIPHER, "bf-ofb", enc_main }, +#endif +#ifndef OPENSSL_NO_CAMELLIA + { FUNC_TYPE_CIPHER, "camellia-128-cbc", enc_main }, + { FUNC_TYPE_CIPHER, "camellia-128-ecb", enc_main }, + { FUNC_TYPE_CIPHER, "camellia-192-cbc", enc_main }, + { FUNC_TYPE_CIPHER, "camellia-192-ecb", enc_main }, + { FUNC_TYPE_CIPHER, "camellia-256-cbc", enc_main }, + { FUNC_TYPE_CIPHER, "camellia-256-ecb", enc_main }, +#endif +#ifndef OPENSSL_NO_CAST + { FUNC_TYPE_CIPHER, "cast", enc_main }, + { FUNC_TYPE_CIPHER, "cast5-cbc", enc_main }, + { FUNC_TYPE_CIPHER, "cast5-ecb", enc_main }, + { FUNC_TYPE_CIPHER, "cast5-cfb", enc_main }, + { FUNC_TYPE_CIPHER, "cast5-ofb", enc_main }, + { FUNC_TYPE_CIPHER, "cast-cbc", enc_main }, +#endif +#ifndef OPENSSL_NO_CHACHA + { FUNC_TYPE_CIPHER, "chacha", enc_main }, +#endif +#ifndef OPENSSL_NO_DES + { FUNC_TYPE_CIPHER, "des", enc_main }, + { FUNC_TYPE_CIPHER, "des3", enc_main }, + { FUNC_TYPE_CIPHER, "desx", enc_main }, + { FUNC_TYPE_CIPHER, "des-ecb", enc_main }, + { FUNC_TYPE_CIPHER, "des-ede", enc_main }, + { FUNC_TYPE_CIPHER, "des-ede3", enc_main }, + { FUNC_TYPE_CIPHER, "des-cbc", enc_main }, + { FUNC_TYPE_CIPHER, "des-ede-cbc", enc_main }, + { FUNC_TYPE_CIPHER, "des-ede3-cbc", enc_main }, + { FUNC_TYPE_CIPHER, "des-cfb", enc_main }, + { FUNC_TYPE_CIPHER, "des-ede-cfb", enc_main }, + { FUNC_TYPE_CIPHER, "des-ede3-cfb", enc_main }, + { FUNC_TYPE_CIPHER, "des-ofb", enc_main }, + { FUNC_TYPE_CIPHER, "des-ede-ofb", enc_main }, + { FUNC_TYPE_CIPHER, "des-ede3-ofb", enc_main }, +#endif +#ifndef OPENSSL_NO_IDEA + { FUNC_TYPE_CIPHER, "idea", enc_main }, + { FUNC_TYPE_CIPHER, "idea-cbc", enc_main }, + { FUNC_TYPE_CIPHER, "idea-ecb", enc_main }, + { FUNC_TYPE_CIPHER, "idea-cfb", enc_main }, + { FUNC_TYPE_CIPHER, "idea-ofb", enc_main }, +#endif +#ifndef OPENSSL_NO_RC2 + { FUNC_TYPE_CIPHER, "rc2", enc_main }, + { FUNC_TYPE_CIPHER, "rc2-cbc", enc_main }, + { FUNC_TYPE_CIPHER, "rc2-ecb", enc_main }, + { FUNC_TYPE_CIPHER, "rc2-cfb", enc_main }, + { FUNC_TYPE_CIPHER, "rc2-ofb", enc_main }, + { FUNC_TYPE_CIPHER, "rc2-64-cbc", enc_main }, + { FUNC_TYPE_CIPHER, "rc2-40-cbc", enc_main }, +#endif +#ifndef OPENSSL_NO_RC4 + { FUNC_TYPE_CIPHER, "rc4", enc_main }, + { FUNC_TYPE_CIPHER, "rc4-40", enc_main }, +#endif +#ifdef ZLIB + { FUNC_TYPE_CIPHER, "zlib", enc_main }, +#endif + + { 0, NULL, NULL } +}; + +static void openssl_startup(void); +static void openssl_shutdown(void); + +/* The LHASH callbacks ("hash" & "cmp") have been replaced by functions with the + * base prototypes (we cast each variable inside the function to the required + * type of "FUNCTION*"). This removes the necessity for macro-generated wrapper + * functions. */ + +static LHASH_OF(FUNCTION) *prog_init(void); +static int do_cmd(LHASH_OF(FUNCTION) *prog, int argc, char *argv[]); +static void list_pkey(BIO * out); +static void list_cipher(BIO * out); +static void list_md(BIO * out); +char *default_config_file = NULL; + +CONF *config = NULL; +BIO *bio_err = NULL; + +static void +lock_dbg_cb(int mode, int type, const char *file, int line) +{ + static int modes[CRYPTO_NUM_LOCKS]; /* = {0, 0, ... } */ + const char *errstr = NULL; + int rw; + + rw = mode & (CRYPTO_READ | CRYPTO_WRITE); + if (!((rw == CRYPTO_READ) || (rw == CRYPTO_WRITE))) { + errstr = "invalid mode"; + goto err; + } + if (type < 0 || type >= CRYPTO_NUM_LOCKS) { + errstr = "type out of bounds"; + goto err; + } + if (mode & CRYPTO_LOCK) { + if (modes[type]) { + errstr = "already locked"; + /* + * must not happen in a single-threaded program + * (would deadlock) + */ + goto err; + } + modes[type] = rw; + } else if (mode & CRYPTO_UNLOCK) { + if (!modes[type]) { + errstr = "not locked"; + goto err; + } + if (modes[type] != rw) { + errstr = (rw == CRYPTO_READ) ? + "CRYPTO_r_unlock on write lock" : + "CRYPTO_w_unlock on read lock"; + } + modes[type] = 0; + } else { + errstr = "invalid mode"; + goto err; + } + +err: + if (errstr) { + /* we cannot use bio_err here */ + fprintf(stderr, "openssl (lock_dbg_cb): %s (mode=%d, type=%d) at %s:%d\n", + errstr, mode, type, file, line); + } +} + +static void +openssl_startup(void) +{ + signal(SIGPIPE, SIG_IGN); + + OpenSSL_add_all_algorithms(); + SSL_library_init(); + SSL_load_error_strings(); + + setup_ui(); +} + +static void +openssl_shutdown(void) +{ + CONF_modules_unload(1); + destroy_ui(); + OBJ_cleanup(); + EVP_cleanup(); + CRYPTO_cleanup_all_ex_data(); + ERR_remove_thread_state(NULL); + ERR_free_strings(); +} + +int +main(int argc, char **argv) +{ + ARGS arg; +#define PROG_NAME_SIZE 39 + char pname[PROG_NAME_SIZE + 1]; + FUNCTION f, *fp; + const char *prompt; + char buf[1024]; + char *to_free = NULL; + int n, i, ret = 0; + char *p; + LHASH_OF(FUNCTION) * prog = NULL; + long errline; + + arg.data = NULL; + arg.count = 0; + + if (pledge("stdio cpath wpath rpath inet dns proc flock tty", NULL) == -1) { + fprintf(stderr, "openssl: pledge: %s\n", strerror(errno)); + exit(1); + } + + bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); + if (bio_err == NULL) { + fprintf(stderr, "openssl: failed to initialise bio_err\n"); + exit(1); + } + + if (BIO_sock_init() != 1) { + BIO_printf(bio_err, "BIO_sock_init failed\n"); + exit(1); + } + + CRYPTO_set_locking_callback(lock_dbg_cb); + + openssl_startup(); + + /* Lets load up our environment a little */ + p = getenv("OPENSSL_CONF"); + if (p == NULL) { + p = to_free = make_config_name(); + if (p == NULL) { + BIO_printf(bio_err, "error making config file name\n"); + goto end; + } + } + + default_config_file = p; + + config = NCONF_new(NULL); + i = NCONF_load(config, p, &errline); + if (i == 0) { + if (ERR_GET_REASON(ERR_peek_last_error()) == + CONF_R_NO_SUCH_FILE) { + BIO_printf(bio_err, + "WARNING: can't open config file: %s\n", p); + ERR_clear_error(); + NCONF_free(config); + config = NULL; + } else { + ERR_print_errors(bio_err); + NCONF_free(config); + exit(1); + } + } + + if (!load_config(bio_err, NULL)) { + BIO_printf(bio_err, "failed to load configuration\n"); + goto end; + } + + prog = prog_init(); + + /* first check the program name */ + program_name(argv[0], pname, sizeof pname); + + f.name = pname; + fp = lh_FUNCTION_retrieve(prog, &f); + if (fp != NULL) { + argv[0] = pname; + + single_execution = 1; + ret = fp->func(argc, argv); + goto end; + } + /* + * ok, now check that there are not arguments, if there are, run with + * them, shifting the ssleay off the front + */ + if (argc != 1) { + argc--; + argv++; + + single_execution = 1; + ret = do_cmd(prog, argc, argv); + if (ret < 0) + ret = 0; + goto end; + } + /* ok, lets enter the old 'OpenSSL>' mode */ + + for (;;) { + ret = 0; + p = buf; + n = sizeof buf; + i = 0; + for (;;) { + p[0] = '\0'; + if (i++) + prompt = ">"; + else + prompt = "OpenSSL> "; + fputs(prompt, stdout); + fflush(stdout); + if (!fgets(p, n, stdin)) + goto end; + if (p[0] == '\0') + goto end; + i = strlen(p); + if (i <= 1) + break; + if (p[i - 2] != '\\') + break; + i -= 2; + p += i; + n -= i; + } + if (!chopup_args(&arg, buf, &argc, &argv)) + break; + + ret = do_cmd(prog, argc, argv); + if (ret < 0) { + ret = 0; + goto end; + } + if (ret != 0) + BIO_printf(bio_err, "error in %s\n", argv[0]); + (void) BIO_flush(bio_err); + } + BIO_printf(bio_err, "bad exit\n"); + ret = 1; + +end: + free(to_free); + + if (config != NULL) { + NCONF_free(config); + config = NULL; + } + if (prog != NULL) + lh_FUNCTION_free(prog); + free(arg.data); + + openssl_shutdown(); + + if (bio_err != NULL) { + BIO_free(bio_err); + bio_err = NULL; + } + return (ret); +} + +#define LIST_STANDARD_COMMANDS "list-standard-commands" +#define LIST_MESSAGE_DIGEST_COMMANDS "list-message-digest-commands" +#define LIST_MESSAGE_DIGEST_ALGORITHMS "list-message-digest-algorithms" +#define LIST_CIPHER_COMMANDS "list-cipher-commands" +#define LIST_CIPHER_ALGORITHMS "list-cipher-algorithms" +#define LIST_PUBLIC_KEY_ALGORITHMS "list-public-key-algorithms" + + +static int +do_cmd(LHASH_OF(FUNCTION) * prog, int argc, char *argv[]) +{ + FUNCTION f, *fp; + int i, ret = 1, tp, nl; + + if ((argc <= 0) || (argv[0] == NULL)) { + ret = 0; + goto end; + } + f.name = argv[0]; + fp = lh_FUNCTION_retrieve(prog, &f); + if (fp == NULL) { + if (EVP_get_digestbyname(argv[0])) { + f.type = FUNC_TYPE_MD; + f.func = dgst_main; + fp = &f; + } else if (EVP_get_cipherbyname(argv[0])) { + f.type = FUNC_TYPE_CIPHER; + f.func = enc_main; + fp = &f; + } + } + if (fp != NULL) { + ret = fp->func(argc, argv); + } else if ((strncmp(argv[0], "no-", 3)) == 0) { + BIO *bio_stdout = BIO_new_fp(stdout, BIO_NOCLOSE); + f.name = argv[0] + 3; + ret = (lh_FUNCTION_retrieve(prog, &f) != NULL); + if (!ret) + BIO_printf(bio_stdout, "%s\n", argv[0]); + else + BIO_printf(bio_stdout, "%s\n", argv[0] + 3); + BIO_free_all(bio_stdout); + goto end; + } else if ((strcmp(argv[0], "quit") == 0) || + (strcmp(argv[0], "q") == 0) || + (strcmp(argv[0], "exit") == 0) || + (strcmp(argv[0], "bye") == 0)) { + ret = -1; + goto end; + } else if ((strcmp(argv[0], LIST_STANDARD_COMMANDS) == 0) || + (strcmp(argv[0], LIST_MESSAGE_DIGEST_COMMANDS) == 0) || + (strcmp(argv[0], LIST_MESSAGE_DIGEST_ALGORITHMS) == 0) || + (strcmp(argv[0], LIST_CIPHER_COMMANDS) == 0) || + (strcmp(argv[0], LIST_CIPHER_ALGORITHMS) == 0) || + (strcmp(argv[0], LIST_PUBLIC_KEY_ALGORITHMS) == 0)) { + int list_type; + BIO *bio_stdout; + + if (strcmp(argv[0], LIST_STANDARD_COMMANDS) == 0) + list_type = FUNC_TYPE_GENERAL; + else if (strcmp(argv[0], LIST_MESSAGE_DIGEST_COMMANDS) == 0) + list_type = FUNC_TYPE_MD; + else if (strcmp(argv[0], LIST_MESSAGE_DIGEST_ALGORITHMS) == 0) + list_type = FUNC_TYPE_MD_ALG; + else if (strcmp(argv[0], LIST_PUBLIC_KEY_ALGORITHMS) == 0) + list_type = FUNC_TYPE_PKEY; + else if (strcmp(argv[0], LIST_CIPHER_ALGORITHMS) == 0) + list_type = FUNC_TYPE_CIPHER_ALG; + else /* strcmp(argv[0],LIST_CIPHER_COMMANDS) == 0 */ + list_type = FUNC_TYPE_CIPHER; + bio_stdout = BIO_new_fp(stdout, BIO_NOCLOSE); + + if (list_type == FUNC_TYPE_PKEY) + list_pkey(bio_stdout); + if (list_type == FUNC_TYPE_MD_ALG) + list_md(bio_stdout); + if (list_type == FUNC_TYPE_CIPHER_ALG) + list_cipher(bio_stdout); + else { + for (fp = functions; fp->name != NULL; fp++) + if (fp->type == list_type) + BIO_printf(bio_stdout, "%s\n", + fp->name); + } + BIO_free_all(bio_stdout); + ret = 0; + goto end; + } else { + BIO_printf(bio_err, + "openssl:Error: '%s' is an invalid command.\n", + argv[0]); + BIO_printf(bio_err, "\nStandard commands"); + i = 0; + tp = 0; + for (fp = functions; fp->name != NULL; fp++) { + nl = 0; +#ifdef OPENSSL_NO_CAMELLIA + if (((i++) % 5) == 0) +#else + if (((i++) % 4) == 0) +#endif + { + BIO_printf(bio_err, "\n"); + nl = 1; + } + if (fp->type != tp) { + tp = fp->type; + if (!nl) + BIO_printf(bio_err, "\n"); + if (tp == FUNC_TYPE_MD) { + i = 1; + BIO_printf(bio_err, + "\nMessage Digest commands (see the `dgst' command for more details)\n"); + } else if (tp == FUNC_TYPE_CIPHER) { + i = 1; + BIO_printf(bio_err, "\nCipher commands (see the `enc' command for more details)\n"); + } + } +#ifdef OPENSSL_NO_CAMELLIA + BIO_printf(bio_err, "%-15s", fp->name); +#else + BIO_printf(bio_err, "%-18s", fp->name); +#endif + } + BIO_printf(bio_err, "\n\n"); + ret = 0; + } +end: + return (ret); +} + +static int +SortFnByName(const void *_f1, const void *_f2) +{ + const FUNCTION *f1 = _f1; + const FUNCTION *f2 = _f2; + + if (f1->type != f2->type) + return f1->type - f2->type; + return strcmp(f1->name, f2->name); +} + +static void +list_pkey(BIO * out) +{ + int i; + + for (i = 0; i < EVP_PKEY_asn1_get_count(); i++) { + const EVP_PKEY_ASN1_METHOD *ameth; + int pkey_id, pkey_base_id, pkey_flags; + const char *pinfo, *pem_str; + ameth = EVP_PKEY_asn1_get0(i); + EVP_PKEY_asn1_get0_info(&pkey_id, &pkey_base_id, &pkey_flags, + &pinfo, &pem_str, ameth); + if (pkey_flags & ASN1_PKEY_ALIAS) { + BIO_printf(out, "Name: %s\n", + OBJ_nid2ln(pkey_id)); + BIO_printf(out, "\tType: Alias to %s\n", + OBJ_nid2ln(pkey_base_id)); + } else { + BIO_printf(out, "Name: %s\n", pinfo); + BIO_printf(out, "\tType: %s Algorithm\n", + pkey_flags & ASN1_PKEY_DYNAMIC ? + "External" : "Builtin"); + BIO_printf(out, "\tOID: %s\n", OBJ_nid2ln(pkey_id)); + if (pem_str == NULL) + pem_str = "(none)"; + BIO_printf(out, "\tPEM string: %s\n", pem_str); + } + + } +} + +static void +list_cipher_fn(const EVP_CIPHER * c, const char *from, const char *to, + void *arg) +{ + if (c) + BIO_printf(arg, "%s\n", EVP_CIPHER_name(c)); + else { + if (!from) + from = ""; + if (!to) + to = ""; + BIO_printf(arg, "%s => %s\n", from, to); + } +} + +static void +list_cipher(BIO * out) +{ + EVP_CIPHER_do_all_sorted(list_cipher_fn, out); +} + +static void +list_md_fn(const EVP_MD * m, const char *from, const char *to, void *arg) +{ + if (m) + BIO_printf(arg, "%s\n", EVP_MD_name(m)); + else { + if (!from) + from = ""; + if (!to) + to = ""; + BIO_printf(arg, "%s => %s\n", from, to); + } +} + +static void +list_md(BIO * out) +{ + EVP_MD_do_all_sorted(list_md_fn, out); +} + +static int +function_cmp(const FUNCTION * a, const FUNCTION * b) +{ + return strncmp(a->name, b->name, 8); +} + +static IMPLEMENT_LHASH_COMP_FN(function, FUNCTION) + +static unsigned long +function_hash(const FUNCTION * a) +{ + return lh_strhash(a->name); +} + +static IMPLEMENT_LHASH_HASH_FN(function, FUNCTION) + +static LHASH_OF(FUNCTION) * +prog_init(void) +{ + LHASH_OF(FUNCTION) * ret; + FUNCTION *f; + size_t i; + + /* Purely so it looks nice when the user hits ? */ + for (i = 0, f = functions; f->name != NULL; ++f, ++i) + ; + qsort(functions, i, sizeof *functions, SortFnByName); + + if ((ret = lh_FUNCTION_new()) == NULL) + return (NULL); + + for (f = functions; f->name != NULL; f++) + (void) lh_FUNCTION_insert(ret, f); + return (ret); +} diff --git a/bin/openssl/passwd.c b/bin/openssl/passwd.c new file mode 100644 index 0000000000..af5360448c --- /dev/null +++ b/bin/openssl/passwd.c @@ -0,0 +1,491 @@ +/* $OpenBSD: passwd.c,v 1.8 2017/01/20 08:57:12 deraadt Exp $ */ + +#if defined OPENSSL_NO_MD5 +#define NO_MD5CRYPT_1 +#endif + +#if !defined(OPENSSL_NO_DES) || !defined(NO_MD5CRYPT_1) + +#include +#include + +#include "apps.h" + +#include +#include +#include + +#ifndef OPENSSL_NO_DES +#include +#endif + +#ifndef NO_MD5CRYPT_1 +#include +#endif + +static unsigned const char cov_2char[64] = { + /* from crypto/des/fcrypt.c */ + 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, + 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, + 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, + 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, + 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, + 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, + 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A +}; + +static int +do_passwd(int passed_salt, char **salt_p, char **salt_malloc_p, + char *passwd, BIO * out, int quiet, int table, int reverse, + size_t pw_maxlen, int usecrypt, int use1, int useapr1); + +static struct { + char *infile; + int in_stdin; + int noverify; + int quiet; + int reverse; + char *salt; + int table; + int use1; + int useapr1; + int usecrypt; +} passwd_config; + +static struct option passwd_options[] = { +#ifndef NO_MD5CRYPT_1 + { + .name = "1", + .desc = "Use MD5 based BSD password algorithm 1", + .type = OPTION_FLAG, + .opt.flag = &passwd_config.use1, + }, + { + .name = "apr1", + .desc = "Use apr1 algorithm (Apache variant of BSD algorithm)", + .type = OPTION_FLAG, + .opt.flag = &passwd_config.useapr1, + }, +#endif +#ifndef OPENSSL_NO_DES + { + .name = "crypt", + .desc = "Use crypt algorithm (default)", + .type = OPTION_FLAG, + .opt.flag = &passwd_config.usecrypt, + }, +#endif + { + .name = "in", + .argname = "file", + .desc = "Read passwords from specified file", + .type = OPTION_ARG, + .opt.arg = &passwd_config.infile, + }, + { + .name = "noverify", + .desc = "Do not verify password", + .type = OPTION_FLAG, + .opt.flag = &passwd_config.noverify, + }, + { + .name = "quiet", + .desc = "Do not output warnings", + .type = OPTION_FLAG, + .opt.flag = &passwd_config.quiet, + }, + { + .name = "reverse", + .desc = "Reverse table columns (requires -table)", + .type = OPTION_FLAG, + .opt.flag = &passwd_config.reverse, + }, + { + .name = "salt", + .argname = "string", + .desc = "Use specified salt", + .type = OPTION_ARG, + .opt.arg = &passwd_config.salt, + }, + { + .name = "stdin", + .desc = "Read passwords from stdin", + .type = OPTION_FLAG, + .opt.flag = &passwd_config.in_stdin, + }, + { + .name = "table", + .desc = "Output cleartext and hashed passwords (tab separated)", + .type = OPTION_FLAG, + .opt.flag = &passwd_config.table, + }, + { NULL }, +}; + +static void +passwd_usage(void) +{ + fprintf(stderr, "usage: passwd [-1 | -apr1 | -crypt] [-in file] " + "[-noverify] [-quiet]\n" + " [-reverse] [-salt string] [-stdin] [-table] [password]\n\n"); + options_usage(passwd_options); +} + +int +passwd_main(int argc, char **argv) +{ + char *passwd = NULL, **passwds = NULL; + char *salt_malloc = NULL, *passwd_malloc = NULL; + size_t passwd_malloc_size = 0; + BIO *in = NULL, *out = NULL; + int badopt = 0; + int passed_salt = 0; + size_t pw_maxlen = 0; + int argsused; + int ret = 1; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + memset(&passwd_config, 0, sizeof(passwd_config)); + + if (options_parse(argc, argv, passwd_options, NULL, &argsused) != 0) { + passwd_usage(); + goto err; + } + + if (argsused < argc) + passwds = &argv[argsused]; + if (passwd_config.salt != NULL) + passed_salt = 1; + + if (!passwd_config.usecrypt && !passwd_config.use1 && + !passwd_config.useapr1) + passwd_config.usecrypt = 1; /* use default */ + if (passwd_config.usecrypt + passwd_config.use1 + + passwd_config.useapr1 > 1) + badopt = 1; /* conflicting options */ + + /* Reject unsupported algorithms */ +#ifdef OPENSSL_NO_DES + if (passwd_config.usecrypt) + badopt = 1; +#endif +#ifdef NO_MD5CRYPT_1 + if (passwd_config.use1 || passwd_config.useapr1) + badopt = 1; +#endif + + if (badopt) { + passwd_usage(); + goto err; + } + + if ((out = BIO_new(BIO_s_file())) == NULL) + goto err; + BIO_set_fp(out, stdout, BIO_NOCLOSE | BIO_FP_TEXT); + + if (passwd_config.infile != NULL || passwd_config.in_stdin) { + if ((in = BIO_new(BIO_s_file())) == NULL) + goto err; + if (passwd_config.infile != NULL) { + assert(passwd_config.in_stdin == 0); + if (BIO_read_filename(in, passwd_config.infile) <= 0) + goto err; + } else { + assert(passwd_config.in_stdin); + BIO_set_fp(in, stdin, BIO_NOCLOSE); + } + } + if (passwd_config.usecrypt) + pw_maxlen = 8; + else if (passwd_config.use1 || passwd_config.useapr1) + pw_maxlen = 256;/* arbitrary limit, should be enough for most + * passwords */ + + if (passwds == NULL) { + /* no passwords on the command line */ + + passwd_malloc_size = pw_maxlen + 2; + /* longer than necessary so that we can warn about truncation */ + passwd = passwd_malloc = malloc(passwd_malloc_size); + if (passwd_malloc == NULL) + goto err; + } + if (in == NULL && passwds == NULL) { + /* build a null-terminated list */ + static char *passwds_static[2] = {NULL, NULL}; + + passwds = passwds_static; + if (in == NULL) + if (EVP_read_pw_string(passwd_malloc, + passwd_malloc_size, "Password: ", + !(passed_salt || passwd_config.noverify)) != 0) + goto err; + passwds[0] = passwd_malloc; + } + if (in == NULL) { + assert(passwds != NULL); + assert(*passwds != NULL); + + do { /* loop over list of passwords */ + passwd = *passwds++; + if (!do_passwd(passed_salt, &passwd_config.salt, + &salt_malloc, passwd, out, passwd_config.quiet, + passwd_config.table, passwd_config.reverse, + pw_maxlen, passwd_config.usecrypt, + passwd_config.use1, passwd_config.useapr1)) + goto err; + } while (*passwds != NULL); + } else { + int done; + + assert(passwd != NULL); + do { + int r = BIO_gets(in, passwd, pw_maxlen + 1); + if (r > 0) { + char *c = (strchr(passwd, '\n')); + if (c != NULL) + *c = 0; /* truncate at newline */ + else { + /* ignore rest of line */ + char trash[BUFSIZ]; + do + r = BIO_gets(in, trash, sizeof trash); + while ((r > 0) && (!strchr(trash, '\n'))); + } + + if (!do_passwd(passed_salt, &passwd_config.salt, + &salt_malloc, passwd, out, + passwd_config.quiet, passwd_config.table, + passwd_config.reverse, pw_maxlen, + passwd_config.usecrypt, passwd_config.use1, + passwd_config.useapr1)) + goto err; + } + done = (r <= 0); + } while (!done); + } + ret = 0; + +err: + ERR_print_errors(bio_err); + + free(salt_malloc); + free(passwd_malloc); + + BIO_free(in); + BIO_free_all(out); + + return (ret); +} + + +#ifndef NO_MD5CRYPT_1 +/* MD5-based password algorithm (should probably be available as a library + * function; then the static buffer would not be acceptable). + * For magic string "1", this should be compatible to the MD5-based BSD + * password algorithm. + * For 'magic' string "apr1", this is compatible to the MD5-based Apache + * password algorithm. + * (Apparently, the Apache password algorithm is identical except that the + * 'magic' string was changed -- the laziest application of the NIH principle + * I've ever encountered.) + */ +static char * +md5crypt(const char *passwd, const char *magic, const char *salt) +{ + static char out_buf[6 + 9 + 24 + 2]; /* "$apr1$..salt..$.......md5h + * ash..........\0" */ + unsigned char buf[MD5_DIGEST_LENGTH]; + char *salt_out; + int n; + unsigned int i; + EVP_MD_CTX md, md2; + size_t passwd_len, salt_len; + + passwd_len = strlen(passwd); + out_buf[0] = '$'; + out_buf[1] = 0; + assert(strlen(magic) <= 4); /* "1" or "apr1" */ + strlcat(out_buf, magic, sizeof(out_buf)); + strlcat(out_buf, "$", sizeof(out_buf)); + strlcat(out_buf, salt, sizeof(out_buf)); + assert(strlen(out_buf) <= 6 + 8); /* "$apr1$..salt.." */ + salt_out = out_buf + 2 + strlen(magic); + salt_len = strlen(salt_out); + assert(salt_len <= 8); + + EVP_MD_CTX_init(&md); + EVP_DigestInit_ex(&md, EVP_md5(), NULL); + EVP_DigestUpdate(&md, passwd, passwd_len); + EVP_DigestUpdate(&md, "$", 1); + EVP_DigestUpdate(&md, magic, strlen(magic)); + EVP_DigestUpdate(&md, "$", 1); + EVP_DigestUpdate(&md, salt_out, salt_len); + + EVP_MD_CTX_init(&md2); + EVP_DigestInit_ex(&md2, EVP_md5(), NULL); + EVP_DigestUpdate(&md2, passwd, passwd_len); + EVP_DigestUpdate(&md2, salt_out, salt_len); + EVP_DigestUpdate(&md2, passwd, passwd_len); + EVP_DigestFinal_ex(&md2, buf, NULL); + + for (i = passwd_len; i > sizeof buf; i -= sizeof buf) + EVP_DigestUpdate(&md, buf, sizeof buf); + EVP_DigestUpdate(&md, buf, i); + + n = passwd_len; + while (n) { + EVP_DigestUpdate(&md, (n & 1) ? "\0" : passwd, 1); + n >>= 1; + } + EVP_DigestFinal_ex(&md, buf, NULL); + + for (i = 0; i < 1000; i++) { + EVP_DigestInit_ex(&md2, EVP_md5(), NULL); + EVP_DigestUpdate(&md2, (i & 1) ? (unsigned const char *) passwd : buf, + (i & 1) ? passwd_len : sizeof buf); + if (i % 3) + EVP_DigestUpdate(&md2, salt_out, salt_len); + if (i % 7) + EVP_DigestUpdate(&md2, passwd, passwd_len); + EVP_DigestUpdate(&md2, (i & 1) ? buf : (unsigned const char *) passwd, + (i & 1) ? sizeof buf : passwd_len); + EVP_DigestFinal_ex(&md2, buf, NULL); + } + EVP_MD_CTX_cleanup(&md2); + + { + /* transform buf into output string */ + + unsigned char buf_perm[sizeof buf]; + int dest, source; + char *output; + + /* silly output permutation */ + for (dest = 0, source = 0; dest < 14; dest++, source = (source + 6) % 17) + buf_perm[dest] = buf[source]; + buf_perm[14] = buf[5]; + buf_perm[15] = buf[11]; + assert(16 == sizeof buf_perm); + + output = salt_out + salt_len; + assert(output == out_buf + strlen(out_buf)); + + *output++ = '$'; + + for (i = 0; i < 15; i += 3) { + *output++ = cov_2char[buf_perm[i + 2] & 0x3f]; + *output++ = cov_2char[((buf_perm[i + 1] & 0xf) << 2) | + (buf_perm[i + 2] >> 6)]; + *output++ = cov_2char[((buf_perm[i] & 3) << 4) | + (buf_perm[i + 1] >> 4)]; + *output++ = cov_2char[buf_perm[i] >> 2]; + } + assert(i == 15); + *output++ = cov_2char[buf_perm[i] & 0x3f]; + *output++ = cov_2char[buf_perm[i] >> 6]; + *output = 0; + assert(strlen(out_buf) < sizeof(out_buf)); + } + EVP_MD_CTX_cleanup(&md); + + return out_buf; +} +#endif + + +static int +do_passwd(int passed_salt, char **salt_p, char **salt_malloc_p, + char *passwd, BIO * out, int quiet, int table, int reverse, + size_t pw_maxlen, int usecrypt, int use1, int useapr1) +{ + char *hash = NULL; + + assert(salt_p != NULL); + assert(salt_malloc_p != NULL); + + /* first make sure we have a salt */ + if (!passed_salt) { +#ifndef OPENSSL_NO_DES + if (usecrypt) { + if (*salt_malloc_p == NULL) { + *salt_p = *salt_malloc_p = malloc(3); + if (*salt_malloc_p == NULL) + goto err; + } + arc4random_buf(*salt_p, 2); + (*salt_p)[0] = cov_2char[(*salt_p)[0] & 0x3f]; /* 6 bits */ + (*salt_p)[1] = cov_2char[(*salt_p)[1] & 0x3f]; /* 6 bits */ + (*salt_p)[2] = 0; + } +#endif /* !OPENSSL_NO_DES */ + +#ifndef NO_MD5CRYPT_1 + if (use1 || useapr1) { + int i; + + if (*salt_malloc_p == NULL) { + *salt_p = *salt_malloc_p = malloc(9); + if (*salt_malloc_p == NULL) + goto err; + } + arc4random_buf(*salt_p, 8); + + for (i = 0; i < 8; i++) + (*salt_p)[i] = cov_2char[(*salt_p)[i] & 0x3f]; /* 6 bits */ + (*salt_p)[8] = 0; + } +#endif /* !NO_MD5CRYPT_1 */ + } + assert(*salt_p != NULL); + + /* truncate password if necessary */ + if ((strlen(passwd) > pw_maxlen)) { + if (!quiet) + /* + * XXX: really we should know how to print a size_t, + * not cast it + */ + BIO_printf(bio_err, "Warning: truncating password to %u characters\n", (unsigned) pw_maxlen); + passwd[pw_maxlen] = 0; + } + assert(strlen(passwd) <= pw_maxlen); + + /* now compute password hash */ +#ifndef OPENSSL_NO_DES + if (usecrypt) + hash = DES_crypt(passwd, *salt_p); +#endif +#ifndef NO_MD5CRYPT_1 + if (use1 || useapr1) + hash = md5crypt(passwd, (use1 ? "1" : "apr1"), *salt_p); +#endif + assert(hash != NULL); + + if (table && !reverse) + BIO_printf(out, "%s\t%s\n", passwd, hash); + else if (table && reverse) + BIO_printf(out, "%s\t%s\n", hash, passwd); + else + BIO_printf(out, "%s\n", hash); + return 1; + +err: + return 0; +} +#else + +int +passwd_main(int argc, char **argv) +{ + fputs("Program not available.\n", stderr) + return (1); +} +#endif diff --git a/bin/openssl/pkcs12.c b/bin/openssl/pkcs12.c new file mode 100644 index 0000000000..69d2d0a950 --- /dev/null +++ b/bin/openssl/pkcs12.c @@ -0,0 +1,896 @@ +/* $OpenBSD: pkcs12.c,v 1.9 2017/01/20 08:57:12 deraadt Exp $ */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 1999-2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include + +#if !defined(OPENSSL_NO_DES) && !defined(OPENSSL_NO_SHA1) + +#include +#include +#include + +#include "apps.h" + +#include +#include +#include +#include + +const EVP_CIPHER *enc; + +#define NOKEYS 0x1 +#define NOCERTS 0x2 +#define INFO 0x4 +#define CLCERTS 0x8 +#define CACERTS 0x10 + +int get_cert_chain(X509 * cert, X509_STORE * store, STACK_OF(X509) ** chain); +int dump_certs_keys_p12(BIO * out, PKCS12 * p12, char *pass, int passlen, + int options, char *pempass); +int dump_certs_pkeys_bags(BIO * out, STACK_OF(PKCS12_SAFEBAG) * bags, char *pass, + int passlen, int options, char *pempass); +int dump_certs_pkeys_bag(BIO * out, PKCS12_SAFEBAG * bags, char *pass, int passlen, + int options, char *pempass); +int print_attribs(BIO * out, STACK_OF(X509_ATTRIBUTE) * attrlst, const char *name); +void hex_prin(BIO * out, unsigned char *buf, int len); +int alg_print(BIO * x, X509_ALGOR * alg); +int cert_load(BIO * in, STACK_OF(X509) * sk); +static int set_pbe(BIO * err, int *ppbe, const char *str); + +int +pkcs12_main(int argc, char **argv) +{ + char *infile = NULL, *outfile = NULL, *keyname = NULL; + char *certfile = NULL; + BIO *in = NULL, *out = NULL; + char **args; + char *name = NULL; + char *csp_name = NULL; + int add_lmk = 0; + PKCS12 *p12 = NULL; + char pass[50], macpass[50]; + int export_cert = 0; + int options = 0; + int chain = 0; + int badarg = 0; + int iter = PKCS12_DEFAULT_ITER; + int maciter = PKCS12_DEFAULT_ITER; + int twopass = 0; + int keytype = 0; + int cert_pbe; + int key_pbe = NID_pbe_WithSHA1And3_Key_TripleDES_CBC; + int ret = 1; + int macver = 1; + int noprompt = 0; + STACK_OF(OPENSSL_STRING) * canames = NULL; + char *cpass = NULL, *mpass = NULL; + char *passargin = NULL, *passargout = NULL, *passarg = NULL; + char *passin = NULL, *passout = NULL; + char *macalg = NULL; + char *CApath = NULL, *CAfile = NULL; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + cert_pbe = NID_pbe_WithSHA1And40BitRC2_CBC; + + enc = EVP_des_ede3_cbc(); + + args = argv + 1; + + while (*args) { + if (*args[0] == '-') { + if (!strcmp(*args, "-nokeys")) + options |= NOKEYS; + else if (!strcmp(*args, "-keyex")) + keytype = KEY_EX; + else if (!strcmp(*args, "-keysig")) + keytype = KEY_SIG; + else if (!strcmp(*args, "-nocerts")) + options |= NOCERTS; + else if (!strcmp(*args, "-clcerts")) + options |= CLCERTS; + else if (!strcmp(*args, "-cacerts")) + options |= CACERTS; + else if (!strcmp(*args, "-noout")) + options |= (NOKEYS | NOCERTS); + else if (!strcmp(*args, "-info")) + options |= INFO; + else if (!strcmp(*args, "-chain")) + chain = 1; + else if (!strcmp(*args, "-twopass")) + twopass = 1; + else if (!strcmp(*args, "-nomacver")) + macver = 0; + else if (!strcmp(*args, "-descert")) + cert_pbe = NID_pbe_WithSHA1And3_Key_TripleDES_CBC; + else if (!strcmp(*args, "-export")) + export_cert = 1; + else if (!strcmp(*args, "-des")) + enc = EVP_des_cbc(); + else if (!strcmp(*args, "-des3")) + enc = EVP_des_ede3_cbc(); +#ifndef OPENSSL_NO_IDEA + else if (!strcmp(*args, "-idea")) + enc = EVP_idea_cbc(); +#endif +#ifndef OPENSSL_NO_AES + else if (!strcmp(*args, "-aes128")) + enc = EVP_aes_128_cbc(); + else if (!strcmp(*args, "-aes192")) + enc = EVP_aes_192_cbc(); + else if (!strcmp(*args, "-aes256")) + enc = EVP_aes_256_cbc(); +#endif +#ifndef OPENSSL_NO_CAMELLIA + else if (!strcmp(*args, "-camellia128")) + enc = EVP_camellia_128_cbc(); + else if (!strcmp(*args, "-camellia192")) + enc = EVP_camellia_192_cbc(); + else if (!strcmp(*args, "-camellia256")) + enc = EVP_camellia_256_cbc(); +#endif + else if (!strcmp(*args, "-noiter")) + iter = 1; + else if (!strcmp(*args, "-maciter")) + maciter = PKCS12_DEFAULT_ITER; + else if (!strcmp(*args, "-nomaciter")) + maciter = 1; + else if (!strcmp(*args, "-nomac")) + maciter = -1; + else if (!strcmp(*args, "-macalg")) + if (args[1]) { + args++; + macalg = *args; + } else + badarg = 1; + else if (!strcmp(*args, "-nodes")) + enc = NULL; + else if (!strcmp(*args, "-certpbe")) { + if (!set_pbe(bio_err, &cert_pbe, *++args)) + badarg = 1; + } else if (!strcmp(*args, "-keypbe")) { + if (!set_pbe(bio_err, &key_pbe, *++args)) + badarg = 1; + } else if (!strcmp(*args, "-inkey")) { + if (args[1]) { + args++; + keyname = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-certfile")) { + if (args[1]) { + args++; + certfile = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-name")) { + if (args[1]) { + args++; + name = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-LMK")) + add_lmk = 1; + else if (!strcmp(*args, "-CSP")) { + if (args[1]) { + args++; + csp_name = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-caname")) { + if (args[1]) { + args++; + if (!canames) + canames = sk_OPENSSL_STRING_new_null(); + sk_OPENSSL_STRING_push(canames, *args); + } else + badarg = 1; + } else if (!strcmp(*args, "-in")) { + if (args[1]) { + args++; + infile = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-out")) { + if (args[1]) { + args++; + outfile = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-passin")) { + if (args[1]) { + args++; + passargin = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-passout")) { + if (args[1]) { + args++; + passargout = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-password")) { + if (args[1]) { + args++; + passarg = *args; + noprompt = 1; + } else + badarg = 1; + } else if (!strcmp(*args, "-CApath")) { + if (args[1]) { + args++; + CApath = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-CAfile")) { + if (args[1]) { + args++; + CAfile = *args; + } else + badarg = 1; + } else + badarg = 1; + + } else + badarg = 1; + args++; + } + + if (badarg) { + BIO_printf(bio_err, "Usage: pkcs12 [options]\n"); + BIO_printf(bio_err, "where options are\n"); + BIO_printf(bio_err, "-export output PKCS12 file\n"); + BIO_printf(bio_err, "-chain add certificate chain\n"); + BIO_printf(bio_err, "-inkey file private key if not infile\n"); + BIO_printf(bio_err, "-certfile f add all certs in f\n"); + BIO_printf(bio_err, "-CApath arg - PEM format directory of CA's\n"); + BIO_printf(bio_err, "-CAfile arg - PEM format file of CA's\n"); + BIO_printf(bio_err, "-name \"name\" use name as friendly name\n"); + BIO_printf(bio_err, "-caname \"nm\" use nm as CA friendly name (can be used more than once).\n"); + BIO_printf(bio_err, "-in infile input filename\n"); + BIO_printf(bio_err, "-out outfile output filename\n"); + BIO_printf(bio_err, "-noout don't output anything, just verify.\n"); + BIO_printf(bio_err, "-nomacver don't verify MAC.\n"); + BIO_printf(bio_err, "-nocerts don't output certificates.\n"); + BIO_printf(bio_err, "-clcerts only output client certificates.\n"); + BIO_printf(bio_err, "-cacerts only output CA certificates.\n"); + BIO_printf(bio_err, "-nokeys don't output private keys.\n"); + BIO_printf(bio_err, "-info give info about PKCS#12 structure.\n"); + BIO_printf(bio_err, "-des encrypt private keys with DES\n"); + BIO_printf(bio_err, "-des3 encrypt private keys with triple DES (default)\n"); +#ifndef OPENSSL_NO_IDEA + BIO_printf(bio_err, "-idea encrypt private keys with idea\n"); +#endif +#ifndef OPENSSL_NO_AES + BIO_printf(bio_err, "-aes128, -aes192, -aes256\n"); + BIO_printf(bio_err, " encrypt PEM output with cbc aes\n"); +#endif +#ifndef OPENSSL_NO_CAMELLIA + BIO_printf(bio_err, "-camellia128, -camellia192, -camellia256\n"); + BIO_printf(bio_err, " encrypt PEM output with cbc camellia\n"); +#endif + BIO_printf(bio_err, "-nodes don't encrypt private keys\n"); + BIO_printf(bio_err, "-noiter don't use encryption iteration\n"); + BIO_printf(bio_err, "-nomaciter don't use MAC iteration\n"); + BIO_printf(bio_err, "-maciter use MAC iteration\n"); + BIO_printf(bio_err, "-nomac don't generate MAC\n"); + BIO_printf(bio_err, "-twopass separate MAC, encryption passwords\n"); + BIO_printf(bio_err, "-descert encrypt PKCS#12 certificates with triple DES (default RC2-40)\n"); + BIO_printf(bio_err, "-certpbe alg specify certificate PBE algorithm (default RC2-40)\n"); + BIO_printf(bio_err, "-keypbe alg specify private key PBE algorithm (default 3DES)\n"); + BIO_printf(bio_err, "-macalg alg digest algorithm used in MAC (default SHA1)\n"); + BIO_printf(bio_err, "-keyex set MS key exchange type\n"); + BIO_printf(bio_err, "-keysig set MS key signature type\n"); + BIO_printf(bio_err, "-password p set import/export password source\n"); + BIO_printf(bio_err, "-passin p input file pass phrase source\n"); + BIO_printf(bio_err, "-passout p output file pass phrase source\n"); + BIO_printf(bio_err, "-CSP name Microsoft CSP name\n"); + BIO_printf(bio_err, "-LMK Add local machine keyset attribute to private key\n"); + goto end; + } + + if (passarg) { + if (export_cert) + passargout = passarg; + else + passargin = passarg; + } + if (!app_passwd(bio_err, passargin, passargout, &passin, &passout)) { + BIO_printf(bio_err, "Error getting passwords\n"); + goto end; + } + if (!cpass) { + if (export_cert) + cpass = passout; + else + cpass = passin; + } + if (cpass) { + mpass = cpass; + noprompt = 1; + } else { + cpass = pass; + mpass = macpass; + } + + if (!infile) + in = BIO_new_fp(stdin, BIO_NOCLOSE); + else + in = BIO_new_file(infile, "rb"); + if (!in) { + BIO_printf(bio_err, "Error opening input file %s\n", + infile ? infile : ""); + perror(infile); + goto end; + } + + if (!outfile) { + out = BIO_new_fp(stdout, BIO_NOCLOSE); + } else + out = BIO_new_file(outfile, "wb"); + if (!out) { + BIO_printf(bio_err, "Error opening output file %s\n", + outfile ? outfile : ""); + perror(outfile); + goto end; + } + if (twopass) { + if (EVP_read_pw_string(macpass, sizeof macpass, "Enter MAC Password:", export_cert)) { + BIO_printf(bio_err, "Can't read Password\n"); + goto end; + } + } + if (export_cert) { + EVP_PKEY *key = NULL; + X509 *ucert = NULL, *x = NULL; + STACK_OF(X509) * certs = NULL; + const EVP_MD *macmd = NULL; + unsigned char *catmp = NULL; + int i; + + if ((options & (NOCERTS | NOKEYS)) == (NOCERTS | NOKEYS)) { + BIO_printf(bio_err, "Nothing to do!\n"); + goto export_end; + } + if (options & NOCERTS) + chain = 0; + + if (!(options & NOKEYS)) { + key = load_key(bio_err, keyname ? keyname : infile, + FORMAT_PEM, 1, passin, "private key"); + if (!key) + goto export_end; + } + + /* Load in all certs in input file */ + if (!(options & NOCERTS)) { + certs = load_certs(bio_err, infile, FORMAT_PEM, NULL, + "certificates"); + if (!certs) + goto export_end; + + if (key) { + /* Look for matching private key */ + for (i = 0; i < sk_X509_num(certs); i++) { + x = sk_X509_value(certs, i); + if (X509_check_private_key(x, key)) { + ucert = x; + /* Zero keyid and alias */ + X509_keyid_set1(ucert, NULL, 0); + X509_alias_set1(ucert, NULL, 0); + /* Remove from list */ + (void) sk_X509_delete(certs, i); + break; + } + } + if (!ucert) { + BIO_printf(bio_err, "No certificate matches private key\n"); + goto export_end; + } + } + } + + /* Add any more certificates asked for */ + if (certfile) { + STACK_OF(X509) * morecerts = NULL; + if (!(morecerts = load_certs(bio_err, certfile, FORMAT_PEM, + NULL, "certificates from certfile"))) + goto export_end; + while (sk_X509_num(morecerts) > 0) + sk_X509_push(certs, sk_X509_shift(morecerts)); + sk_X509_free(morecerts); + } + + + /* If chaining get chain from user cert */ + if (chain) { + int vret; + STACK_OF(X509) * chain2; + X509_STORE *store = X509_STORE_new(); + if (!store) { + BIO_printf(bio_err, "Memory allocation error\n"); + goto export_end; + } + if (!X509_STORE_load_locations(store, CAfile, CApath)) + X509_STORE_set_default_paths(store); + + vret = get_cert_chain(ucert, store, &chain2); + X509_STORE_free(store); + + if (!vret) { + /* Exclude verified certificate */ + for (i = 1; i < sk_X509_num(chain2); i++) + sk_X509_push(certs, sk_X509_value(chain2, i)); + /* Free first certificate */ + X509_free(sk_X509_value(chain2, 0)); + sk_X509_free(chain2); + } else { + if (vret >= 0) + BIO_printf(bio_err, "Error %s getting chain.\n", + X509_verify_cert_error_string(vret)); + else + ERR_print_errors(bio_err); + goto export_end; + } + } + /* Add any CA names */ + + for (i = 0; i < sk_OPENSSL_STRING_num(canames); i++) { + catmp = (unsigned char *) sk_OPENSSL_STRING_value(canames, i); + X509_alias_set1(sk_X509_value(certs, i), catmp, -1); + } + + if (csp_name && key) + EVP_PKEY_add1_attr_by_NID(key, NID_ms_csp_name, + MBSTRING_ASC, (unsigned char *) csp_name, -1); + + if (add_lmk && key) + EVP_PKEY_add1_attr_by_NID(key, NID_LocalKeySet, 0, NULL, -1); + + + if (!noprompt && + EVP_read_pw_string(pass, sizeof pass, "Enter Export Password:", 1)) { + BIO_printf(bio_err, "Can't read Password\n"); + goto export_end; + } + if (!twopass) + strlcpy(macpass, pass, sizeof macpass); + + + p12 = PKCS12_create(cpass, name, key, ucert, certs, + key_pbe, cert_pbe, iter, -1, keytype); + + if (!p12) { + ERR_print_errors(bio_err); + goto export_end; + } + if (macalg) { + macmd = EVP_get_digestbyname(macalg); + if (!macmd) { + BIO_printf(bio_err, "Unknown digest algorithm %s\n", + macalg); + } + } + if (maciter != -1) + PKCS12_set_mac(p12, mpass, -1, NULL, 0, maciter, macmd); + + + i2d_PKCS12_bio(out, p12); + + ret = 0; + +export_end: + + if (key) + EVP_PKEY_free(key); + if (certs) + sk_X509_pop_free(certs, X509_free); + if (ucert) + X509_free(ucert); + + goto end; + + } + if (!(p12 = d2i_PKCS12_bio(in, NULL))) { + ERR_print_errors(bio_err); + goto end; + } + if (!noprompt && EVP_read_pw_string(pass, sizeof pass, "Enter Import Password:", 0)) { + BIO_printf(bio_err, "Can't read Password\n"); + goto end; + } + + if (!twopass) + strlcpy(macpass, pass, sizeof macpass); + + if ((options & INFO) && p12->mac) + BIO_printf(bio_err, "MAC Iteration %ld\n", p12->mac->iter ? ASN1_INTEGER_get(p12->mac->iter) : 1); + if (macver) { + /* If we enter empty password try no password first */ + if (!mpass[0] && PKCS12_verify_mac(p12, NULL, 0)) { + /* If mac and crypto pass the same set it to NULL too */ + if (!twopass) + cpass = NULL; + } else if (!PKCS12_verify_mac(p12, mpass, -1)) { + BIO_printf(bio_err, "Mac verify error: invalid password?\n"); + ERR_print_errors(bio_err); + goto end; + } + BIO_printf(bio_err, "MAC verified OK\n"); + } + if (!dump_certs_keys_p12(out, p12, cpass, -1, options, passout)) { + BIO_printf(bio_err, "Error outputting keys and certificates\n"); + ERR_print_errors(bio_err); + goto end; + } + ret = 0; +end: + if (p12) + PKCS12_free(p12); + BIO_free(in); + BIO_free_all(out); + if (canames) + sk_OPENSSL_STRING_free(canames); + free(passin); + free(passout); + + return (ret); +} + +int +dump_certs_keys_p12(BIO * out, PKCS12 * p12, char *pass, + int passlen, int options, char *pempass) +{ + STACK_OF(PKCS7) * asafes = NULL; + STACK_OF(PKCS12_SAFEBAG) * bags; + int i, bagnid; + int ret = 0; + PKCS7 *p7; + + if (!(asafes = PKCS12_unpack_authsafes(p12))) + return 0; + for (i = 0; i < sk_PKCS7_num(asafes); i++) { + p7 = sk_PKCS7_value(asafes, i); + bagnid = OBJ_obj2nid(p7->type); + if (bagnid == NID_pkcs7_data) { + bags = PKCS12_unpack_p7data(p7); + if (options & INFO) + BIO_printf(bio_err, "PKCS7 Data\n"); + } else if (bagnid == NID_pkcs7_encrypted) { + if (options & INFO) { + BIO_printf(bio_err, "PKCS7 Encrypted data: "); + alg_print(bio_err, + p7->d.encrypted->enc_data->algorithm); + } + bags = PKCS12_unpack_p7encdata(p7, pass, passlen); + } else + continue; + if (!bags) + goto err; + if (!dump_certs_pkeys_bags(out, bags, pass, passlen, + options, pempass)) { + sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); + goto err; + } + sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); + bags = NULL; + } + ret = 1; + +err: + + if (asafes) + sk_PKCS7_pop_free(asafes, PKCS7_free); + return ret; +} + +int +dump_certs_pkeys_bags(BIO * out, STACK_OF(PKCS12_SAFEBAG) * bags, + char *pass, int passlen, int options, char *pempass) +{ + int i; + for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) { + if (!dump_certs_pkeys_bag(out, + sk_PKCS12_SAFEBAG_value(bags, i), + pass, passlen, + options, pempass)) + return 0; + } + return 1; +} + +int +dump_certs_pkeys_bag(BIO * out, PKCS12_SAFEBAG * bag, char *pass, + int passlen, int options, char *pempass) +{ + EVP_PKEY *pkey; + PKCS8_PRIV_KEY_INFO *p8; + X509 *x509; + + switch (OBJ_obj2nid(bag->type)) { + case NID_keyBag: + if (options & INFO) + BIO_printf(bio_err, "Key bag\n"); + if (options & NOKEYS) + return 1; + print_attribs(out, bag->attrib, "Bag Attributes"); + p8 = bag->value.keybag; + if (!(pkey = EVP_PKCS82PKEY(p8))) + return 0; + print_attribs(out, p8->attributes, "Key Attributes"); + PEM_write_bio_PrivateKey(out, pkey, enc, NULL, 0, NULL, pempass); + EVP_PKEY_free(pkey); + break; + + case NID_pkcs8ShroudedKeyBag: + if (options & INFO) { + BIO_printf(bio_err, "Shrouded Keybag: "); + alg_print(bio_err, bag->value.shkeybag->algor); + } + if (options & NOKEYS) + return 1; + print_attribs(out, bag->attrib, "Bag Attributes"); + if (!(p8 = PKCS12_decrypt_skey(bag, pass, passlen))) + return 0; + if (!(pkey = EVP_PKCS82PKEY(p8))) { + PKCS8_PRIV_KEY_INFO_free(p8); + return 0; + } + print_attribs(out, p8->attributes, "Key Attributes"); + PKCS8_PRIV_KEY_INFO_free(p8); + PEM_write_bio_PrivateKey(out, pkey, enc, NULL, 0, NULL, pempass); + EVP_PKEY_free(pkey); + break; + + case NID_certBag: + if (options & INFO) + BIO_printf(bio_err, "Certificate bag\n"); + if (options & NOCERTS) + return 1; + if (PKCS12_get_attr(bag, NID_localKeyID)) { + if (options & CACERTS) + return 1; + } else if (options & CLCERTS) + return 1; + print_attribs(out, bag->attrib, "Bag Attributes"); + if (OBJ_obj2nid(bag->value.bag->type) != NID_x509Certificate) + return 1; + if (!(x509 = PKCS12_certbag2x509(bag))) + return 0; + dump_cert_text(out, x509); + PEM_write_bio_X509(out, x509); + X509_free(x509); + break; + + case NID_safeContentsBag: + if (options & INFO) + BIO_printf(bio_err, "Safe Contents bag\n"); + print_attribs(out, bag->attrib, "Bag Attributes"); + return dump_certs_pkeys_bags(out, bag->value.safes, pass, + passlen, options, pempass); + + default: + BIO_printf(bio_err, "Warning unsupported bag type: "); + i2a_ASN1_OBJECT(bio_err, bag->type); + BIO_printf(bio_err, "\n"); + return 1; + break; + } + return 1; +} + +/* Given a single certificate return a verified chain or NULL if error */ + +/* Hope this is OK .... */ + +int +get_cert_chain(X509 * cert, X509_STORE * store, STACK_OF(X509) ** chain) +{ + X509_STORE_CTX store_ctx; + STACK_OF(X509) * chn; + int i = 0; + + /* + * FIXME: Should really check the return status of + * X509_STORE_CTX_init for an error, but how that fits into the + * return value of this function is less obvious. + */ + X509_STORE_CTX_init(&store_ctx, store, cert, NULL); + if (X509_verify_cert(&store_ctx) <= 0) { + i = X509_STORE_CTX_get_error(&store_ctx); + if (i == 0) + /* + * avoid returning 0 if X509_verify_cert() did not + * set an appropriate error value in the context + */ + i = -1; + chn = NULL; + goto err; + } else + chn = X509_STORE_CTX_get1_chain(&store_ctx); +err: + X509_STORE_CTX_cleanup(&store_ctx); + *chain = chn; + + return i; +} + +int +alg_print(BIO * x, X509_ALGOR * alg) +{ + PBEPARAM *pbe; + const unsigned char *p; + p = alg->parameter->value.sequence->data; + pbe = d2i_PBEPARAM(NULL, &p, alg->parameter->value.sequence->length); + if (!pbe) + return 1; + BIO_printf(bio_err, "%s, Iteration %ld\n", + OBJ_nid2ln(OBJ_obj2nid(alg->algorithm)), + ASN1_INTEGER_get(pbe->iter)); + PBEPARAM_free(pbe); + return 1; +} + +/* Load all certificates from a given file */ + +int +cert_load(BIO * in, STACK_OF(X509) * sk) +{ + int ret; + X509 *cert; + ret = 0; + while ((cert = PEM_read_bio_X509(in, NULL, NULL, NULL))) { + ret = 1; + sk_X509_push(sk, cert); + } + if (ret) + ERR_clear_error(); + return ret; +} + +/* Generalised attribute print: handle PKCS#8 and bag attributes */ + +int +print_attribs(BIO * out, STACK_OF(X509_ATTRIBUTE) * attrlst, const char *name) +{ + X509_ATTRIBUTE *attr; + ASN1_TYPE *av; + char *value; + int i, attr_nid; + if (!attrlst) { + BIO_printf(out, "%s: \n", name); + return 1; + } + if (!sk_X509_ATTRIBUTE_num(attrlst)) { + BIO_printf(out, "%s: \n", name); + return 1; + } + BIO_printf(out, "%s\n", name); + for (i = 0; i < sk_X509_ATTRIBUTE_num(attrlst); i++) { + attr = sk_X509_ATTRIBUTE_value(attrlst, i); + attr_nid = OBJ_obj2nid(attr->object); + BIO_printf(out, " "); + if (attr_nid == NID_undef) { + i2a_ASN1_OBJECT(out, attr->object); + BIO_printf(out, ": "); + } else + BIO_printf(out, "%s: ", OBJ_nid2ln(attr_nid)); + + if (sk_ASN1_TYPE_num(attr->value.set)) { + av = sk_ASN1_TYPE_value(attr->value.set, 0); + switch (av->type) { + case V_ASN1_BMPSTRING: + value = OPENSSL_uni2asc(av->value.bmpstring->data, + av->value.bmpstring->length); + BIO_printf(out, "%s\n", value); + free(value); + break; + + case V_ASN1_OCTET_STRING: + hex_prin(out, av->value.octet_string->data, + av->value.octet_string->length); + BIO_printf(out, "\n"); + break; + + case V_ASN1_BIT_STRING: + hex_prin(out, av->value.bit_string->data, + av->value.bit_string->length); + BIO_printf(out, "\n"); + break; + + default: + BIO_printf(out, "\n", av->type); + break; + } + } else + BIO_printf(out, "\n"); + } + return 1; +} + +void +hex_prin(BIO * out, unsigned char *buf, int len) +{ + int i; + for (i = 0; i < len; i++) + BIO_printf(out, "%02X ", buf[i]); +} + +static int +set_pbe(BIO * err, int *ppbe, const char *str) +{ + if (!str) + return 0; + if (!strcmp(str, "NONE")) { + *ppbe = -1; + return 1; + } + *ppbe = OBJ_txt2nid(str); + if (*ppbe == NID_undef) { + BIO_printf(bio_err, "Unknown PBE algorithm %s\n", str); + return 0; + } + return 1; +} + +#endif diff --git a/bin/openssl/pkcs7.c b/bin/openssl/pkcs7.c new file mode 100644 index 0000000000..32d1682ff1 --- /dev/null +++ b/bin/openssl/pkcs7.c @@ -0,0 +1,289 @@ +/* $OpenBSD: pkcs7.c,v 1.9 2017/01/20 08:57:12 deraadt Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include +#include +#include +#include + +#include "apps.h" + +#include +#include +#include +#include +#include +#include + +static struct { + char *infile; + int informat; + int noout; + char *outfile; + int outformat; + int p7_print; + int print_certs; + int text; +} pkcs7_config; + +static struct option pkcs7_options[] = { + { + .name = "in", + .argname = "file", + .desc = "Input file (default stdin)", + .type = OPTION_ARG, + .opt.arg = &pkcs7_config.infile, + }, + { + .name = "inform", + .argname = "format", + .desc = "Input format (DER or PEM (default))", + .type = OPTION_ARG_FORMAT, + .opt.value = &pkcs7_config.informat, + }, + { + .name = "noout", + .desc = "Do not output encoded version of PKCS#7 structure", + .type = OPTION_FLAG, + .opt.flag = &pkcs7_config.noout, + }, + { + .name = "out", + .argname = "file", + .desc = "Output file (default stdout)", + .type = OPTION_ARG, + .opt.arg = &pkcs7_config.outfile, + }, + { + .name = "outform", + .argname = "format", + .desc = "Output format (DER or PEM (default))", + .type = OPTION_ARG_FORMAT, + .opt.value = &pkcs7_config.outformat, + }, + { + .name = "print", + .desc = "Output ASN.1 representation of PKCS#7 structure", + .type = OPTION_FLAG, + .opt.flag = &pkcs7_config.p7_print, + }, + { + .name = "print_certs", + .desc = "Print out any certificates or CRLs contained in file", + .type = OPTION_FLAG, + .opt.flag = &pkcs7_config.print_certs, + }, + { + .name = "text", + .desc = "Print out full certificate details", + .type = OPTION_FLAG, + .opt.flag = &pkcs7_config.text, + }, + { NULL }, +}; + +static void +pkcs7_usage() +{ + fprintf(stderr, "usage: pkcs7 [-in file] " + "[-inform DER | PEM] [-noout]\n" + " [-out file] [-outform DER | PEM] [-print_certs] [-text]\n\n"); + options_usage(pkcs7_options); +} + +int +pkcs7_main(int argc, char **argv) +{ + PKCS7 *p7 = NULL; + BIO *in = NULL, *out = NULL; + int ret = 1; + int i; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + memset(&pkcs7_config, 0, sizeof(pkcs7_config)); + + pkcs7_config.informat = FORMAT_PEM; + pkcs7_config.outformat = FORMAT_PEM; + + if (options_parse(argc, argv, pkcs7_options, NULL, NULL) != 0) { + pkcs7_usage(); + goto end; + } + + in = BIO_new(BIO_s_file()); + out = BIO_new(BIO_s_file()); + if ((in == NULL) || (out == NULL)) { + ERR_print_errors(bio_err); + goto end; + } + if (pkcs7_config.infile == NULL) + BIO_set_fp(in, stdin, BIO_NOCLOSE); + else { + if (BIO_read_filename(in, pkcs7_config.infile) <= 0) { + perror(pkcs7_config.infile); + goto end; + } + } + + if (pkcs7_config.informat == FORMAT_ASN1) + p7 = d2i_PKCS7_bio(in, NULL); + else if (pkcs7_config.informat == FORMAT_PEM) + p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL); + else { + BIO_printf(bio_err, "bad input format specified for pkcs7 object\n"); + goto end; + } + if (p7 == NULL) { + BIO_printf(bio_err, "unable to load PKCS7 object\n"); + ERR_print_errors(bio_err); + goto end; + } + if (pkcs7_config.outfile == NULL) { + BIO_set_fp(out, stdout, BIO_NOCLOSE); + } else { + if (BIO_write_filename(out, pkcs7_config.outfile) <= 0) { + perror(pkcs7_config.outfile); + goto end; + } + } + + if (pkcs7_config.p7_print) + PKCS7_print_ctx(out, p7, 0, NULL); + + if (pkcs7_config.print_certs) { + STACK_OF(X509) * certs = NULL; + STACK_OF(X509_CRL) * crls = NULL; + + i = OBJ_obj2nid(p7->type); + switch (i) { + case NID_pkcs7_signed: + certs = p7->d.sign->cert; + crls = p7->d.sign->crl; + break; + case NID_pkcs7_signedAndEnveloped: + certs = p7->d.signed_and_enveloped->cert; + crls = p7->d.signed_and_enveloped->crl; + break; + default: + break; + } + + if (certs != NULL) { + X509 *x; + + for (i = 0; i < sk_X509_num(certs); i++) { + x = sk_X509_value(certs, i); + if (pkcs7_config.text) + X509_print(out, x); + else + dump_cert_text(out, x); + + if (!pkcs7_config.noout) + PEM_write_bio_X509(out, x); + BIO_puts(out, "\n"); + } + } + if (crls != NULL) { + X509_CRL *crl; + + for (i = 0; i < sk_X509_CRL_num(crls); i++) { + crl = sk_X509_CRL_value(crls, i); + + X509_CRL_print(out, crl); + + if (!pkcs7_config.noout) + PEM_write_bio_X509_CRL(out, crl); + BIO_puts(out, "\n"); + } + } + ret = 0; + goto end; + } + if (!pkcs7_config.noout) { + if (pkcs7_config.outformat == FORMAT_ASN1) + i = i2d_PKCS7_bio(out, p7); + else if (pkcs7_config.outformat == FORMAT_PEM) + i = PEM_write_bio_PKCS7(out, p7); + else { + BIO_printf(bio_err, "bad output format specified for outfile\n"); + goto end; + } + + if (!i) { + BIO_printf(bio_err, "unable to write pkcs7 object\n"); + ERR_print_errors(bio_err); + goto end; + } + } + ret = 0; +end: + if (p7 != NULL) + PKCS7_free(p7); + if (in != NULL) + BIO_free(in); + if (out != NULL) + BIO_free_all(out); + + return (ret); +} diff --git a/bin/openssl/pkcs8.c b/bin/openssl/pkcs8.c new file mode 100644 index 0000000000..5d1c2023af --- /dev/null +++ b/bin/openssl/pkcs8.c @@ -0,0 +1,419 @@ +/* $OpenBSD: pkcs8.c,v 1.10 2017/01/20 08:57:12 deraadt Exp $ */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999-2004. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include +#include + +#include "apps.h" +#include "progs.h" + +#include +#include +#include +#include + +static struct { + const EVP_CIPHER *cipher; + char *infile; + int informat; + int iter; + int nocrypt; + char *outfile; + int outformat; + int p8_broken; + char *passargin; + char *passargout; + int pbe_nid; + int topk8; +} pkcs8_config; + +static int +pkcs8_opt_v1(char *arg) +{ + if ((pkcs8_config.pbe_nid = OBJ_txt2nid(arg)) == NID_undef) { + fprintf(stderr, "Unknown PBE algorithm '%s'\n", arg); + return (1); + } + + return (0); +} + +static int +pkcs8_opt_v2(char *arg) +{ + if ((pkcs8_config.cipher = EVP_get_cipherbyname(arg)) == NULL) { + fprintf(stderr, "Unknown cipher '%s'\n", arg); + return (1); + } + + return (0); +} + +static struct option pkcs8_options[] = { + { + .name = "embed", + .desc = "Generate DSA keys in a broken format", + .type = OPTION_VALUE, + .value = PKCS8_EMBEDDED_PARAM, + .opt.value = &pkcs8_config.p8_broken, + }, + { + .name = "in", + .argname = "file", + .desc = "Input file (default stdin)", + .type = OPTION_ARG, + .opt.arg = &pkcs8_config.infile, + }, + { + .name = "inform", + .argname = "format", + .desc = "Input format (DER or PEM (default))", + .type = OPTION_ARG_FORMAT, + .opt.value = &pkcs8_config.informat, + }, + { + .name = "nocrypt", + .desc = "Use or expect unencrypted private key", + .type = OPTION_FLAG, + .opt.flag = &pkcs8_config.nocrypt, + }, + { + .name = "noiter", + .desc = "Use 1 as iteration count", + .type = OPTION_VALUE, + .value = 1, + .opt.value = &pkcs8_config.iter, + }, + { + .name = "nooct", + .desc = "Generate RSA keys in a broken format (no octet)", + .type = OPTION_VALUE, + .value = PKCS8_NO_OCTET, + .opt.value = &pkcs8_config.p8_broken, + }, + { + .name = "nsdb", + .desc = "Generate DSA keys in the broken Netscape DB format", + .type = OPTION_VALUE, + .value = PKCS8_NS_DB, + .opt.value = &pkcs8_config.p8_broken, + }, + { + .name = "out", + .argname = "file", + .desc = "Output file (default stdout)", + .type = OPTION_ARG, + .opt.arg = &pkcs8_config.outfile, + }, + { + .name = "outform", + .argname = "format", + .desc = "Output format (DER or PEM (default))", + .type = OPTION_ARG_FORMAT, + .opt.value = &pkcs8_config.outformat, + }, + { + .name = "passin", + .argname = "source", + .desc = "Input file passphrase source", + .type = OPTION_ARG, + .opt.arg = &pkcs8_config.passargin, + }, + { + .name = "passout", + .argname = "source", + .desc = "Output file passphrase source", + .type = OPTION_ARG, + .opt.arg = &pkcs8_config.passargout, + }, + { + .name = "topk8", + .desc = "Read traditional format key and write PKCS#8 format" + " key", + .type = OPTION_FLAG, + .opt.flag = &pkcs8_config.topk8, + }, + { + .name = "v1", + .argname = "algorithm", + .desc = "Use PKCS#5 v1.5 or PKCS#12 with given algorithm", + .type = OPTION_ARG_FUNC, + .opt.argfunc = pkcs8_opt_v1, + }, + { + .name = "v2", + .argname = "cipher", + .desc = "Use PKCS#5 v2.0 with given cipher", + .type = OPTION_ARG_FUNC, + .opt.argfunc = pkcs8_opt_v2, + }, + { NULL }, +}; + +static void +pkcs8_usage() +{ + fprintf(stderr, "usage: pkcs8 [-embed] [-in file] " + "[-inform fmt] [-nocrypt]\n" + " [-noiter] [-nooct] [-nsdb] [-out file] [-outform fmt] " + "[-passin src]\n" + " [-passout src] [-topk8] [-v1 alg] [-v2 alg]\n\n"); + options_usage(pkcs8_options); +} + +int +pkcs8_main(int argc, char **argv) +{ + BIO *in = NULL, *out = NULL; + X509_SIG *p8 = NULL; + PKCS8_PRIV_KEY_INFO *p8inf = NULL; + EVP_PKEY *pkey = NULL; + char pass[50], *passin = NULL, *passout = NULL, *p8pass = NULL; + int ret = 1; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + memset(&pkcs8_config, 0, sizeof(pkcs8_config)); + + pkcs8_config.iter = PKCS12_DEFAULT_ITER; + pkcs8_config.informat = FORMAT_PEM; + pkcs8_config.outformat = FORMAT_PEM; + pkcs8_config.p8_broken = PKCS8_OK; + pkcs8_config.pbe_nid = -1; + + if (options_parse(argc, argv, pkcs8_options, NULL, NULL) != 0) { + pkcs8_usage(); + return (1); + } + + if (!app_passwd(bio_err, pkcs8_config.passargin, + pkcs8_config.passargout, &passin, &passout)) { + BIO_printf(bio_err, "Error getting passwords\n"); + goto end; + } + if ((pkcs8_config.pbe_nid == -1) && !pkcs8_config.cipher) + pkcs8_config.pbe_nid = NID_pbeWithMD5AndDES_CBC; + + if (pkcs8_config.infile) { + if (!(in = BIO_new_file(pkcs8_config.infile, "rb"))) { + BIO_printf(bio_err, + "Can't open input file '%s'\n", + pkcs8_config.infile); + goto end; + } + } else + in = BIO_new_fp(stdin, BIO_NOCLOSE); + + if (pkcs8_config.outfile) { + if (!(out = BIO_new_file(pkcs8_config.outfile, "wb"))) { + BIO_printf(bio_err, "Can't open output file '%s'\n", + pkcs8_config.outfile); + goto end; + } + } else { + out = BIO_new_fp(stdout, BIO_NOCLOSE); + } + if (pkcs8_config.topk8) { + pkey = load_key(bio_err, pkcs8_config.infile, + pkcs8_config.informat, 1, passin, "key"); + if (!pkey) + goto end; + if (!(p8inf = EVP_PKEY2PKCS8_broken(pkey, + pkcs8_config.p8_broken))) { + BIO_printf(bio_err, "Error converting key\n"); + ERR_print_errors(bio_err); + goto end; + } + if (pkcs8_config.nocrypt) { + if (pkcs8_config.outformat == FORMAT_PEM) + PEM_write_bio_PKCS8_PRIV_KEY_INFO(out, p8inf); + else if (pkcs8_config.outformat == FORMAT_ASN1) + i2d_PKCS8_PRIV_KEY_INFO_bio(out, p8inf); + else { + BIO_printf(bio_err, + "Bad format specified for key\n"); + goto end; + } + } else { + if (passout) + p8pass = passout; + else { + p8pass = pass; + if (EVP_read_pw_string(pass, sizeof pass, + "Enter Encryption Password:", 1)) + goto end; + } + if (!(p8 = PKCS8_encrypt(pkcs8_config.pbe_nid, + pkcs8_config.cipher, p8pass, strlen(p8pass), + NULL, 0, pkcs8_config.iter, p8inf))) { + BIO_printf(bio_err, "Error encrypting key\n"); + ERR_print_errors(bio_err); + goto end; + } + if (pkcs8_config.outformat == FORMAT_PEM) + PEM_write_bio_PKCS8(out, p8); + else if (pkcs8_config.outformat == FORMAT_ASN1) + i2d_PKCS8_bio(out, p8); + else { + BIO_printf(bio_err, + "Bad format specified for key\n"); + goto end; + } + } + + ret = 0; + goto end; + } + if (pkcs8_config.nocrypt) { + if (pkcs8_config.informat == FORMAT_PEM) + p8inf = PEM_read_bio_PKCS8_PRIV_KEY_INFO(in, NULL, + NULL, NULL); + else if (pkcs8_config.informat == FORMAT_ASN1) + p8inf = d2i_PKCS8_PRIV_KEY_INFO_bio(in, NULL); + else { + BIO_printf(bio_err, "Bad format specified for key\n"); + goto end; + } + } else { + if (pkcs8_config.informat == FORMAT_PEM) + p8 = PEM_read_bio_PKCS8(in, NULL, NULL, NULL); + else if (pkcs8_config.informat == FORMAT_ASN1) + p8 = d2i_PKCS8_bio(in, NULL); + else { + BIO_printf(bio_err, "Bad format specified for key\n"); + goto end; + } + + if (!p8) { + BIO_printf(bio_err, "Error reading key\n"); + ERR_print_errors(bio_err); + goto end; + } + if (passin) + p8pass = passin; + else { + p8pass = pass; + EVP_read_pw_string(pass, sizeof pass, + "Enter Password:", 0); + } + p8inf = PKCS8_decrypt(p8, p8pass, strlen(p8pass)); + } + + if (!p8inf) { + BIO_printf(bio_err, "Error decrypting key\n"); + ERR_print_errors(bio_err); + goto end; + } + if (!(pkey = EVP_PKCS82PKEY(p8inf))) { + BIO_printf(bio_err, "Error converting key\n"); + ERR_print_errors(bio_err); + goto end; + } + if (p8inf->broken) { + BIO_printf(bio_err, "Warning: broken key encoding: "); + switch (p8inf->broken) { + case PKCS8_NO_OCTET: + BIO_printf(bio_err, "No Octet String in PrivateKey\n"); + break; + + case PKCS8_EMBEDDED_PARAM: + BIO_printf(bio_err, + "DSA parameters included in PrivateKey\n"); + break; + + case PKCS8_NS_DB: + BIO_printf(bio_err, + "DSA public key include in PrivateKey\n"); + break; + + case PKCS8_NEG_PRIVKEY: + BIO_printf(bio_err, "DSA private key value is negative\n"); + break; + + default: + BIO_printf(bio_err, "Unknown broken type\n"); + break; + } + } + if (pkcs8_config.outformat == FORMAT_PEM) + PEM_write_bio_PrivateKey(out, pkey, NULL, NULL, 0, NULL, + passout); + else if (pkcs8_config.outformat == FORMAT_ASN1) + i2d_PrivateKey_bio(out, pkey); + else { + BIO_printf(bio_err, "Bad format specified for key\n"); + goto end; + } + ret = 0; + +end: + X509_SIG_free(p8); + PKCS8_PRIV_KEY_INFO_free(p8inf); + EVP_PKEY_free(pkey); + BIO_free_all(out); + BIO_free(in); + free(passin); + free(passout); + + return ret; +} diff --git a/bin/openssl/pkey.c b/bin/openssl/pkey.c new file mode 100644 index 0000000000..e91bc79090 --- /dev/null +++ b/bin/openssl/pkey.c @@ -0,0 +1,220 @@ +/* $OpenBSD: pkey.c,v 1.9 2017/01/20 08:57:12 deraadt Exp $ */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2006 + */ +/* ==================================================================== + * Copyright (c) 2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include +#include + +#include "apps.h" + +#include +#include +#include + +int +pkey_main(int argc, char **argv) +{ + char **args, *infile = NULL, *outfile = NULL; + char *passargin = NULL, *passargout = NULL; + BIO *in = NULL, *out = NULL; + const EVP_CIPHER *cipher = NULL; + int informat, outformat; + int pubin = 0, pubout = 0, pubtext = 0, text = 0, noout = 0; + EVP_PKEY *pkey = NULL; + char *passin = NULL, *passout = NULL; + int badarg = 0; + int ret = 1; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + informat = FORMAT_PEM; + outformat = FORMAT_PEM; + + args = argv + 1; + while (!badarg && *args && *args[0] == '-') { + if (!strcmp(*args, "-inform")) { + if (args[1]) { + args++; + informat = str2fmt(*args); + } else + badarg = 1; + } else if (!strcmp(*args, "-outform")) { + if (args[1]) { + args++; + outformat = str2fmt(*args); + } else + badarg = 1; + } else if (!strcmp(*args, "-passin")) { + if (!args[1]) + goto bad; + passargin = *(++args); + } else if (!strcmp(*args, "-passout")) { + if (!args[1]) + goto bad; + passargout = *(++args); + } + else if (!strcmp(*args, "-in")) { + if (args[1]) { + args++; + infile = *args; + } else + badarg = 1; + } else if (!strcmp(*args, "-out")) { + if (args[1]) { + args++; + outfile = *args; + } else + badarg = 1; + } else if (strcmp(*args, "-pubin") == 0) { + pubin = 1; + pubout = 1; + pubtext = 1; + } else if (strcmp(*args, "-pubout") == 0) + pubout = 1; + else if (strcmp(*args, "-text_pub") == 0) { + pubtext = 1; + text = 1; + } else if (strcmp(*args, "-text") == 0) + text = 1; + else if (strcmp(*args, "-noout") == 0) + noout = 1; + else { + cipher = EVP_get_cipherbyname(*args + 1); + if (!cipher) { + BIO_printf(bio_err, "Unknown cipher %s\n", + *args + 1); + badarg = 1; + } + } + args++; + } + + if (badarg) { +bad: + BIO_printf(bio_err, "Usage pkey [options]\n"); + BIO_printf(bio_err, "where options are\n"); + BIO_printf(bio_err, "-in file input file\n"); + BIO_printf(bio_err, "-inform X input format (DER or PEM)\n"); + BIO_printf(bio_err, "-passin arg input file pass phrase source\n"); + BIO_printf(bio_err, "-outform X output format (DER or PEM)\n"); + BIO_printf(bio_err, "-out file output file\n"); + BIO_printf(bio_err, "-passout arg output file pass phrase source\n"); + return 1; + } + + if (!app_passwd(bio_err, passargin, passargout, &passin, &passout)) { + BIO_printf(bio_err, "Error getting passwords\n"); + goto end; + } + if (outfile) { + if (!(out = BIO_new_file(outfile, "wb"))) { + BIO_printf(bio_err, + "Can't open output file %s\n", outfile); + goto end; + } + } else { + out = BIO_new_fp(stdout, BIO_NOCLOSE); + } + + if (pubin) + pkey = load_pubkey(bio_err, infile, informat, 1, + passin, "Public Key"); + else + pkey = load_key(bio_err, infile, informat, 1, passin, "key"); + if (!pkey) + goto end; + + if (!noout) { + if (outformat == FORMAT_PEM) { + if (pubout) + PEM_write_bio_PUBKEY(out, pkey); + else + PEM_write_bio_PrivateKey(out, pkey, cipher, + NULL, 0, NULL, passout); + } else if (outformat == FORMAT_ASN1) { + if (pubout) + i2d_PUBKEY_bio(out, pkey); + else + i2d_PrivateKey_bio(out, pkey); + } else { + BIO_printf(bio_err, "Bad format specified for key\n"); + goto end; + } + + } + if (text) { + if (pubtext) + EVP_PKEY_print_public(out, pkey, 0, NULL); + else + EVP_PKEY_print_private(out, pkey, 0, NULL); + } + ret = 0; + +end: + EVP_PKEY_free(pkey); + BIO_free_all(out); + BIO_free(in); + free(passin); + free(passout); + + return ret; +} diff --git a/bin/openssl/pkeyparam.c b/bin/openssl/pkeyparam.c new file mode 100644 index 0000000000..698c105141 --- /dev/null +++ b/bin/openssl/pkeyparam.c @@ -0,0 +1,174 @@ +/* $OpenBSD: pkeyparam.c,v 1.10 2017/01/20 08:57:12 deraadt Exp $ */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2006 + */ +/* ==================================================================== + * Copyright (c) 2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include +#include + +#include "apps.h" + +#include +#include +#include + +struct { + char *infile; + int noout; + char *outfile; + int text; +} pkeyparam_config; + +struct option pkeyparam_options[] = { + { + .name = "in", + .argname = "file", + .desc = "Input file (default stdin)", + .type = OPTION_ARG, + .opt.arg = &pkeyparam_config.infile, + }, + { + .name = "noout", + .desc = "Do not print encoded version of the parameters", + .type = OPTION_FLAG, + .opt.flag = &pkeyparam_config.noout, + }, + { + .name = "out", + .argname = "file", + .desc = "Output file (default stdout)", + .type = OPTION_ARG, + .opt.arg = &pkeyparam_config.outfile, + }, + { + .name = "text", + .desc = "Print out the parameters in plain text", + .type = OPTION_FLAG, + .opt.flag = &pkeyparam_config.text, + }, + { NULL }, +}; + +static void +pkeyparam_usage() +{ + fprintf(stderr, + "usage: pkeyparam [-in file] [-noout] [-out file] " + "[-text]\n"); + options_usage(pkeyparam_options); +} + +int +pkeyparam_main(int argc, char **argv) +{ + BIO *in = NULL, *out = NULL; + EVP_PKEY *pkey = NULL; + int ret = 1; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + memset(&pkeyparam_config, 0, sizeof(pkeyparam_config)); + + if (options_parse(argc, argv, pkeyparam_options, NULL, NULL) != 0) { + pkeyparam_usage(); + return (1); + } + + if (pkeyparam_config.infile) { + if (!(in = BIO_new_file(pkeyparam_config.infile, "r"))) { + BIO_printf(bio_err, "Can't open input file %s\n", + pkeyparam_config.infile); + goto end; + } + } else + in = BIO_new_fp(stdin, BIO_NOCLOSE); + + if (pkeyparam_config.outfile) { + if (!(out = BIO_new_file(pkeyparam_config.outfile, "w"))) { + BIO_printf(bio_err, "Can't open output file %s\n", + pkeyparam_config.outfile); + goto end; + } + } else { + out = BIO_new_fp(stdout, BIO_NOCLOSE); + } + + pkey = PEM_read_bio_Parameters(in, NULL); + if (!pkey) { + BIO_printf(bio_err, "Error reading parameters\n"); + ERR_print_errors(bio_err); + goto end; + } + if (!pkeyparam_config.noout) + PEM_write_bio_Parameters(out, pkey); + + if (pkeyparam_config.text) + EVP_PKEY_print_params(out, pkey, 0, NULL); + + ret = 0; + +end: + EVP_PKEY_free(pkey); + BIO_free_all(out); + BIO_free(in); + + return ret; +} diff --git a/bin/openssl/pkeyutl.c b/bin/openssl/pkeyutl.c new file mode 100644 index 0000000000..4752b4c79a --- /dev/null +++ b/bin/openssl/pkeyutl.c @@ -0,0 +1,494 @@ +/* $OpenBSD: pkeyutl.c,v 1.11 2017/01/20 08:57:12 deraadt Exp $ */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2006. + */ +/* ==================================================================== + * Copyright (c) 2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include + +#include "apps.h" + +#include +#include +#include + +#define KEY_PRIVKEY 1 +#define KEY_PUBKEY 2 +#define KEY_CERT 3 + +static void usage(void); + +static EVP_PKEY_CTX *init_ctx(int *pkeysize, + char *keyfile, int keyform, int key_type, + char *passargin, int pkey_op); + +static int setup_peer(BIO * err, EVP_PKEY_CTX * ctx, int peerform, + const char *file); + +static int do_keyop(EVP_PKEY_CTX * ctx, int pkey_op, + unsigned char *out, size_t * poutlen, + unsigned char *in, size_t inlen); + +int +pkeyutl_main(int argc, char **argv) +{ + BIO *in = NULL, *out = NULL; + char *infile = NULL, *outfile = NULL, *sigfile = NULL; + int pkey_op = EVP_PKEY_OP_SIGN, key_type = KEY_PRIVKEY; + int keyform = FORMAT_PEM, peerform = FORMAT_PEM; + char badarg = 0, rev = 0; + char hexdump = 0, asn1parse = 0; + EVP_PKEY_CTX *ctx = NULL; + char *passargin = NULL; + int keysize = -1; + + unsigned char *buf_in = NULL, *buf_out = NULL, *sig = NULL; + size_t buf_outlen; + int buf_inlen = 0, siglen = -1; + + int ret = 1, rv = -1; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + argc--; + argv++; + + while (argc >= 1) { + if (!strcmp(*argv, "-in")) { + if (--argc < 1) + badarg = 1; + else + infile = *(++argv); + } else if (!strcmp(*argv, "-out")) { + if (--argc < 1) + badarg = 1; + else + outfile = *(++argv); + } else if (!strcmp(*argv, "-sigfile")) { + if (--argc < 1) + badarg = 1; + else + sigfile = *(++argv); + } else if (!strcmp(*argv, "-inkey")) { + if (--argc < 1) + badarg = 1; + else { + ctx = init_ctx(&keysize, + *(++argv), keyform, key_type, + passargin, pkey_op); + if (!ctx) { + BIO_puts(bio_err, + "Error initializing context\n"); + ERR_print_errors(bio_err); + badarg = 1; + } + } + } else if (!strcmp(*argv, "-peerkey")) { + if (--argc < 1) + badarg = 1; + else if (!setup_peer(bio_err, ctx, peerform, *(++argv))) + badarg = 1; + } else if (!strcmp(*argv, "-passin")) { + if (--argc < 1) + badarg = 1; + else + passargin = *(++argv); + } else if (strcmp(*argv, "-peerform") == 0) { + if (--argc < 1) + badarg = 1; + else + peerform = str2fmt(*(++argv)); + } else if (strcmp(*argv, "-keyform") == 0) { + if (--argc < 1) + badarg = 1; + else + keyform = str2fmt(*(++argv)); + } + else if (!strcmp(*argv, "-pubin")) + key_type = KEY_PUBKEY; + else if (!strcmp(*argv, "-certin")) + key_type = KEY_CERT; + else if (!strcmp(*argv, "-asn1parse")) + asn1parse = 1; + else if (!strcmp(*argv, "-hexdump")) + hexdump = 1; + else if (!strcmp(*argv, "-sign")) + pkey_op = EVP_PKEY_OP_SIGN; + else if (!strcmp(*argv, "-verify")) + pkey_op = EVP_PKEY_OP_VERIFY; + else if (!strcmp(*argv, "-verifyrecover")) + pkey_op = EVP_PKEY_OP_VERIFYRECOVER; + else if (!strcmp(*argv, "-rev")) + rev = 1; + else if (!strcmp(*argv, "-encrypt")) + pkey_op = EVP_PKEY_OP_ENCRYPT; + else if (!strcmp(*argv, "-decrypt")) + pkey_op = EVP_PKEY_OP_DECRYPT; + else if (!strcmp(*argv, "-derive")) + pkey_op = EVP_PKEY_OP_DERIVE; + else if (strcmp(*argv, "-pkeyopt") == 0) { + if (--argc < 1) + badarg = 1; + else if (!ctx) { + BIO_puts(bio_err, + "-pkeyopt command before -inkey\n"); + badarg = 1; + } else if (pkey_ctrl_string(ctx, *(++argv)) <= 0) { + BIO_puts(bio_err, "parameter setting error\n"); + ERR_print_errors(bio_err); + goto end; + } + } else + badarg = 1; + if (badarg) { + usage(); + goto end; + } + argc--; + argv++; + } + + if (!ctx) { + usage(); + goto end; + } + if (sigfile && (pkey_op != EVP_PKEY_OP_VERIFY)) { + BIO_puts(bio_err, "Signature file specified for non verify\n"); + goto end; + } + if (!sigfile && (pkey_op == EVP_PKEY_OP_VERIFY)) { + BIO_puts(bio_err, "No signature file specified for verify\n"); + goto end; + } + + if (pkey_op != EVP_PKEY_OP_DERIVE) { + if (infile) { + if (!(in = BIO_new_file(infile, "rb"))) { + BIO_puts(bio_err, + "Error Opening Input File\n"); + ERR_print_errors(bio_err); + goto end; + } + } else + in = BIO_new_fp(stdin, BIO_NOCLOSE); + } + if (outfile) { + if (!(out = BIO_new_file(outfile, "wb"))) { + BIO_printf(bio_err, "Error Creating Output File\n"); + ERR_print_errors(bio_err); + goto end; + } + } else { + out = BIO_new_fp(stdout, BIO_NOCLOSE); + } + + if (sigfile) { + BIO *sigbio = BIO_new_file(sigfile, "rb"); + if (!sigbio) { + BIO_printf(bio_err, "Can't open signature file %s\n", + sigfile); + goto end; + } + siglen = bio_to_mem(&sig, keysize * 10, sigbio); + BIO_free(sigbio); + if (siglen <= 0) { + BIO_printf(bio_err, "Error reading signature data\n"); + goto end; + } + } + if (in) { + /* Read the input data */ + buf_inlen = bio_to_mem(&buf_in, keysize * 10, in); + if (buf_inlen <= 0) { + BIO_printf(bio_err, "Error reading input Data\n"); + exit(1); + } + if (rev) { + size_t i; + unsigned char ctmp; + size_t l = (size_t) buf_inlen; + for (i = 0; i < l / 2; i++) { + ctmp = buf_in[i]; + buf_in[i] = buf_in[l - 1 - i]; + buf_in[l - 1 - i] = ctmp; + } + } + } + if (pkey_op == EVP_PKEY_OP_VERIFY) { + rv = EVP_PKEY_verify(ctx, sig, (size_t) siglen, + buf_in, (size_t) buf_inlen); + if (rv == 1) { + BIO_puts(out, "Signature Verified Successfully\n"); + ret = 0; + } else + BIO_puts(out, "Signature Verification Failure\n"); + if (rv >= 0) + goto end; + } else { + rv = do_keyop(ctx, pkey_op, NULL, (size_t *)&buf_outlen, + buf_in, (size_t) buf_inlen); + if (rv > 0) { + buf_out = malloc(buf_outlen); + if (!buf_out) + rv = -1; + else + rv = do_keyop(ctx, pkey_op, + buf_out, (size_t *) & buf_outlen, + buf_in, (size_t) buf_inlen); + } + } + + if (rv <= 0) { + BIO_printf(bio_err, "Public Key operation error\n"); + ERR_print_errors(bio_err); + goto end; + } + ret = 0; + if (asn1parse) { + if (!ASN1_parse_dump(out, buf_out, buf_outlen, 1, -1)) + ERR_print_errors(bio_err); + } else if (hexdump) + BIO_dump(out, (char *) buf_out, buf_outlen); + else + BIO_write(out, buf_out, buf_outlen); + +end: + if (ctx) + EVP_PKEY_CTX_free(ctx); + BIO_free(in); + BIO_free_all(out); + free(buf_in); + free(buf_out); + free(sig); + + return ret; +} + +static void +usage() +{ + BIO_printf(bio_err, "Usage: pkeyutl [options]\n"); + BIO_printf(bio_err, "-in file input file\n"); + BIO_printf(bio_err, "-out file output file\n"); + BIO_printf(bio_err, "-sigfile file signature file (verify operation only)\n"); + BIO_printf(bio_err, "-inkey file input key\n"); + BIO_printf(bio_err, "-keyform arg private key format - default PEM\n"); + BIO_printf(bio_err, "-pubin input is a public key\n"); + BIO_printf(bio_err, "-certin input is a certificate carrying a public key\n"); + BIO_printf(bio_err, "-pkeyopt X:Y public key options\n"); + BIO_printf(bio_err, "-sign sign with private key\n"); + BIO_printf(bio_err, "-verify verify with public key\n"); + BIO_printf(bio_err, "-verifyrecover verify with public key, recover original data\n"); + BIO_printf(bio_err, "-encrypt encrypt with public key\n"); + BIO_printf(bio_err, "-decrypt decrypt with private key\n"); + BIO_printf(bio_err, "-derive derive shared secret\n"); + BIO_printf(bio_err, "-hexdump hex dump output\n"); + BIO_printf(bio_err, "-passin arg pass phrase source\n"); + +} + +static EVP_PKEY_CTX * +init_ctx(int *pkeysize, + char *keyfile, int keyform, int key_type, + char *passargin, int pkey_op) +{ + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *ctx = NULL; + char *passin = NULL; + int rv = -1; + X509 *x; + if (((pkey_op == EVP_PKEY_OP_SIGN) || (pkey_op == EVP_PKEY_OP_DECRYPT) + || (pkey_op == EVP_PKEY_OP_DERIVE)) + && (key_type != KEY_PRIVKEY)) { + BIO_printf(bio_err, "A private key is needed for this operation\n"); + goto end; + } + if (!app_passwd(bio_err, passargin, NULL, &passin, NULL)) { + BIO_printf(bio_err, "Error getting password\n"); + goto end; + } + switch (key_type) { + case KEY_PRIVKEY: + pkey = load_key(bio_err, keyfile, keyform, 0, + passin, "Private Key"); + break; + + case KEY_PUBKEY: + pkey = load_pubkey(bio_err, keyfile, keyform, 0, + NULL, "Public Key"); + break; + + case KEY_CERT: + x = load_cert(bio_err, keyfile, keyform, + NULL, "Certificate"); + if (x) { + pkey = X509_get_pubkey(x); + X509_free(x); + } + break; + + } + + *pkeysize = EVP_PKEY_size(pkey); + + if (!pkey) + goto end; + + ctx = EVP_PKEY_CTX_new(pkey, NULL); + + EVP_PKEY_free(pkey); + + if (!ctx) + goto end; + + switch (pkey_op) { + case EVP_PKEY_OP_SIGN: + rv = EVP_PKEY_sign_init(ctx); + break; + + case EVP_PKEY_OP_VERIFY: + rv = EVP_PKEY_verify_init(ctx); + break; + + case EVP_PKEY_OP_VERIFYRECOVER: + rv = EVP_PKEY_verify_recover_init(ctx); + break; + + case EVP_PKEY_OP_ENCRYPT: + rv = EVP_PKEY_encrypt_init(ctx); + break; + + case EVP_PKEY_OP_DECRYPT: + rv = EVP_PKEY_decrypt_init(ctx); + break; + + case EVP_PKEY_OP_DERIVE: + rv = EVP_PKEY_derive_init(ctx); + break; + } + + if (rv <= 0) { + EVP_PKEY_CTX_free(ctx); + ctx = NULL; + } +end: + + free(passin); + + return ctx; + + +} + +static int +setup_peer(BIO * err, EVP_PKEY_CTX * ctx, int peerform, + const char *file) +{ + EVP_PKEY *peer = NULL; + int ret; + if (!ctx) { + BIO_puts(err, "-peerkey command before -inkey\n"); + return 0; + } + peer = load_pubkey(bio_err, file, peerform, 0, NULL, "Peer Key"); + + if (!peer) { + BIO_printf(bio_err, "Error reading peer key %s\n", file); + ERR_print_errors(err); + return 0; + } + ret = EVP_PKEY_derive_set_peer(ctx, peer); + + EVP_PKEY_free(peer); + if (ret <= 0) + ERR_print_errors(err); + return ret; +} + +static int +do_keyop(EVP_PKEY_CTX * ctx, int pkey_op, + unsigned char *out, size_t * poutlen, + unsigned char *in, size_t inlen) +{ + int rv = 0; + switch (pkey_op) { + case EVP_PKEY_OP_VERIFYRECOVER: + rv = EVP_PKEY_verify_recover(ctx, out, poutlen, in, inlen); + break; + + case EVP_PKEY_OP_SIGN: + rv = EVP_PKEY_sign(ctx, out, poutlen, in, inlen); + break; + + case EVP_PKEY_OP_ENCRYPT: + rv = EVP_PKEY_encrypt(ctx, out, poutlen, in, inlen); + break; + + case EVP_PKEY_OP_DECRYPT: + rv = EVP_PKEY_decrypt(ctx, out, poutlen, in, inlen); + break; + + case EVP_PKEY_OP_DERIVE: + rv = EVP_PKEY_derive(ctx, out, poutlen); + break; + + } + return rv; +} diff --git a/bin/openssl/prime.c b/bin/openssl/prime.c new file mode 100644 index 0000000000..c9bf33bff9 --- /dev/null +++ b/bin/openssl/prime.c @@ -0,0 +1,199 @@ +/* $OpenBSD: prime.c,v 1.10 2015/10/17 15:00:11 doug Exp $ */ +/* ==================================================================== + * Copyright (c) 2004 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#include "apps.h" + +#include +#include + +struct { + int bits; + int checks; + int generate; + int hex; + int safe; +} prime_config; + +struct option prime_options[] = { + { + .name = "bits", + .argname = "n", + .desc = "Number of bits in the generated prime number", + .type = OPTION_ARG_INT, + .opt.value = &prime_config.bits, + }, + { + .name = "checks", + .argname = "n", + .desc = "Miller-Rabin probablistic primality test iterations", + .type = OPTION_ARG_INT, + .opt.value = &prime_config.checks, + }, + { + .name = "generate", + .desc = "Generate a pseudo-random prime number", + .type = OPTION_FLAG, + .opt.flag = &prime_config.generate, + }, + { + .name = "hex", + .desc = "Hexadecimal prime numbers", + .type = OPTION_FLAG, + .opt.flag = &prime_config.hex, + }, + { + .name = "safe", + .desc = "Generate only \"safe\" prime numbers", + .type = OPTION_FLAG, + .opt.flag = &prime_config.safe, + }, + {NULL}, +}; + +static void +prime_usage() +{ + fprintf(stderr, + "usage: prime [-bits n] [-checks n] [-generate] [-hex] [-safe] " + "p\n"); + options_usage(prime_options); +} + +int +prime_main(int argc, char **argv) +{ + BIGNUM *bn = NULL; + char *prime = NULL; + BIO *bio_out; + char *s; + int ret = 1; + + if (single_execution) { + if (pledge("stdio rpath", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + memset(&prime_config, 0, sizeof(prime_config)); + + /* Default iterations for Miller-Rabin probabilistic primality test. */ + prime_config.checks = 20; + + if (options_parse(argc, argv, prime_options, &prime, NULL) != 0) { + prime_usage(); + return (1); + } + + if (prime == NULL && prime_config.generate == 0) { + BIO_printf(bio_err, "No prime specified.\n"); + prime_usage(); + return (1); + } + + if ((bio_out = BIO_new(BIO_s_file())) == NULL) { + ERR_print_errors(bio_err); + return (1); + } + BIO_set_fp(bio_out, stdout, BIO_NOCLOSE); + + if (prime_config.generate != 0) { + if (prime_config.bits == 0) { + BIO_printf(bio_err, "Specify the number of bits.\n"); + goto end; + } + bn = BN_new(); + if (!bn) { + BIO_printf(bio_err, "Out of memory.\n"); + goto end; + } + if (!BN_generate_prime_ex(bn, prime_config.bits, + prime_config.safe, NULL, NULL, NULL)) { + BIO_printf(bio_err, "Prime generation error.\n"); + goto end; + } + s = prime_config.hex ? BN_bn2hex(bn) : BN_bn2dec(bn); + if (s == NULL) { + BIO_printf(bio_err, "Out of memory.\n"); + goto end; + } + BIO_printf(bio_out, "%s\n", s); + free(s); + } else { + if (prime_config.hex) { + if (!BN_hex2bn(&bn, prime)) { + BIO_printf(bio_err, "%s is an invalid hex " + "value.\n", prime); + goto end; + } + } else { + if (!BN_dec2bn(&bn, prime)) { + BIO_printf(bio_err, "%s is an invalid decimal " + "value.\n", prime); + goto end; + } + } + + BIO_printf(bio_out, "%s is %sprime\n", prime, + BN_is_prime_ex(bn, prime_config.checks, + NULL, NULL) ? "" : "not "); + } + + ret = 0; + +end: + BN_free(bn); + BIO_free_all(bio_out); + + return (ret); +} diff --git a/bin/openssl/progs.h b/bin/openssl/progs.h new file mode 100644 index 0000000000..1c11a35655 --- /dev/null +++ b/bin/openssl/progs.h @@ -0,0 +1,47 @@ +/* $OpenBSD: progs.h,v 1.8 2016/09/05 10:45:19 deraadt Exp $ */ +/* Public domain */ + +int asn1parse_main(int argc, char **argv); +int ca_main(int argc, char **argv); +int certhash_main(int argc, char **argv); +int ciphers_main(int argc, char **argv); +int crl2pkcs7_main(int argc, char **argv); +int crl_main(int argc, char **argv); +int dgst_main(int argc, char **argv); +int dh_main(int argc, char **argv); +int dhparam_main(int argc, char **argv); +int dsa_main(int argc, char **argv); +int dsaparam_main(int argc, char **argv); +int ec_main(int argc, char **argv); +int ecparam_main(int argc, char **argv); +int enc_main(int argc, char **argv); +int errstr_main(int argc, char **argv); +int gendh_main(int argc, char **argv); +int gendsa_main(int argc, char **argv); +int genpkey_main(int argc, char **argv); +int genrsa_main(int argc, char **argv); +int nseq_main(int argc, char **argv); +int ocsp_main(int argc, char **argv); +int passwd_main(int argc, char **argv); +int pkcs7_main(int argc, char **argv); +int pkcs8_main(int argc, char **argv); +int pkcs12_main(int argc, char **argv); +int pkey_main(int argc, char **argv); +int pkeyparam_main(int argc, char **argv); +int pkeyutl_main(int argc, char **argv); +int prime_main(int argc, char **argv); +int rand_main(int argc, char **argv); +int req_main(int argc, char **argv); +int rsa_main(int argc, char **argv); +int rsautl_main(int argc, char **argv); +int s_client_main(int argc, char **argv); +int s_server_main(int argc, char **argv); +int s_time_main(int argc, char **argv); +int sess_id_main(int argc, char **argv); +int smime_main(int argc, char **argv); +int speed_main(int argc, char **argv); +int spkac_main(int argc, char **argv); +int ts_main(int argc, char **argv); +int verify_main(int argc, char **argv); +int version_main(int argc, char **argv); +int x509_main(int argc, char **argv); diff --git a/bin/openssl/rand.c b/bin/openssl/rand.c new file mode 100644 index 0000000000..04105bc46e --- /dev/null +++ b/bin/openssl/rand.c @@ -0,0 +1,185 @@ +/* $OpenBSD: rand.c,v 1.11 2017/01/20 08:57:12 deraadt Exp $ */ +/* ==================================================================== + * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include +#include +#include + +#include "apps.h" + +#include +#include + +struct { + int base64; + int hex; + char *outfile; +} rand_config; + +struct option rand_options[] = { + { + .name = "base64", + .desc = "Perform base64 encoding on output", + .type = OPTION_FLAG, + .opt.flag = &rand_config.base64, + }, + { + .name = "hex", + .desc = "Hexadecimal output", + .type = OPTION_FLAG, + .opt.flag = &rand_config.hex, + }, + { + .name = "out", + .argname = "file", + .desc = "Write to the given file instead of standard output", + .type = OPTION_ARG, + .opt.arg = &rand_config.outfile, + }, + {NULL}, +}; + +static void +rand_usage() +{ + fprintf(stderr, + "usage: rand [-base64 | -hex] [-out file] num\n"); + options_usage(rand_options); +} + +int +rand_main(int argc, char **argv) +{ + char *num_bytes = NULL; + int ret = 1; + int badopt = 0; + int num = -1; + int i, r; + BIO *out = NULL; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + memset(&rand_config, 0, sizeof(rand_config)); + + if (options_parse(argc, argv, rand_options, &num_bytes, NULL) != 0) { + rand_usage(); + return (1); + } + + if (num_bytes != NULL) { + r = sscanf(num_bytes, "%d", &num); + if (r == 0 || num < 0) + badopt = 1; + } else + badopt = 1; + + if (rand_config.hex && rand_config.base64) + badopt = 1; + + if (badopt) { + rand_usage(); + goto err; + } + + out = BIO_new(BIO_s_file()); + if (out == NULL) + goto err; + if (rand_config.outfile != NULL) + r = BIO_write_filename(out, rand_config.outfile); + else + r = BIO_set_fp(out, stdout, BIO_NOCLOSE | BIO_FP_TEXT); + if (r <= 0) + goto err; + if (rand_config.base64) { + BIO *b64 = BIO_new(BIO_f_base64()); + if (b64 == NULL) + goto err; + out = BIO_push(b64, out); + } + + while (num > 0) { + unsigned char buf[4096]; + int chunk; + + chunk = num; + if (chunk > (int) sizeof(buf)) + chunk = sizeof(buf); + arc4random_buf(buf, chunk); + if (rand_config.hex) { + for (i = 0; i < chunk; i++) + BIO_printf(out, "%02x", buf[i]); + } else + BIO_write(out, buf, chunk); + num -= chunk; + } + + if (rand_config.hex) + BIO_puts(out, "\n"); + (void) BIO_flush(out); + + ret = 0; + +err: + ERR_print_errors(bio_err); + if (out) + BIO_free_all(out); + + return (ret); +} diff --git a/bin/openssl/req.c b/bin/openssl/req.c new file mode 100644 index 0000000000..352e38b226 --- /dev/null +++ b/bin/openssl/req.c @@ -0,0 +1,1560 @@ +/* $OpenBSD: req.c,v 1.14 2017/01/20 08:57:12 deraadt Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +/* Until the key-gen callbacks are modified to use newer prototypes, we allow + * deprecated functions for openssl-internal code */ +#ifdef OPENSSL_NO_DEPRECATED +#undef OPENSSL_NO_DEPRECATED +#endif + +#include +#include +#include +#include +#include + +#include "apps.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#define SECTION "req" + +#define BITS "default_bits" +#define KEYFILE "default_keyfile" +#define PROMPT "prompt" +#define DISTINGUISHED_NAME "distinguished_name" +#define ATTRIBUTES "attributes" +#define V3_EXTENSIONS "x509_extensions" +#define REQ_EXTENSIONS "req_extensions" +#define STRING_MASK "string_mask" +#define UTF8_IN "utf8" + +#define DEFAULT_KEY_LENGTH 2048 +#define MIN_KEY_LENGTH 384 + + +/* -inform arg - input format - default PEM (DER or PEM) + * -outform arg - output format - default PEM + * -in arg - input file - default stdin + * -out arg - output file - default stdout + * -verify - check request signature + * -noout - don't print stuff out. + * -text - print out human readable text. + * -nodes - no des encryption + * -config file - Load configuration file. + * -key file - make a request using key in file (or use it for verification). + * -keyform arg - key file format. + * -newkey - make a key and a request. + * -modulus - print RSA modulus. + * -pubkey - output Public Key. + * -x509 - output a self signed X509 structure instead. + * -asn1-kludge - output new certificate request in a format that some CA's + * require. This format is wrong + */ + +static int make_REQ(X509_REQ * req, EVP_PKEY * pkey, char *dn, int multirdn, + int attribs, unsigned long chtype); +static int build_subject(X509_REQ * req, char *subj, unsigned long chtype, + int multirdn); +static int prompt_info(X509_REQ * req, + STACK_OF(CONF_VALUE) * dn_sk, char *dn_sect, + STACK_OF(CONF_VALUE) * attr_sk, char *attr_sect, int attribs, + unsigned long chtype); +static int auto_info(X509_REQ * req, STACK_OF(CONF_VALUE) * sk, + STACK_OF(CONF_VALUE) * attr, int attribs, + unsigned long chtype); +static int add_attribute_object(X509_REQ * req, char *text, const char *def, + char *value, int nid, int n_min, + int n_max, unsigned long chtype); +static int add_DN_object(X509_NAME * n, char *text, const char *def, char *value, + int nid, int n_min, int n_max, unsigned long chtype, int mval); +static int genpkey_cb(EVP_PKEY_CTX * ctx); +static int req_check_len(int len, int n_min, int n_max); +static int check_end(const char *str, const char *end); +static EVP_PKEY_CTX *set_keygen_ctx(BIO * err, const char *gstr, int *pkey_type, + long *pkeylen, char **palgnam); +static CONF *req_conf = NULL; +static int batch = 0; + +int +req_main(int argc, char **argv) +{ + unsigned long nmflag = 0, reqflag = 0; + int ex = 1, x509 = 0, days = 30; + X509 *x509ss = NULL; + X509_REQ *req = NULL; + EVP_PKEY_CTX *genctx = NULL; + const char *keyalg = NULL; + char *keyalgstr = NULL; + STACK_OF(OPENSSL_STRING) * pkeyopts = NULL, *sigopts = NULL; + EVP_PKEY *pkey = NULL; + int i = 0, badops = 0, newreq = 0, verbose = 0, pkey_type = -1; + long newkey = -1; + BIO *in = NULL, *out = NULL; + int informat, outformat, verify = 0, noout = 0, text = 0, keyform = FORMAT_PEM; + int nodes = 0, kludge = 0, newhdr = 0, subject = 0, pubkey = 0; + char *infile, *outfile, *prog, *keyfile = NULL, *template = NULL, + *keyout = NULL; + char *extensions = NULL; + char *req_exts = NULL; + const EVP_CIPHER *cipher = NULL; + ASN1_INTEGER *serial = NULL; + int modulus = 0; + char *passargin = NULL, *passargout = NULL; + char *passin = NULL, *passout = NULL; + char *p; + char *subj = NULL; + int multirdn = 0; + const EVP_MD *md_alg = NULL, *digest = NULL; + unsigned long chtype = MBSTRING_ASC; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + req_conf = NULL; + cipher = EVP_aes_256_cbc(); + digest = EVP_sha256(); + + infile = NULL; + outfile = NULL; + informat = FORMAT_PEM; + outformat = FORMAT_PEM; + + prog = argv[0]; + argc--; + argv++; + while (argc >= 1) { + if (strcmp(*argv, "-inform") == 0) { + if (--argc < 1) + goto bad; + informat = str2fmt(*(++argv)); + } else if (strcmp(*argv, "-outform") == 0) { + if (--argc < 1) + goto bad; + outformat = str2fmt(*(++argv)); + } + else if (strcmp(*argv, "-key") == 0) { + if (--argc < 1) + goto bad; + keyfile = *(++argv); + } else if (strcmp(*argv, "-pubkey") == 0) { + pubkey = 1; + } else if (strcmp(*argv, "-new") == 0) { + newreq = 1; + } else if (strcmp(*argv, "-config") == 0) { + if (--argc < 1) + goto bad; + template = *(++argv); + } else if (strcmp(*argv, "-keyform") == 0) { + if (--argc < 1) + goto bad; + keyform = str2fmt(*(++argv)); + } else if (strcmp(*argv, "-in") == 0) { + if (--argc < 1) + goto bad; + infile = *(++argv); + } else if (strcmp(*argv, "-out") == 0) { + if (--argc < 1) + goto bad; + outfile = *(++argv); + } else if (strcmp(*argv, "-keyout") == 0) { + if (--argc < 1) + goto bad; + keyout = *(++argv); + } else if (strcmp(*argv, "-passin") == 0) { + if (--argc < 1) + goto bad; + passargin = *(++argv); + } else if (strcmp(*argv, "-passout") == 0) { + if (--argc < 1) + goto bad; + passargout = *(++argv); + } else if (strcmp(*argv, "-newkey") == 0) { + if (--argc < 1) + goto bad; + keyalg = *(++argv); + newreq = 1; + } else if (strcmp(*argv, "-pkeyopt") == 0) { + if (--argc < 1) + goto bad; + if (!pkeyopts) + pkeyopts = sk_OPENSSL_STRING_new_null(); + if (!pkeyopts || !sk_OPENSSL_STRING_push(pkeyopts, *(++argv))) + goto bad; + } else if (strcmp(*argv, "-sigopt") == 0) { + if (--argc < 1) + goto bad; + if (!sigopts) + sigopts = sk_OPENSSL_STRING_new_null(); + if (!sigopts || !sk_OPENSSL_STRING_push(sigopts, *(++argv))) + goto bad; + } else if (strcmp(*argv, "-batch") == 0) + batch = 1; + else if (strcmp(*argv, "-newhdr") == 0) + newhdr = 1; + else if (strcmp(*argv, "-modulus") == 0) + modulus = 1; + else if (strcmp(*argv, "-verify") == 0) + verify = 1; + else if (strcmp(*argv, "-nodes") == 0) + nodes = 1; + else if (strcmp(*argv, "-noout") == 0) + noout = 1; + else if (strcmp(*argv, "-verbose") == 0) + verbose = 1; + else if (strcmp(*argv, "-utf8") == 0) + chtype = MBSTRING_UTF8; + else if (strcmp(*argv, "-nameopt") == 0) { + if (--argc < 1) + goto bad; + if (!set_name_ex(&nmflag, *(++argv))) + goto bad; + } else if (strcmp(*argv, "-reqopt") == 0) { + if (--argc < 1) + goto bad; + if (!set_cert_ex(&reqflag, *(++argv))) + goto bad; + } else if (strcmp(*argv, "-subject") == 0) + subject = 1; + else if (strcmp(*argv, "-text") == 0) + text = 1; + else if (strcmp(*argv, "-x509") == 0) + x509 = 1; + else if (strcmp(*argv, "-asn1-kludge") == 0) + kludge = 1; + else if (strcmp(*argv, "-no-asn1-kludge") == 0) + kludge = 0; + else if (strcmp(*argv, "-subj") == 0) { + if (--argc < 1) + goto bad; + subj = *(++argv); + } else if (strcmp(*argv, "-multivalue-rdn") == 0) + multirdn = 1; + else if (strcmp(*argv, "-days") == 0) { + const char *errstr; + + if (--argc < 1) + goto bad; + days = strtonum(*(++argv), 1, INT_MAX, &errstr); + if (errstr) { + BIO_printf(bio_err, "bad -days %s, using 0: %s\n", + *argv, errstr); + days = 30; + } + } else if (strcmp(*argv, "-set_serial") == 0) { + if (--argc < 1) + goto bad; + serial = s2i_ASN1_INTEGER(NULL, *(++argv)); + if (!serial) + goto bad; + } else if (strcmp(*argv, "-extensions") == 0) { + if (--argc < 1) + goto bad; + extensions = *(++argv); + } else if (strcmp(*argv, "-reqexts") == 0) { + if (--argc < 1) + goto bad; + req_exts = *(++argv); + } else if ((md_alg = EVP_get_digestbyname(&((*argv)[1]))) != NULL) { + /* ok */ + digest = md_alg; + } else { + BIO_printf(bio_err, "unknown option %s\n", *argv); + badops = 1; + break; + } + argc--; + argv++; + } + + if (badops) { +bad: + BIO_printf(bio_err, "%s [options] outfile\n", prog); + BIO_printf(bio_err, "where options are\n"); + BIO_printf(bio_err, " -inform arg input format - DER or PEM\n"); + BIO_printf(bio_err, " -outform arg output format - DER or PEM\n"); + BIO_printf(bio_err, " -in arg input file\n"); + BIO_printf(bio_err, " -out arg output file\n"); + BIO_printf(bio_err, " -text text form of request\n"); + BIO_printf(bio_err, " -pubkey output public key\n"); + BIO_printf(bio_err, " -noout do not output REQ\n"); + BIO_printf(bio_err, " -verify verify signature on REQ\n"); + BIO_printf(bio_err, " -modulus RSA modulus\n"); + BIO_printf(bio_err, " -nodes don't encrypt the output key\n"); + BIO_printf(bio_err, " -subject output the request's subject\n"); + BIO_printf(bio_err, " -passin private key password source\n"); + BIO_printf(bio_err, " -key file use the private key contained in file\n"); + BIO_printf(bio_err, " -keyform arg key file format\n"); + BIO_printf(bio_err, " -keyout arg file to send the key to\n"); + BIO_printf(bio_err, " -newkey rsa:bits generate a new RSA key of 'bits' in size\n"); + BIO_printf(bio_err, " -newkey dsa:file generate a new DSA key, parameters taken from CA in 'file'\n"); + BIO_printf(bio_err, " -newkey ec:file generate a new EC key, parameters taken from CA in 'file'\n"); + BIO_printf(bio_err, " -[digest] Digest to sign with (md5, sha1, md4)\n"); + BIO_printf(bio_err, " -config file request template file.\n"); + BIO_printf(bio_err, " -subj arg set or modify request subject\n"); + BIO_printf(bio_err, " -multivalue-rdn enable support for multivalued RDNs\n"); + BIO_printf(bio_err, " -new new request.\n"); + BIO_printf(bio_err, " -batch do not ask anything during request generation\n"); + BIO_printf(bio_err, " -x509 output a x509 structure instead of a cert. req.\n"); + BIO_printf(bio_err, " -days number of days a certificate generated by -x509 is valid for.\n"); + BIO_printf(bio_err, " -set_serial serial number to use for a certificate generated by -x509.\n"); + BIO_printf(bio_err, " -newhdr output \"NEW\" in the header lines\n"); + BIO_printf(bio_err, " -asn1-kludge Output the 'request' in a format that is wrong but some CA's\n"); + BIO_printf(bio_err, " have been reported as requiring\n"); + BIO_printf(bio_err, " -extensions .. specify certificate extension section (override value in config file)\n"); + BIO_printf(bio_err, " -reqexts .. specify request extension section (override value in config file)\n"); + BIO_printf(bio_err, " -utf8 input characters are UTF8 (default ASCII)\n"); + BIO_printf(bio_err, " -nameopt arg - various certificate name options\n"); + BIO_printf(bio_err, " -reqopt arg - various request text options\n\n"); + goto end; + } + + if (!app_passwd(bio_err, passargin, passargout, &passin, &passout)) { + BIO_printf(bio_err, "Error getting passwords\n"); + goto end; + } + if (template != NULL) { + long errline = -1; + + if (verbose) + BIO_printf(bio_err, "Using configuration from %s\n", template); + req_conf = NCONF_new(NULL); + i = NCONF_load(req_conf, template, &errline); + if (i == 0) { + BIO_printf(bio_err, "error on line %ld of %s\n", errline, template); + goto end; + } + } else { + req_conf = config; + + if (req_conf == NULL) { + BIO_printf(bio_err, "Unable to load config info from %s\n", default_config_file); + if (newreq) + goto end; + } else if (verbose) + BIO_printf(bio_err, "Using configuration from %s\n", + default_config_file); + } + + if (req_conf != NULL) { + if (!load_config(bio_err, req_conf)) + goto end; + p = NCONF_get_string(req_conf, NULL, "oid_file"); + if (p == NULL) + ERR_clear_error(); + if (p != NULL) { + BIO *oid_bio; + + oid_bio = BIO_new_file(p, "r"); + if (oid_bio == NULL) { + /* + BIO_printf(bio_err,"problems opening %s for extra oid's\n",p); + ERR_print_errors(bio_err); + */ + } else { + OBJ_create_objects(oid_bio); + BIO_free(oid_bio); + } + } + } + if (!add_oid_section(bio_err, req_conf)) + goto end; + + if (md_alg == NULL) { + p = NCONF_get_string(req_conf, SECTION, "default_md"); + if (p == NULL) + ERR_clear_error(); + if (p != NULL) { + if ((md_alg = EVP_get_digestbyname(p)) != NULL) + digest = md_alg; + } + } + if (!extensions) { + extensions = NCONF_get_string(req_conf, SECTION, V3_EXTENSIONS); + if (!extensions) + ERR_clear_error(); + } + if (extensions) { + /* Check syntax of file */ + X509V3_CTX ctx; + X509V3_set_ctx_test(&ctx); + X509V3_set_nconf(&ctx, req_conf); + if (!X509V3_EXT_add_nconf(req_conf, &ctx, extensions, NULL)) { + BIO_printf(bio_err, + "Error Loading extension section %s\n", extensions); + goto end; + } + } + if (!passin) { + passin = NCONF_get_string(req_conf, SECTION, "input_password"); + if (!passin) + ERR_clear_error(); + } + if (!passout) { + passout = NCONF_get_string(req_conf, SECTION, "output_password"); + if (!passout) + ERR_clear_error(); + } + p = NCONF_get_string(req_conf, SECTION, STRING_MASK); + if (!p) + ERR_clear_error(); + + if (p && !ASN1_STRING_set_default_mask_asc(p)) { + BIO_printf(bio_err, "Invalid global string mask setting %s\n", p); + goto end; + } + if (chtype != MBSTRING_UTF8) { + p = NCONF_get_string(req_conf, SECTION, UTF8_IN); + if (!p) + ERR_clear_error(); + else if (!strcmp(p, "yes")) + chtype = MBSTRING_UTF8; + } + if (!req_exts) { + req_exts = NCONF_get_string(req_conf, SECTION, REQ_EXTENSIONS); + if (!req_exts) + ERR_clear_error(); + } + if (req_exts) { + /* Check syntax of file */ + X509V3_CTX ctx; + X509V3_set_ctx_test(&ctx); + X509V3_set_nconf(&ctx, req_conf); + if (!X509V3_EXT_add_nconf(req_conf, &ctx, req_exts, NULL)) { + BIO_printf(bio_err, + "Error Loading request extension section %s\n", + req_exts); + goto end; + } + } + in = BIO_new(BIO_s_file()); + out = BIO_new(BIO_s_file()); + if ((in == NULL) || (out == NULL)) + goto end; + + if (keyfile != NULL) { + pkey = load_key(bio_err, keyfile, keyform, 0, passin, + "Private Key"); + if (!pkey) { + /* + * load_key() has already printed an appropriate + * message + */ + goto end; + } + } + if (newreq && (pkey == NULL)) { + if (!NCONF_get_number(req_conf, SECTION, BITS, &newkey)) { + newkey = DEFAULT_KEY_LENGTH; + } + if (keyalg) { + genctx = set_keygen_ctx(bio_err, keyalg, &pkey_type, &newkey, + &keyalgstr); + if (!genctx) + goto end; + } + if (newkey < MIN_KEY_LENGTH && (pkey_type == EVP_PKEY_RSA || pkey_type == EVP_PKEY_DSA)) { + BIO_printf(bio_err, "private key length is too short,\n"); + BIO_printf(bio_err, "it needs to be at least %d bits, not %ld\n", MIN_KEY_LENGTH, newkey); + goto end; + } + if (!genctx) { + genctx = set_keygen_ctx(bio_err, NULL, &pkey_type, &newkey, + &keyalgstr); + if (!genctx) + goto end; + } + if (pkeyopts) { + char *genopt; + for (i = 0; i < sk_OPENSSL_STRING_num(pkeyopts); i++) { + genopt = sk_OPENSSL_STRING_value(pkeyopts, i); + if (pkey_ctrl_string(genctx, genopt) <= 0) { + BIO_printf(bio_err, + "parameter error \"%s\"\n", + genopt); + ERR_print_errors(bio_err); + goto end; + } + } + } + BIO_printf(bio_err, "Generating a %ld bit %s private key\n", + newkey, keyalgstr); + + EVP_PKEY_CTX_set_cb(genctx, genpkey_cb); + EVP_PKEY_CTX_set_app_data(genctx, bio_err); + + if (EVP_PKEY_keygen(genctx, &pkey) <= 0) { + BIO_puts(bio_err, "Error Generating Key\n"); + goto end; + } + EVP_PKEY_CTX_free(genctx); + genctx = NULL; + + if (keyout == NULL) { + keyout = NCONF_get_string(req_conf, SECTION, KEYFILE); + if (keyout == NULL) + ERR_clear_error(); + } + if (keyout == NULL) { + BIO_printf(bio_err, "writing new private key to stdout\n"); + BIO_set_fp(out, stdout, BIO_NOCLOSE); + } else { + BIO_printf(bio_err, "writing new private key to '%s'\n", keyout); + if (BIO_write_filename(out, keyout) <= 0) { + perror(keyout); + goto end; + } + } + + p = NCONF_get_string(req_conf, SECTION, "encrypt_rsa_key"); + if (p == NULL) { + ERR_clear_error(); + p = NCONF_get_string(req_conf, SECTION, "encrypt_key"); + if (p == NULL) + ERR_clear_error(); + } + if ((p != NULL) && (strcmp(p, "no") == 0)) + cipher = NULL; + if (nodes) + cipher = NULL; + + i = 0; +loop: + if (!PEM_write_bio_PrivateKey(out, pkey, cipher, + NULL, 0, NULL, passout)) { + if ((ERR_GET_REASON(ERR_peek_error()) == + PEM_R_PROBLEMS_GETTING_PASSWORD) && (i < 3)) { + ERR_clear_error(); + i++; + goto loop; + } + goto end; + } + BIO_printf(bio_err, "-----\n"); + } + if (!newreq) { + /* + * Since we are using a pre-existing certificate request, the + * kludge 'format' info should not be changed. + */ + kludge = -1; + if (infile == NULL) + BIO_set_fp(in, stdin, BIO_NOCLOSE); + else { + if (BIO_read_filename(in, infile) <= 0) { + perror(infile); + goto end; + } + } + + if (informat == FORMAT_ASN1) + req = d2i_X509_REQ_bio(in, NULL); + else if (informat == FORMAT_PEM) + req = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL); + else { + BIO_printf(bio_err, "bad input format specified for X509 request\n"); + goto end; + } + if (req == NULL) { + BIO_printf(bio_err, "unable to load X509 request\n"); + goto end; + } + } + if (newreq || x509) { + if (pkey == NULL) { + BIO_printf(bio_err, "you need to specify a private key\n"); + goto end; + } + if (req == NULL) { + req = X509_REQ_new(); + if (req == NULL) { + goto end; + } + i = make_REQ(req, pkey, subj, multirdn, !x509, chtype); + subj = NULL; /* done processing '-subj' option */ + if ((kludge > 0) && !sk_X509_ATTRIBUTE_num(req->req_info->attributes)) { + sk_X509_ATTRIBUTE_free(req->req_info->attributes); + req->req_info->attributes = NULL; + } + if (!i) { + BIO_printf(bio_err, "problems making Certificate Request\n"); + goto end; + } + } + if (x509) { + EVP_PKEY *tmppkey; + X509V3_CTX ext_ctx; + if ((x509ss = X509_new()) == NULL) + goto end; + + /* Set version to V3 */ + if (extensions && !X509_set_version(x509ss, 2)) + goto end; + if (serial) { + if (!X509_set_serialNumber(x509ss, serial)) + goto end; + } else { + if (!rand_serial(NULL, + X509_get_serialNumber(x509ss))) + goto end; + } + + if (!X509_set_issuer_name(x509ss, X509_REQ_get_subject_name(req))) + goto end; + if (!X509_gmtime_adj(X509_get_notBefore(x509ss), 0)) + goto end; + if (!X509_time_adj_ex(X509_get_notAfter(x509ss), days, 0, NULL)) + goto end; + if (!X509_set_subject_name(x509ss, X509_REQ_get_subject_name(req))) + goto end; + tmppkey = X509_REQ_get_pubkey(req); + if (!tmppkey || !X509_set_pubkey(x509ss, tmppkey)) + goto end; + EVP_PKEY_free(tmppkey); + + /* Set up V3 context struct */ + + X509V3_set_ctx(&ext_ctx, x509ss, x509ss, NULL, NULL, 0); + X509V3_set_nconf(&ext_ctx, req_conf); + + /* Add extensions */ + if (extensions && !X509V3_EXT_add_nconf(req_conf, + &ext_ctx, extensions, x509ss)) { + BIO_printf(bio_err, + "Error Loading extension section %s\n", + extensions); + goto end; + } + i = do_X509_sign(bio_err, x509ss, pkey, digest, sigopts); + if (!i) { + ERR_print_errors(bio_err); + goto end; + } + } else { + X509V3_CTX ext_ctx; + + /* Set up V3 context struct */ + + X509V3_set_ctx(&ext_ctx, NULL, NULL, req, NULL, 0); + X509V3_set_nconf(&ext_ctx, req_conf); + + /* Add extensions */ + if (req_exts && !X509V3_EXT_REQ_add_nconf(req_conf, + &ext_ctx, req_exts, req)) { + BIO_printf(bio_err, + "Error Loading extension section %s\n", + req_exts); + goto end; + } + i = do_X509_REQ_sign(bio_err, req, pkey, digest, sigopts); + if (!i) { + ERR_print_errors(bio_err); + goto end; + } + } + } + if (subj && x509) { + BIO_printf(bio_err, "Cannot modifiy certificate subject\n"); + goto end; + } + if (subj && !x509) { + if (verbose) { + BIO_printf(bio_err, "Modifying Request's Subject\n"); + print_name(bio_err, "old subject=", X509_REQ_get_subject_name(req), nmflag); + } + if (build_subject(req, subj, chtype, multirdn) == 0) { + BIO_printf(bio_err, "ERROR: cannot modify subject\n"); + ex = 1; + goto end; + } + req->req_info->enc.modified = 1; + + if (verbose) { + print_name(bio_err, "new subject=", X509_REQ_get_subject_name(req), nmflag); + } + } + if (verify && !x509) { + int tmp = 0; + + if (pkey == NULL) { + pkey = X509_REQ_get_pubkey(req); + tmp = 1; + if (pkey == NULL) + goto end; + } + i = X509_REQ_verify(req, pkey); + if (tmp) { + EVP_PKEY_free(pkey); + pkey = NULL; + } + if (i < 0) { + goto end; + } else if (i == 0) { + BIO_printf(bio_err, "verify failure\n"); + ERR_print_errors(bio_err); + } else /* if (i > 0) */ + BIO_printf(bio_err, "verify OK\n"); + } + if (noout && !text && !modulus && !subject && !pubkey) { + ex = 0; + goto end; + } + if (outfile == NULL) { + BIO_set_fp(out, stdout, BIO_NOCLOSE); + } else { + if ((keyout != NULL) && (strcmp(outfile, keyout) == 0)) + i = (int) BIO_append_filename(out, outfile); + else + i = (int) BIO_write_filename(out, outfile); + if (!i) { + perror(outfile); + goto end; + } + } + + if (pubkey) { + EVP_PKEY *tpubkey; + tpubkey = X509_REQ_get_pubkey(req); + if (tpubkey == NULL) { + BIO_printf(bio_err, "Error getting public key\n"); + ERR_print_errors(bio_err); + goto end; + } + PEM_write_bio_PUBKEY(out, tpubkey); + EVP_PKEY_free(tpubkey); + } + if (text) { + if (x509) + X509_print_ex(out, x509ss, nmflag, reqflag); + else + X509_REQ_print_ex(out, req, nmflag, reqflag); + } + if (subject) { + if (x509) + print_name(out, "subject=", X509_get_subject_name(x509ss), nmflag); + else + print_name(out, "subject=", X509_REQ_get_subject_name(req), nmflag); + } + if (modulus) { + EVP_PKEY *tpubkey; + + if (x509) + tpubkey = X509_get_pubkey(x509ss); + else + tpubkey = X509_REQ_get_pubkey(req); + if (tpubkey == NULL) { + fprintf(stdout, "Modulus=unavailable\n"); + goto end; + } + fprintf(stdout, "Modulus="); + if (EVP_PKEY_base_id(tpubkey) == EVP_PKEY_RSA) + BN_print(out, tpubkey->pkey.rsa->n); + else + fprintf(stdout, "Wrong Algorithm type"); + EVP_PKEY_free(tpubkey); + fprintf(stdout, "\n"); + } + if (!noout && !x509) { + if (outformat == FORMAT_ASN1) + i = i2d_X509_REQ_bio(out, req); + else if (outformat == FORMAT_PEM) { + if (newhdr) + i = PEM_write_bio_X509_REQ_NEW(out, req); + else + i = PEM_write_bio_X509_REQ(out, req); + } else { + BIO_printf(bio_err, "bad output format specified for outfile\n"); + goto end; + } + if (!i) { + BIO_printf(bio_err, "unable to write X509 request\n"); + goto end; + } + } + if (!noout && x509 && (x509ss != NULL)) { + if (outformat == FORMAT_ASN1) + i = i2d_X509_bio(out, x509ss); + else if (outformat == FORMAT_PEM) + i = PEM_write_bio_X509(out, x509ss); + else { + BIO_printf(bio_err, "bad output format specified for outfile\n"); + goto end; + } + if (!i) { + BIO_printf(bio_err, "unable to write X509 certificate\n"); + goto end; + } + } + ex = 0; +end: + if (ex) { + ERR_print_errors(bio_err); + } + if ((req_conf != NULL) && (req_conf != config)) + NCONF_free(req_conf); + BIO_free(in); + BIO_free_all(out); + EVP_PKEY_free(pkey); + if (genctx) + EVP_PKEY_CTX_free(genctx); + if (pkeyopts) + sk_OPENSSL_STRING_free(pkeyopts); + if (sigopts) + sk_OPENSSL_STRING_free(sigopts); + free(keyalgstr); + X509_REQ_free(req); + X509_free(x509ss); + ASN1_INTEGER_free(serial); + if (passargin && passin) + free(passin); + if (passargout && passout) + free(passout); + OBJ_cleanup(); + + return (ex); +} + +static int +make_REQ(X509_REQ * req, EVP_PKEY * pkey, char *subj, int multirdn, + int attribs, unsigned long chtype) +{ + int ret = 0, i; + char no_prompt = 0; + STACK_OF(CONF_VALUE) * dn_sk, *attr_sk = NULL; + char *tmp, *dn_sect, *attr_sect; + + tmp = NCONF_get_string(req_conf, SECTION, PROMPT); + if (tmp == NULL) + ERR_clear_error(); + if ((tmp != NULL) && !strcmp(tmp, "no")) + no_prompt = 1; + + dn_sect = NCONF_get_string(req_conf, SECTION, DISTINGUISHED_NAME); + if (dn_sect == NULL) { + BIO_printf(bio_err, "unable to find '%s' in config\n", + DISTINGUISHED_NAME); + goto err; + } + dn_sk = NCONF_get_section(req_conf, dn_sect); + if (dn_sk == NULL) { + BIO_printf(bio_err, "unable to get '%s' section\n", dn_sect); + goto err; + } + attr_sect = NCONF_get_string(req_conf, SECTION, ATTRIBUTES); + if (attr_sect == NULL) { + ERR_clear_error(); + attr_sk = NULL; + } else { + attr_sk = NCONF_get_section(req_conf, attr_sect); + if (attr_sk == NULL) { + BIO_printf(bio_err, "unable to get '%s' section\n", attr_sect); + goto err; + } + } + + /* setup version number */ + if (!X509_REQ_set_version(req, 0L)) + goto err; /* version 1 */ + + if (no_prompt) + i = auto_info(req, dn_sk, attr_sk, attribs, chtype); + else { + if (subj) + i = build_subject(req, subj, chtype, multirdn); + else + i = prompt_info(req, dn_sk, dn_sect, attr_sk, attr_sect, attribs, chtype); + } + if (!i) + goto err; + + if (!X509_REQ_set_pubkey(req, pkey)) + goto err; + + ret = 1; +err: + return (ret); +} + +/* + * subject is expected to be in the format /type0=value0/type1=value1/type2=... + * where characters may be escaped by \ + */ +static int +build_subject(X509_REQ * req, char *subject, unsigned long chtype, int multirdn) +{ + X509_NAME *n; + + if (!(n = parse_name(subject, chtype, multirdn))) + return 0; + + if (!X509_REQ_set_subject_name(req, n)) { + X509_NAME_free(n); + return 0; + } + X509_NAME_free(n); + return 1; +} + + +static int +prompt_info(X509_REQ * req, + STACK_OF(CONF_VALUE) * dn_sk, char *dn_sect, + STACK_OF(CONF_VALUE) * attr_sk, char *attr_sect, int attribs, + unsigned long chtype) +{ + int i; + char *p, *q; + char buf[100]; + int nid, mval; + long n_min, n_max; + char *type, *value; + const char *def; + CONF_VALUE *v; + X509_NAME *subj; + subj = X509_REQ_get_subject_name(req); + + if (!batch) { + BIO_printf(bio_err, "You are about to be asked to enter information that will be incorporated\n"); + BIO_printf(bio_err, "into your certificate request.\n"); + BIO_printf(bio_err, "What you are about to enter is what is called a Distinguished Name or a DN.\n"); + BIO_printf(bio_err, "There are quite a few fields but you can leave some blank\n"); + BIO_printf(bio_err, "For some fields there will be a default value,\n"); + BIO_printf(bio_err, "If you enter '.', the field will be left blank.\n"); + BIO_printf(bio_err, "-----\n"); + } + if (sk_CONF_VALUE_num(dn_sk)) { + i = -1; +start: for (;;) { + int ret; + i++; + if (sk_CONF_VALUE_num(dn_sk) <= i) + break; + + v = sk_CONF_VALUE_value(dn_sk, i); + p = q = NULL; + type = v->name; + if (!check_end(type, "_min") || !check_end(type, "_max") || + !check_end(type, "_default") || + !check_end(type, "_value")) + continue; + /* + * Skip past any leading X. X: X, etc to allow for + * multiple instances + */ + for (p = v->name; *p; p++) + if ((*p == ':') || (*p == ',') || + (*p == '.')) { + p++; + if (*p) + type = p; + break; + } + if (*type == '+') { + mval = -1; + type++; + } else + mval = 0; + /* If OBJ not recognised ignore it */ + if ((nid = OBJ_txt2nid(type)) == NID_undef) + goto start; + ret = snprintf(buf, sizeof buf, "%s_default", v->name); + if (ret == -1 || ret >= sizeof(buf)) { + BIO_printf(bio_err, "Name '%s' too long for default\n", + v->name); + return 0; + } + if ((def = NCONF_get_string(req_conf, dn_sect, buf)) == NULL) { + ERR_clear_error(); + def = ""; + } + ret = snprintf(buf, sizeof buf, "%s_value", v->name); + if (ret == -1 || ret >= sizeof(buf)) { + BIO_printf(bio_err, "Name '%s' too long for value\n", + v->name); + return 0; + } + if ((value = NCONF_get_string(req_conf, dn_sect, buf)) == NULL) { + ERR_clear_error(); + value = NULL; + } + ret = snprintf(buf, sizeof buf, "%s_min", v->name); + if (ret == -1 || ret >= sizeof(buf)) { + BIO_printf(bio_err, "Name '%s' too long for min\n", + v->name); + return 0; + } + if (!NCONF_get_number(req_conf, dn_sect, buf, &n_min)) { + ERR_clear_error(); + n_min = -1; + } + ret = snprintf(buf, sizeof buf, "%s_max", v->name); + if (ret == -1 || ret >= sizeof(buf)) { + BIO_printf(bio_err, "Name '%s' too long for max\n", + v->name); + return 0; + } + if (!NCONF_get_number(req_conf, dn_sect, buf, &n_max)) { + ERR_clear_error(); + n_max = -1; + } + if (!add_DN_object(subj, v->value, def, value, nid, + n_min, n_max, chtype, mval)) + return 0; + } + if (X509_NAME_entry_count(subj) == 0) { + BIO_printf(bio_err, "error, no objects specified in config file\n"); + return 0; + } + if (attribs) { + if ((attr_sk != NULL) && (sk_CONF_VALUE_num(attr_sk) > 0) && + (!batch)) { + BIO_printf(bio_err, + "\nPlease enter the following 'extra' attributes\n"); + BIO_printf(bio_err, + "to be sent with your certificate request\n"); + } + i = -1; +start2: for (;;) { + int ret; + i++; + if ((attr_sk == NULL) || + (sk_CONF_VALUE_num(attr_sk) <= i)) + break; + + v = sk_CONF_VALUE_value(attr_sk, i); + type = v->name; + if ((nid = OBJ_txt2nid(type)) == NID_undef) + goto start2; + ret = snprintf(buf, sizeof buf, "%s_default", type); + if (ret == -1 || ret >= sizeof(buf)) { + BIO_printf(bio_err, "Name '%s' too long for default\n", + v->name); + return 0; + } + if ((def = NCONF_get_string(req_conf, attr_sect, buf)) + == NULL) { + ERR_clear_error(); + def = ""; + } + ret = snprintf(buf, sizeof buf, "%s_value", type); + if (ret == -1 || ret >= sizeof(buf)) { + BIO_printf(bio_err, "Name '%s' too long for value\n", + v->name); + return 0; + } + if ((value = NCONF_get_string(req_conf, attr_sect, buf)) + == NULL) { + ERR_clear_error(); + value = NULL; + } + ret = snprintf(buf, sizeof buf, "%s_min", type); + if (ret == -1 || ret >= sizeof(buf)) { + BIO_printf(bio_err, "Name '%s' too long for min\n", + v->name); + return 0; + } + if (!NCONF_get_number(req_conf, attr_sect, buf, &n_min)) { + ERR_clear_error(); + n_min = -1; + } + ret = snprintf(buf, sizeof buf, "%s_max", type); + if (ret == -1 || ret >= sizeof(buf)) { + BIO_printf(bio_err, "Name '%s' too long for max\n", + v->name); + return 0; + } + if (!NCONF_get_number(req_conf, attr_sect, buf, &n_max)) { + ERR_clear_error(); + n_max = -1; + } + if (!add_attribute_object(req, + v->value, def, value, nid, n_min, n_max, chtype)) + return 0; + } + } + } else { + BIO_printf(bio_err, "No template, please set one up.\n"); + return 0; + } + + return 1; + +} + +static int +auto_info(X509_REQ * req, STACK_OF(CONF_VALUE) * dn_sk, + STACK_OF(CONF_VALUE) * attr_sk, int attribs, unsigned long chtype) +{ + int i; + char *p, *q; + char *type; + CONF_VALUE *v; + X509_NAME *subj; + + subj = X509_REQ_get_subject_name(req); + + for (i = 0; i < sk_CONF_VALUE_num(dn_sk); i++) { + int mval; + v = sk_CONF_VALUE_value(dn_sk, i); + p = q = NULL; + type = v->name; + /* + * Skip past any leading X. X: X, etc to allow for multiple + * instances + */ + for (p = v->name; *p; p++) + if ((*p == ':') || (*p == ',') || (*p == '.')) { + p++; + if (*p) + type = p; + break; + } + if (*p == '+') { + p++; + mval = -1; + } else + mval = 0; + if (!X509_NAME_add_entry_by_txt(subj, type, chtype, + (unsigned char *) v->value, -1, -1, mval)) + return 0; + + } + + if (!X509_NAME_entry_count(subj)) { + BIO_printf(bio_err, "error, no objects specified in config file\n"); + return 0; + } + if (attribs) { + for (i = 0; i < sk_CONF_VALUE_num(attr_sk); i++) { + v = sk_CONF_VALUE_value(attr_sk, i); + if (!X509_REQ_add1_attr_by_txt(req, v->name, chtype, + (unsigned char *) v->value, -1)) + return 0; + } + } + return 1; +} + + +static int +add_DN_object(X509_NAME * n, char *text, const char *def, char *value, + int nid, int n_min, int n_max, unsigned long chtype, int mval) +{ + int i, ret = 0; + char buf[1024]; +start: + if (!batch) + BIO_printf(bio_err, "%s [%s]:", text, def); + (void) BIO_flush(bio_err); + if (value != NULL) { + strlcpy(buf, value, sizeof buf); + strlcat(buf, "\n", sizeof buf); + BIO_printf(bio_err, "%s\n", value); + } else { + buf[0] = '\0'; + if (!batch) { + if (!fgets(buf, sizeof buf, stdin)) + return 0; + } else { + buf[0] = '\n'; + buf[1] = '\0'; + } + } + + if (buf[0] == '\0') + return (0); + else if (buf[0] == '\n') { + if ((def == NULL) || (def[0] == '\0')) + return (1); + strlcpy(buf, def, sizeof buf); + strlcat(buf, "\n", sizeof buf); + } else if ((buf[0] == '.') && (buf[1] == '\n')) + return (1); + + i = strlen(buf); + if (buf[i - 1] != '\n') { + BIO_printf(bio_err, "weird input :-(\n"); + return (0); + } + buf[--i] = '\0'; + if (!req_check_len(i, n_min, n_max)) + goto start; + if (!X509_NAME_add_entry_by_NID(n, nid, chtype, + (unsigned char *) buf, -1, -1, mval)) + goto err; + ret = 1; +err: + return (ret); +} + +static int +add_attribute_object(X509_REQ * req, char *text, const char *def, + char *value, int nid, int n_min, + int n_max, unsigned long chtype) +{ + int i; + static char buf[1024]; + +start: + if (!batch) + BIO_printf(bio_err, "%s [%s]:", text, def); + (void) BIO_flush(bio_err); + if (value != NULL) { + strlcpy(buf, value, sizeof buf); + strlcat(buf, "\n", sizeof buf); + BIO_printf(bio_err, "%s\n", value); + } else { + buf[0] = '\0'; + if (!batch) { + if (!fgets(buf, sizeof buf, stdin)) + return 0; + } else { + buf[0] = '\n'; + buf[1] = '\0'; + } + } + + if (buf[0] == '\0') + return (0); + else if (buf[0] == '\n') { + if ((def == NULL) || (def[0] == '\0')) + return (1); + strlcpy(buf, def, sizeof buf); + strlcat(buf, "\n", sizeof buf); + } else if ((buf[0] == '.') && (buf[1] == '\n')) + return (1); + + i = strlen(buf); + if (buf[i - 1] != '\n') { + BIO_printf(bio_err, "weird input :-(\n"); + return (0); + } + buf[--i] = '\0'; + if (!req_check_len(i, n_min, n_max)) + goto start; + + if (!X509_REQ_add1_attr_by_NID(req, nid, chtype, + (unsigned char *) buf, -1)) { + BIO_printf(bio_err, "Error adding attribute\n"); + ERR_print_errors(bio_err); + goto err; + } + return (1); +err: + return (0); +} + +static int +req_check_len(int len, int n_min, int n_max) +{ + if ((n_min > 0) && (len < n_min)) { + BIO_printf(bio_err, "string is too short, it needs to be at least %d bytes long\n", n_min); + return (0); + } + if ((n_max >= 0) && (len > n_max)) { + BIO_printf(bio_err, "string is too long, it needs to be less than %d bytes long\n", n_max); + return (0); + } + return (1); +} + +/* Check if the end of a string matches 'end' */ +static int +check_end(const char *str, const char *end) +{ + int elen, slen; + const char *tmp; + elen = strlen(end); + slen = strlen(str); + if (elen > slen) + return 1; + tmp = str + slen - elen; + return strcmp(tmp, end); +} + +static EVP_PKEY_CTX * +set_keygen_ctx(BIO * err, const char *gstr, int *pkey_type, + long *pkeylen, char **palgnam) +{ + EVP_PKEY_CTX *gctx = NULL; + EVP_PKEY *param = NULL; + long keylen = -1; + BIO *pbio = NULL; + const char *paramfile = NULL; + const char *errstr; + + if (gstr == NULL) { + *pkey_type = EVP_PKEY_RSA; + keylen = *pkeylen; + } else if (gstr[0] >= '0' && gstr[0] <= '9') { + *pkey_type = EVP_PKEY_RSA; + keylen = strtonum(gstr, 0, LONG_MAX, &errstr); + if (errstr) { + BIO_printf(err, "bad algorithm %s: %s\n", gstr, errstr); + return NULL; + } + *pkeylen = keylen; + } else if (!strncmp(gstr, "param:", 6)) + paramfile = gstr + 6; + else { + const char *p = strchr(gstr, ':'); + int len; + const EVP_PKEY_ASN1_METHOD *ameth; + + if (p) + len = p - gstr; + else + len = strlen(gstr); + + ameth = EVP_PKEY_asn1_find_str(NULL, gstr, len); + + if (!ameth) { + BIO_printf(err, "Unknown algorithm %.*s\n", len, gstr); + return NULL; + } + EVP_PKEY_asn1_get0_info(NULL, pkey_type, NULL, NULL, NULL, + ameth); + if (*pkey_type == EVP_PKEY_RSA) { + if (p) { + keylen = strtonum(p + 1, 0, LONG_MAX, &errstr); + if (errstr) { + BIO_printf(err, "bad algorithm %s: %s\n", + p + 1, errstr); + return NULL; + } + *pkeylen = keylen; + } else + keylen = *pkeylen; + } else if (p) + paramfile = p + 1; + } + + if (paramfile) { + pbio = BIO_new_file(paramfile, "r"); + if (!pbio) { + BIO_printf(err, "Can't open parameter file %s\n", + paramfile); + return NULL; + } + param = PEM_read_bio_Parameters(pbio, NULL); + + if (!param) { + X509 *x; + (void) BIO_reset(pbio); + x = PEM_read_bio_X509(pbio, NULL, NULL, NULL); + if (x) { + param = X509_get_pubkey(x); + X509_free(x); + } + } + BIO_free(pbio); + + if (!param) { + BIO_printf(err, "Error reading parameter file %s\n", + paramfile); + return NULL; + } + if (*pkey_type == -1) + *pkey_type = EVP_PKEY_id(param); + else if (*pkey_type != EVP_PKEY_base_id(param)) { + BIO_printf(err, "Key Type does not match parameters\n"); + EVP_PKEY_free(param); + return NULL; + } + } + if (palgnam) { + const EVP_PKEY_ASN1_METHOD *ameth; + const char *anam; + ameth = EVP_PKEY_asn1_find(NULL, *pkey_type); + if (!ameth) { + BIO_puts(err, "Internal error: can't find key algorithm\n"); + return NULL; + } + EVP_PKEY_asn1_get0_info(NULL, NULL, NULL, NULL, &anam, ameth); + *palgnam = strdup(anam); + } + if (param) { + gctx = EVP_PKEY_CTX_new(param, NULL); + *pkeylen = EVP_PKEY_bits(param); + EVP_PKEY_free(param); + } else + gctx = EVP_PKEY_CTX_new_id(*pkey_type, NULL); + + if (!gctx) { + BIO_puts(err, "Error allocating keygen context\n"); + ERR_print_errors(err); + return NULL; + } + if (EVP_PKEY_keygen_init(gctx) <= 0) { + BIO_puts(err, "Error initializing keygen context\n"); + ERR_print_errors(err); + return NULL; + } + if ((*pkey_type == EVP_PKEY_RSA) && (keylen != -1)) { + if (EVP_PKEY_CTX_set_rsa_keygen_bits(gctx, keylen) <= 0) { + BIO_puts(err, "Error setting RSA keysize\n"); + ERR_print_errors(err); + EVP_PKEY_CTX_free(gctx); + return NULL; + } + } + + return gctx; +} + +static int +genpkey_cb(EVP_PKEY_CTX * ctx) +{ + char c = '*'; + BIO *b = EVP_PKEY_CTX_get_app_data(ctx); + int p; + p = EVP_PKEY_CTX_get_keygen_info(ctx, 0); + if (p == 0) + c = '.'; + if (p == 1) + c = '+'; + if (p == 2) + c = '*'; + if (p == 3) + c = '\n'; + BIO_write(b, &c, 1); + (void) BIO_flush(b); + return 1; +} + +static int +do_sign_init(BIO * err, EVP_MD_CTX * ctx, EVP_PKEY * pkey, + const EVP_MD * md, STACK_OF(OPENSSL_STRING) * sigopts) +{ + EVP_PKEY_CTX *pkctx = NULL; + int i; + EVP_MD_CTX_init(ctx); + if (!EVP_DigestSignInit(ctx, &pkctx, md, NULL, pkey)) + return 0; + for (i = 0; i < sk_OPENSSL_STRING_num(sigopts); i++) { + char *sigopt = sk_OPENSSL_STRING_value(sigopts, i); + if (pkey_ctrl_string(pkctx, sigopt) <= 0) { + BIO_printf(err, "parameter error \"%s\"\n", sigopt); + ERR_print_errors(bio_err); + return 0; + } + } + return 1; +} + +int +do_X509_sign(BIO * err, X509 * x, EVP_PKEY * pkey, const EVP_MD * md, + STACK_OF(OPENSSL_STRING) * sigopts) +{ + int rv; + EVP_MD_CTX mctx; + EVP_MD_CTX_init(&mctx); + rv = do_sign_init(err, &mctx, pkey, md, sigopts); + if (rv > 0) + rv = X509_sign_ctx(x, &mctx); + EVP_MD_CTX_cleanup(&mctx); + return rv > 0 ? 1 : 0; +} + + +int +do_X509_REQ_sign(BIO * err, X509_REQ * x, EVP_PKEY * pkey, const EVP_MD * md, + STACK_OF(OPENSSL_STRING) * sigopts) +{ + int rv; + EVP_MD_CTX mctx; + EVP_MD_CTX_init(&mctx); + rv = do_sign_init(err, &mctx, pkey, md, sigopts); + if (rv > 0) + rv = X509_REQ_sign_ctx(x, &mctx); + EVP_MD_CTX_cleanup(&mctx); + return rv > 0 ? 1 : 0; +} + + + +int +do_X509_CRL_sign(BIO * err, X509_CRL * x, EVP_PKEY * pkey, const EVP_MD * md, + STACK_OF(OPENSSL_STRING) * sigopts) +{ + int rv; + EVP_MD_CTX mctx; + EVP_MD_CTX_init(&mctx); + rv = do_sign_init(err, &mctx, pkey, md, sigopts); + if (rv > 0) + rv = X509_CRL_sign_ctx(x, &mctx); + EVP_MD_CTX_cleanup(&mctx); + return rv > 0 ? 1 : 0; +} diff --git a/bin/openssl/rsa.c b/bin/openssl/rsa.c new file mode 100644 index 0000000000..7ad1da13b2 --- /dev/null +++ b/bin/openssl/rsa.c @@ -0,0 +1,449 @@ +/* $OpenBSD: rsa.c,v 1.9 2017/01/20 08:57:12 deraadt Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include + +#include +#include +#include +#include + +#include "apps.h" +#include "progs.h" + +#include +#include +#include +#include +#include +#include +#include + +static struct { + int check; + const EVP_CIPHER *enc; + char *infile; + int informat; + int modulus; + int noout; + char *outfile; + int outformat; + char *passargin; + char *passargout; + int pubin; + int pubout; + int pvk_encr; + int sgckey; + int text; +} rsa_config; + +static int +rsa_opt_cipher(int argc, char **argv, int *argsused) +{ + char *name = argv[0]; + + if (*name++ != '-') + return (1); + + if ((rsa_config.enc = EVP_get_cipherbyname(name)) == NULL) { + fprintf(stderr, "Invalid cipher '%s'\n", name); + return (1); + } + + *argsused = 1; + return (0); +} + +static struct option rsa_options[] = { + { + .name = "check", + .desc = "Check consistency of RSA private key", + .type = OPTION_FLAG, + .opt.flag = &rsa_config.check, + }, + { + .name = "in", + .argname = "file", + .desc = "Input file (default stdin)", + .type = OPTION_ARG, + .opt.arg = &rsa_config.infile, + }, + { + .name = "inform", + .argname = "format", + .desc = "Input format (DER, NET or PEM (default))", + .type = OPTION_ARG_FORMAT, + .opt.value = &rsa_config.informat, + }, + { + .name = "modulus", + .desc = "Print the RSA key modulus", + .type = OPTION_FLAG, + .opt.flag = &rsa_config.modulus, + }, + { + .name = "noout", + .desc = "Do not print encoded version of the key", + .type = OPTION_FLAG, + .opt.flag = &rsa_config.noout, + }, + { + .name = "out", + .argname = "file", + .desc = "Output file (default stdout)", + .type = OPTION_ARG, + .opt.arg = &rsa_config.outfile, + }, + { + .name = "outform", + .argname = "format", + .desc = "Output format (DER, NET or PEM (default PEM))", + .type = OPTION_ARG_FORMAT, + .opt.value = &rsa_config.outformat, + }, + { + .name = "passin", + .argname = "src", + .desc = "Input file passphrase source", + .type = OPTION_ARG, + .opt.arg = &rsa_config.passargin, + }, + { + .name = "passout", + .argname = "src", + .desc = "Output file passphrase source", + .type = OPTION_ARG, + .opt.arg = &rsa_config.passargout, + }, + { + .name = "pubin", + .desc = "Expect a public key (default private key)", + .type = OPTION_VALUE, + .value = 1, + .opt.value = &rsa_config.pubin, + }, + { + .name = "pubout", + .desc = "Output a public key (default private key)", + .type = OPTION_VALUE, + .value = 1, + .opt.value = &rsa_config.pubout, + }, + { + .name = "pvk-none", + .type = OPTION_VALUE, + .value = 0, + .opt.value = &rsa_config.pvk_encr, + }, + { + .name = "pvk-strong", + .type = OPTION_VALUE, + .value = 2, + .opt.value = &rsa_config.pvk_encr, + }, + { + .name = "pvk-weak", + .type = OPTION_VALUE, + .value = 1, + .opt.value = &rsa_config.pvk_encr, + }, + { + .name = "RSAPublicKey_in", + .type = OPTION_VALUE, + .value = 2, + .opt.value = &rsa_config.pubin, + }, + { + .name = "RSAPublicKey_out", + .type = OPTION_VALUE, + .value = 2, + .opt.value = &rsa_config.pubout, + }, + { + .name = "sgckey", + .desc = "Use modified NET algorithm for IIS and SGC keys", + .type = OPTION_FLAG, + .opt.flag = &rsa_config.sgckey, + }, + { + .name = "text", + .desc = "Print in plain text in addition to encoded", + .type = OPTION_FLAG, + .opt.flag = &rsa_config.text, + }, + { + .name = NULL, + .type = OPTION_ARGV_FUNC, + .opt.argvfunc = rsa_opt_cipher, + }, + { NULL } +}; + +static void +show_ciphers(const OBJ_NAME *name, void *arg) +{ + static int n; + + fprintf(stderr, " -%-24s%s", name->name, (++n % 3 ? "" : "\n")); +} + +static void +rsa_usage() +{ + fprintf(stderr, + "usage: rsa [-ciphername] [-check] [-in file] " + "[-inform fmt]\n" + " [-modulus] [-noout] [-out file] [-outform fmt] " + "[-passin src]\n" + " [-passout src] [-pubin] [-pubout] [-sgckey] [-text]\n\n"); + options_usage(rsa_options); + fprintf(stderr, "\n"); + + fprintf(stderr, "Valid ciphername values:\n\n"); + OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, show_ciphers, NULL); + fprintf(stderr, "\n"); +} + +int +rsa_main(int argc, char **argv) +{ + int ret = 1; + RSA *rsa = NULL; + int i; + BIO *out = NULL; + char *passin = NULL, *passout = NULL; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + memset(&rsa_config, 0, sizeof(rsa_config)); + rsa_config.pvk_encr = 2; + rsa_config.informat = FORMAT_PEM; + rsa_config.outformat = FORMAT_PEM; + + if (options_parse(argc, argv, rsa_options, NULL, NULL) != 0) { + rsa_usage(); + goto end; + } + + if (!app_passwd(bio_err, rsa_config.passargin, rsa_config.passargout, + &passin, &passout)) { + BIO_printf(bio_err, "Error getting passwords\n"); + goto end; + } + if (rsa_config.check && rsa_config.pubin) { + BIO_printf(bio_err, "Only private keys can be checked\n"); + goto end; + } + out = BIO_new(BIO_s_file()); + + { + EVP_PKEY *pkey; + + if (rsa_config.pubin) { + int tmpformat = -1; + if (rsa_config.pubin == 2) { + if (rsa_config.informat == FORMAT_PEM) + tmpformat = FORMAT_PEMRSA; + else if (rsa_config.informat == FORMAT_ASN1) + tmpformat = FORMAT_ASN1RSA; + } else if (rsa_config.informat == FORMAT_NETSCAPE && + rsa_config.sgckey) + tmpformat = FORMAT_IISSGC; + else + tmpformat = rsa_config.informat; + + pkey = load_pubkey(bio_err, rsa_config.infile, + tmpformat, 1, passin, "Public Key"); + } else + pkey = load_key(bio_err, rsa_config.infile, + (rsa_config.informat == FORMAT_NETSCAPE && + rsa_config.sgckey ? FORMAT_IISSGC : + rsa_config.informat), 1, passin, "Private Key"); + + if (pkey != NULL) + rsa = EVP_PKEY_get1_RSA(pkey); + EVP_PKEY_free(pkey); + } + + if (rsa == NULL) { + ERR_print_errors(bio_err); + goto end; + } + if (rsa_config.outfile == NULL) { + BIO_set_fp(out, stdout, BIO_NOCLOSE); + } else { + if (BIO_write_filename(out, rsa_config.outfile) <= 0) { + perror(rsa_config.outfile); + goto end; + } + } + + if (rsa_config.text) + if (!RSA_print(out, rsa, 0)) { + perror(rsa_config.outfile); + ERR_print_errors(bio_err); + goto end; + } + if (rsa_config.modulus) { + BIO_printf(out, "Modulus="); + BN_print(out, rsa->n); + BIO_printf(out, "\n"); + } + if (rsa_config.check) { + int r = RSA_check_key(rsa); + + if (r == 1) + BIO_printf(out, "RSA key ok\n"); + else if (r == 0) { + unsigned long err; + + while ((err = ERR_peek_error()) != 0 && + ERR_GET_LIB(err) == ERR_LIB_RSA && + ERR_GET_FUNC(err) == RSA_F_RSA_CHECK_KEY && + ERR_GET_REASON(err) != ERR_R_MALLOC_FAILURE) { + BIO_printf(out, "RSA key error: %s\n", + ERR_reason_error_string(err)); + ERR_get_error(); /* remove e from error + * stack */ + } + } + if (r == -1 || ERR_peek_error() != 0) { /* should happen only if + * r == -1 */ + ERR_print_errors(bio_err); + goto end; + } + } + if (rsa_config.noout) { + ret = 0; + goto end; + } + BIO_printf(bio_err, "writing RSA key\n"); + if (rsa_config.outformat == FORMAT_ASN1) { + if (rsa_config.pubout || rsa_config.pubin) { + if (rsa_config.pubout == 2) + i = i2d_RSAPublicKey_bio(out, rsa); + else + i = i2d_RSA_PUBKEY_bio(out, rsa); + } else + i = i2d_RSAPrivateKey_bio(out, rsa); + } +#ifndef OPENSSL_NO_RC4 + else if (rsa_config.outformat == FORMAT_NETSCAPE) { + unsigned char *p, *pp; + int size; + + i = 1; + size = i2d_RSA_NET(rsa, NULL, NULL, rsa_config.sgckey); + if ((p = malloc(size)) == NULL) { + BIO_printf(bio_err, "Memory allocation failure\n"); + goto end; + } + pp = p; + i2d_RSA_NET(rsa, &p, NULL, rsa_config.sgckey); + BIO_write(out, (char *) pp, size); + free(pp); + } +#endif + else if (rsa_config.outformat == FORMAT_PEM) { + if (rsa_config.pubout || rsa_config.pubin) { + if (rsa_config.pubout == 2) + i = PEM_write_bio_RSAPublicKey(out, rsa); + else + i = PEM_write_bio_RSA_PUBKEY(out, rsa); + } else + i = PEM_write_bio_RSAPrivateKey(out, rsa, + rsa_config.enc, NULL, 0, NULL, passout); +#if !defined(OPENSSL_NO_DSA) && !defined(OPENSSL_NO_RC4) + } else if (rsa_config.outformat == FORMAT_MSBLOB || + rsa_config.outformat == FORMAT_PVK) { + EVP_PKEY *pk; + pk = EVP_PKEY_new(); + EVP_PKEY_set1_RSA(pk, rsa); + if (rsa_config.outformat == FORMAT_PVK) + i = i2b_PVK_bio(out, pk, rsa_config.pvk_encr, 0, + passout); + else if (rsa_config.pubin || rsa_config.pubout) + i = i2b_PublicKey_bio(out, pk); + else + i = i2b_PrivateKey_bio(out, pk); + EVP_PKEY_free(pk); +#endif + } else { + BIO_printf(bio_err, + "bad output format specified for outfile\n"); + goto end; + } + if (i <= 0) { + BIO_printf(bio_err, "unable to write key\n"); + ERR_print_errors(bio_err); + } else + ret = 0; + +end: + BIO_free_all(out); + RSA_free(rsa); + free(passin); + free(passout); + + return (ret); +} diff --git a/bin/openssl/rsautl.c b/bin/openssl/rsautl.c new file mode 100644 index 0000000000..48f739135a --- /dev/null +++ b/bin/openssl/rsautl.c @@ -0,0 +1,332 @@ +/* $OpenBSD: rsautl.c,v 1.11 2017/01/20 08:57:12 deraadt Exp $ */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2000. + */ +/* ==================================================================== + * Copyright (c) 2000 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include + + +#include + +#include "apps.h" + +#include +#include +#include + +#define RSA_SIGN 1 +#define RSA_VERIFY 2 +#define RSA_ENCRYPT 3 +#define RSA_DECRYPT 4 + +#define KEY_PRIVKEY 1 +#define KEY_PUBKEY 2 +#define KEY_CERT 3 + +static void usage(void); + +int +rsautl_main(int argc, char **argv) +{ + BIO *in = NULL, *out = NULL; + char *infile = NULL, *outfile = NULL; + char *keyfile = NULL; + char rsa_mode = RSA_VERIFY, key_type = KEY_PRIVKEY; + int keyform = FORMAT_PEM; + char need_priv = 0, badarg = 0, rev = 0; + char hexdump = 0, asn1parse = 0; + X509 *x; + EVP_PKEY *pkey = NULL; + RSA *rsa = NULL; + unsigned char *rsa_in = NULL, *rsa_out = NULL, pad; + char *passargin = NULL, *passin = NULL; + int rsa_inlen, rsa_outlen = 0; + int keysize; + + int ret = 1; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath tty", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + argc--; + argv++; + + pad = RSA_PKCS1_PADDING; + + while (argc >= 1) { + if (!strcmp(*argv, "-in")) { + if (--argc < 1) + badarg = 1; + else + infile = *(++argv); + } else if (!strcmp(*argv, "-out")) { + if (--argc < 1) + badarg = 1; + else + outfile = *(++argv); + } else if (!strcmp(*argv, "-inkey")) { + if (--argc < 1) + badarg = 1; + else + keyfile = *(++argv); + } else if (!strcmp(*argv, "-passin")) { + if (--argc < 1) + badarg = 1; + else + passargin = *(++argv); + } else if (strcmp(*argv, "-keyform") == 0) { + if (--argc < 1) + badarg = 1; + else + keyform = str2fmt(*(++argv)); + } else if (!strcmp(*argv, "-pubin")) { + key_type = KEY_PUBKEY; + } else if (!strcmp(*argv, "-certin")) { + key_type = KEY_CERT; + } else if (!strcmp(*argv, "-asn1parse")) + asn1parse = 1; + else if (!strcmp(*argv, "-hexdump")) + hexdump = 1; + else if (!strcmp(*argv, "-raw")) + pad = RSA_NO_PADDING; + else if (!strcmp(*argv, "-oaep")) + pad = RSA_PKCS1_OAEP_PADDING; + else if (!strcmp(*argv, "-ssl")) + pad = RSA_SSLV23_PADDING; + else if (!strcmp(*argv, "-pkcs")) + pad = RSA_PKCS1_PADDING; + else if (!strcmp(*argv, "-x931")) + pad = RSA_X931_PADDING; + else if (!strcmp(*argv, "-sign")) { + rsa_mode = RSA_SIGN; + need_priv = 1; + } else if (!strcmp(*argv, "-verify")) + rsa_mode = RSA_VERIFY; + else if (!strcmp(*argv, "-rev")) + rev = 1; + else if (!strcmp(*argv, "-encrypt")) + rsa_mode = RSA_ENCRYPT; + else if (!strcmp(*argv, "-decrypt")) { + rsa_mode = RSA_DECRYPT; + need_priv = 1; + } else + badarg = 1; + if (badarg) { + usage(); + goto end; + } + argc--; + argv++; + } + + if (need_priv && (key_type != KEY_PRIVKEY)) { + BIO_printf(bio_err, "A private key is needed for this operation\n"); + goto end; + } + if (!app_passwd(bio_err, passargin, NULL, &passin, NULL)) { + BIO_printf(bio_err, "Error getting password\n"); + goto end; + } + + switch (key_type) { + case KEY_PRIVKEY: + pkey = load_key(bio_err, keyfile, keyform, 0, + passin, "Private Key"); + break; + + case KEY_PUBKEY: + pkey = load_pubkey(bio_err, keyfile, keyform, 0, + NULL, "Public Key"); + break; + + case KEY_CERT: + x = load_cert(bio_err, keyfile, keyform, + NULL, "Certificate"); + if (x) { + pkey = X509_get_pubkey(x); + X509_free(x); + } + break; + } + + if (!pkey) + goto end; + + rsa = EVP_PKEY_get1_RSA(pkey); + EVP_PKEY_free(pkey); + + if (!rsa) { + BIO_printf(bio_err, "Error getting RSA key\n"); + ERR_print_errors(bio_err); + goto end; + } + if (infile) { + if (!(in = BIO_new_file(infile, "rb"))) { + BIO_printf(bio_err, "Error Reading Input File\n"); + ERR_print_errors(bio_err); + goto end; + } + } else + in = BIO_new_fp(stdin, BIO_NOCLOSE); + + if (outfile) { + if (!(out = BIO_new_file(outfile, "wb"))) { + BIO_printf(bio_err, "Error Reading Output File\n"); + ERR_print_errors(bio_err); + goto end; + } + } else { + out = BIO_new_fp(stdout, BIO_NOCLOSE); + } + + keysize = RSA_size(rsa); + + rsa_in = reallocarray(NULL, keysize, 2); + if (rsa_in == NULL) { + BIO_printf(bio_err, "Error allocating memory for input data\n"); + exit(1); + } + rsa_out = malloc(keysize); + if (rsa_out == NULL) { + BIO_printf(bio_err, "Error allocating memory for output data\n"); + exit(1); + } + + /* Read the input data */ + rsa_inlen = BIO_read(in, rsa_in, keysize * 2); + if (rsa_inlen <= 0) { + BIO_printf(bio_err, "Error reading input Data\n"); + exit(1); + } + if (rev) { + int i; + unsigned char ctmp; + for (i = 0; i < rsa_inlen / 2; i++) { + ctmp = rsa_in[i]; + rsa_in[i] = rsa_in[rsa_inlen - 1 - i]; + rsa_in[rsa_inlen - 1 - i] = ctmp; + } + } + switch (rsa_mode) { + + case RSA_VERIFY: + rsa_outlen = RSA_public_decrypt(rsa_inlen, rsa_in, rsa_out, rsa, pad); + break; + + case RSA_SIGN: + rsa_outlen = RSA_private_encrypt(rsa_inlen, rsa_in, rsa_out, rsa, pad); + break; + + case RSA_ENCRYPT: + rsa_outlen = RSA_public_encrypt(rsa_inlen, rsa_in, rsa_out, rsa, pad); + break; + + case RSA_DECRYPT: + rsa_outlen = RSA_private_decrypt(rsa_inlen, rsa_in, rsa_out, rsa, pad); + break; + + } + + if (rsa_outlen <= 0) { + BIO_printf(bio_err, "RSA operation error\n"); + ERR_print_errors(bio_err); + goto end; + } + ret = 0; + if (asn1parse) { + if (!ASN1_parse_dump(out, rsa_out, rsa_outlen, 1, -1)) { + ERR_print_errors(bio_err); + } + } else if (hexdump) + BIO_dump(out, (char *) rsa_out, rsa_outlen); + else + BIO_write(out, rsa_out, rsa_outlen); + +end: + RSA_free(rsa); + BIO_free(in); + BIO_free_all(out); + free(rsa_in); + free(rsa_out); + free(passin); + + return ret; +} + +static void +usage() +{ + BIO_printf(bio_err, "Usage: rsautl [options]\n"); + BIO_printf(bio_err, "-in file input file\n"); + BIO_printf(bio_err, "-out file output file\n"); + BIO_printf(bio_err, "-inkey file input key\n"); + BIO_printf(bio_err, "-keyform arg private key format - default PEM\n"); + BIO_printf(bio_err, "-pubin input is an RSA public\n"); + BIO_printf(bio_err, "-certin input is a certificate carrying an RSA public key\n"); + BIO_printf(bio_err, "-ssl use SSL v2 padding\n"); + BIO_printf(bio_err, "-raw use no padding\n"); + BIO_printf(bio_err, "-pkcs use PKCS#1 v1.5 padding (default)\n"); + BIO_printf(bio_err, "-oaep use PKCS#1 OAEP\n"); + BIO_printf(bio_err, "-sign sign with private key\n"); + BIO_printf(bio_err, "-verify verify with public key\n"); + BIO_printf(bio_err, "-encrypt encrypt with public key\n"); + BIO_printf(bio_err, "-decrypt decrypt with private key\n"); + BIO_printf(bio_err, "-hexdump hex dump output\n"); +} diff --git a/bin/openssl/s_apps.h b/bin/openssl/s_apps.h new file mode 100644 index 0000000000..ecadff5c01 --- /dev/null +++ b/bin/openssl/s_apps.h @@ -0,0 +1,151 @@ +/* $OpenBSD: s_apps.h,v 1.4 2016/12/30 17:25:48 jsing Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +#include +#include + +#define PORT 4433 +#define PORT_STR "4433" +#define PROTOCOL "tcp" + +extern int verify_depth; +extern int verify_return_error; + +int do_server(int port, int type, int *ret, + int (*cb)(char *hostname, int s, unsigned char *context), + unsigned char *context); +#ifdef HEADER_X509_H +int verify_callback(int ok, X509_STORE_CTX *ctx); +#endif +#ifdef HEADER_SSL_H +int set_cert_stuff(SSL_CTX *ctx, char *cert_file, char *key_file); +int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key); +#endif +int ssl_print_tmp_key(BIO *out, SSL *s); +int init_client(int *sock, char *server, char *port, int type, int af); +int should_retry(int i); +int extract_port(char *str, short *port_ptr); +int extract_host_port(char *str, char **host_ptr, unsigned char *ip, char **p); + +long bio_dump_callback(BIO *bio, int cmd, const char *argp, int argi, + long argl, long ret); + +#ifdef HEADER_SSL_H +void apps_ssl_info_callback(const SSL *s, int where, int ret); +void msg_cb(int write_p, int version, int content_type, const void *buf, + size_t len, SSL *ssl, void *arg); +void tlsext_cb(SSL *s, int client_server, int type, unsigned char *data, + int len, void *arg); +#endif + +int generate_cookie_callback(SSL *ssl, unsigned char *cookie, + unsigned int *cookie_len); +int verify_cookie_callback(SSL *ssl, unsigned char *cookie, + unsigned int cookie_len); diff --git a/bin/openssl/s_cb.c b/bin/openssl/s_cb.c new file mode 100644 index 0000000000..d8ab83fb01 --- /dev/null +++ b/bin/openssl/s_cb.c @@ -0,0 +1,886 @@ +/* $OpenBSD: s_cb.c,v 1.7 2016/12/30 17:25:48 jsing Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include + +#include + +#include +#include +#include +#include + +#include "apps.h" + +#include +#include +#include + +#include "s_apps.h" + +#define COOKIE_SECRET_LENGTH 16 + +int verify_depth = 0; +int verify_return_error = 0; +unsigned char cookie_secret[COOKIE_SECRET_LENGTH]; +int cookie_initialized = 0; + +int +verify_callback(int ok, X509_STORE_CTX * ctx) +{ + X509 *err_cert; + int err, depth; + + err_cert = X509_STORE_CTX_get_current_cert(ctx); + err = X509_STORE_CTX_get_error(ctx); + depth = X509_STORE_CTX_get_error_depth(ctx); + + BIO_printf(bio_err, "depth=%d ", depth); + if (err_cert) { + X509_NAME_print_ex(bio_err, X509_get_subject_name(err_cert), + 0, XN_FLAG_ONELINE); + BIO_puts(bio_err, "\n"); + } else + BIO_puts(bio_err, "\n"); + if (!ok) { + BIO_printf(bio_err, "verify error:num=%d:%s\n", err, + X509_verify_cert_error_string(err)); + if (verify_depth >= depth) { + if (!verify_return_error) + ok = 1; + } else { + ok = 0; + } + } + switch (err) { + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: + BIO_puts(bio_err, "issuer= "); + if (err_cert == NULL) + BIO_puts(bio_err, ""); + else + X509_NAME_print_ex(bio_err, + X509_get_issuer_name(err_cert), 0, XN_FLAG_ONELINE); + BIO_puts(bio_err, "\n"); + break; + case X509_V_ERR_CERT_NOT_YET_VALID: + case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: + BIO_printf(bio_err, "notBefore="); + if (err_cert == NULL) + BIO_printf(bio_err, " "); + else + ASN1_TIME_print(bio_err, X509_get_notBefore(err_cert)); + BIO_printf(bio_err, "\n"); + break; + case X509_V_ERR_CERT_HAS_EXPIRED: + case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: + BIO_printf(bio_err, "notAfter="); + if (err_cert == NULL) + BIO_printf(bio_err, " "); + else + ASN1_TIME_print(bio_err, X509_get_notAfter(err_cert)); + BIO_printf(bio_err, "\n"); + break; + case X509_V_ERR_NO_EXPLICIT_POLICY: + policies_print(bio_err, ctx); + break; + } + if (err == X509_V_OK && ok == 2) + policies_print(bio_err, ctx); + + BIO_printf(bio_err, "verify return:%d\n", ok); + return (ok); +} + +int +set_cert_stuff(SSL_CTX * ctx, char *cert_file, char *key_file) +{ + if (cert_file != NULL) { + /* + SSL *ssl; + X509 *x509; + */ + + if (SSL_CTX_use_certificate_file(ctx, cert_file, + SSL_FILETYPE_PEM) <= 0) { + BIO_printf(bio_err, + "unable to get certificate from '%s'\n", cert_file); + ERR_print_errors(bio_err); + return (0); + } + if (key_file == NULL) + key_file = cert_file; + if (SSL_CTX_use_PrivateKey_file(ctx, key_file, + SSL_FILETYPE_PEM) <= 0) { + BIO_printf(bio_err, + "unable to get private key from '%s'\n", key_file); + ERR_print_errors(bio_err); + return (0); + } + /* + In theory this is no longer needed + ssl=SSL_new(ctx); + x509=SSL_get_certificate(ssl); + + if (x509 != NULL) { + EVP_PKEY *pktmp; + pktmp = X509_get_pubkey(x509); + EVP_PKEY_copy_parameters(pktmp, + SSL_get_privatekey(ssl)); + EVP_PKEY_free(pktmp); + } + SSL_free(ssl); + */ + + /* + * If we are using DSA, we can copy the parameters from the + * private key + */ + + + /* + * Now we know that a key and cert have been set against the + * SSL context + */ + if (!SSL_CTX_check_private_key(ctx)) { + BIO_printf(bio_err, + "Private key does not match the certificate public key\n"); + return (0); + } + } + return (1); +} + +int +set_cert_key_stuff(SSL_CTX * ctx, X509 * cert, EVP_PKEY * key) +{ + if (cert == NULL) + return 1; + if (SSL_CTX_use_certificate(ctx, cert) <= 0) { + BIO_printf(bio_err, "error setting certificate\n"); + ERR_print_errors(bio_err); + return 0; + } + if (SSL_CTX_use_PrivateKey(ctx, key) <= 0) { + BIO_printf(bio_err, "error setting private key\n"); + ERR_print_errors(bio_err); + return 0; + } + /* + * Now we know that a key and cert have been set against the SSL + * context + */ + if (!SSL_CTX_check_private_key(ctx)) { + BIO_printf(bio_err, + "Private key does not match the certificate public key\n"); + return 0; + } + return 1; +} + +int +ssl_print_tmp_key(BIO *out, SSL *s) +{ + const char *cname; + EVP_PKEY *pkey; + EC_KEY *ec; + int nid; + + if (!SSL_get_server_tmp_key(s, &pkey)) + return 0; + + BIO_puts(out, "Server Temp Key: "); + switch (EVP_PKEY_id(pkey)) { + case EVP_PKEY_DH: + BIO_printf(out, "DH, %d bits\n", EVP_PKEY_bits(pkey)); + break; + + case EVP_PKEY_EC: + ec = EVP_PKEY_get1_EC_KEY(pkey); + nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec)); + EC_KEY_free(ec); + + if ((cname = EC_curve_nid2nist(nid)) == NULL) + cname = OBJ_nid2sn(nid); + + BIO_printf(out, "ECDH, %s, %d bits\n", cname, EVP_PKEY_bits(pkey)); + break; + + default: + BIO_printf(out, "%s, %d bits\n", OBJ_nid2sn(EVP_PKEY_id(pkey)), + EVP_PKEY_bits(pkey)); + } + + EVP_PKEY_free(pkey); + return 1; +} + +long +bio_dump_callback(BIO * bio, int cmd, const char *argp, + int argi, long argl, long ret) +{ + BIO *out; + + out = (BIO *) BIO_get_callback_arg(bio); + if (out == NULL) + return (ret); + + if (cmd == (BIO_CB_READ | BIO_CB_RETURN)) { + BIO_printf(out, + "read from %p [%p] (%lu bytes => %ld (0x%lX))\n", + (void *) bio, argp, (unsigned long) argi, ret, ret); + BIO_dump(out, argp, (int) ret); + return (ret); + } else if (cmd == (BIO_CB_WRITE | BIO_CB_RETURN)) { + BIO_printf(out, + "write to %p [%p] (%lu bytes => %ld (0x%lX))\n", + (void *) bio, argp, (unsigned long) argi, ret, ret); + BIO_dump(out, argp, (int) ret); + } + return (ret); +} + +void +apps_ssl_info_callback(const SSL * s, int where, int ret) +{ + const char *str; + int w; + + w = where & ~SSL_ST_MASK; + + if (w & SSL_ST_CONNECT) + str = "SSL_connect"; + else if (w & SSL_ST_ACCEPT) + str = "SSL_accept"; + else + str = "undefined"; + + if (where & SSL_CB_LOOP) { + BIO_printf(bio_err, "%s:%s\n", str, SSL_state_string_long(s)); + } else if (where & SSL_CB_ALERT) { + str = (where & SSL_CB_READ) ? "read" : "write"; + BIO_printf(bio_err, "SSL3 alert %s:%s:%s\n", str, + SSL_alert_type_string_long(ret), + SSL_alert_desc_string_long(ret)); + } else if (where & SSL_CB_EXIT) { + if (ret == 0) + BIO_printf(bio_err, "%s:failed in %s\n", + str, SSL_state_string_long(s)); + else if (ret < 0) { + BIO_printf(bio_err, "%s:error in %s\n", + str, SSL_state_string_long(s)); + } + } +} + + +void +msg_cb(int write_p, int version, int content_type, const void *buf, size_t len, SSL * ssl, void *arg) +{ + BIO *bio = arg; + const char *str_write_p, *str_version, *str_content_type = "", + *str_details1 = "", *str_details2 = ""; + + str_write_p = write_p ? ">>>" : "<<<"; + + switch (version) { + case SSL2_VERSION: + str_version = "SSL 2.0"; + break; + case SSL3_VERSION: + str_version = "SSL 3.0 "; + break; + case TLS1_VERSION: + str_version = "TLS 1.0 "; + break; + case TLS1_1_VERSION: + str_version = "TLS 1.1 "; + break; + case TLS1_2_VERSION: + str_version = "TLS 1.2 "; + break; + case DTLS1_VERSION: + str_version = "DTLS 1.0 "; + break; + default: + str_version = "???"; + } + + if (version == SSL2_VERSION) { + str_details1 = "???"; + + if (len > 0) { + switch (((const unsigned char *) buf)[0]) { + case 0: + str_details1 = ", ERROR:"; + str_details2 = " ???"; + if (len >= 3) { + unsigned err = (((const unsigned char *) buf)[1] << 8) + ((const unsigned char *) buf)[2]; + + switch (err) { + case 0x0001: + str_details2 = " NO-CIPHER-ERROR"; + break; + case 0x0002: + str_details2 = " NO-CERTIFICATE-ERROR"; + break; + case 0x0004: + str_details2 = " BAD-CERTIFICATE-ERROR"; + break; + case 0x0006: + str_details2 = " UNSUPPORTED-CERTIFICATE-TYPE-ERROR"; + break; + } + } + break; + case 1: + str_details1 = ", CLIENT-HELLO"; + break; + case 2: + str_details1 = ", CLIENT-MASTER-KEY"; + break; + case 3: + str_details1 = ", CLIENT-FINISHED"; + break; + case 4: + str_details1 = ", SERVER-HELLO"; + break; + case 5: + str_details1 = ", SERVER-VERIFY"; + break; + case 6: + str_details1 = ", SERVER-FINISHED"; + break; + case 7: + str_details1 = ", REQUEST-CERTIFICATE"; + break; + case 8: + str_details1 = ", CLIENT-CERTIFICATE"; + break; + } + } + } + if (version == SSL3_VERSION || version == TLS1_VERSION || + version == TLS1_1_VERSION || version == TLS1_2_VERSION || + version == DTLS1_VERSION) { + switch (content_type) { + case 20: + str_content_type = "ChangeCipherSpec"; + break; + case 21: + str_content_type = "Alert"; + break; + case 22: + str_content_type = "Handshake"; + break; + } + + if (content_type == 21) { /* Alert */ + str_details1 = ", ???"; + + if (len == 2) { + switch (((const unsigned char *) buf)[0]) { + case 1: + str_details1 = ", warning"; + break; + case 2: + str_details1 = ", fatal"; + break; + } + + str_details2 = " ???"; + switch (((const unsigned char *) buf)[1]) { + case 0: + str_details2 = " close_notify"; + break; + case 10: + str_details2 = " unexpected_message"; + break; + case 20: + str_details2 = " bad_record_mac"; + break; + case 21: + str_details2 = " decryption_failed"; + break; + case 22: + str_details2 = " record_overflow"; + break; + case 30: + str_details2 = " decompression_failure"; + break; + case 40: + str_details2 = " handshake_failure"; + break; + case 42: + str_details2 = " bad_certificate"; + break; + case 43: + str_details2 = " unsupported_certificate"; + break; + case 44: + str_details2 = " certificate_revoked"; + break; + case 45: + str_details2 = " certificate_expired"; + break; + case 46: + str_details2 = " certificate_unknown"; + break; + case 47: + str_details2 = " illegal_parameter"; + break; + case 48: + str_details2 = " unknown_ca"; + break; + case 49: + str_details2 = " access_denied"; + break; + case 50: + str_details2 = " decode_error"; + break; + case 51: + str_details2 = " decrypt_error"; + break; + case 60: + str_details2 = " export_restriction"; + break; + case 70: + str_details2 = " protocol_version"; + break; + case 71: + str_details2 = " insufficient_security"; + break; + case 80: + str_details2 = " internal_error"; + break; + case 90: + str_details2 = " user_canceled"; + break; + case 100: + str_details2 = " no_renegotiation"; + break; + case 110: + str_details2 = " unsupported_extension"; + break; + case 111: + str_details2 = " certificate_unobtainable"; + break; + case 112: + str_details2 = " unrecognized_name"; + break; + case 113: + str_details2 = " bad_certificate_status_response"; + break; + case 114: + str_details2 = " bad_certificate_hash_value"; + break; + case 115: + str_details2 = " unknown_psk_identity"; + break; + } + } + } + if (content_type == 22) { /* Handshake */ + str_details1 = "???"; + + if (len > 0) { + switch (((const unsigned char *) buf)[0]) { + case 0: + str_details1 = ", HelloRequest"; + break; + case 1: + str_details1 = ", ClientHello"; + break; + case 2: + str_details1 = ", ServerHello"; + break; + case 3: + str_details1 = ", HelloVerifyRequest"; + break; + case 11: + str_details1 = ", Certificate"; + break; + case 12: + str_details1 = ", ServerKeyExchange"; + break; + case 13: + str_details1 = ", CertificateRequest"; + break; + case 14: + str_details1 = ", ServerHelloDone"; + break; + case 15: + str_details1 = ", CertificateVerify"; + break; + case 16: + str_details1 = ", ClientKeyExchange"; + break; + case 20: + str_details1 = ", Finished"; + break; + } + } + } + } + BIO_printf(bio, "%s %s%s [length %04lx]%s%s\n", str_write_p, + str_version, str_content_type, (unsigned long) len, + str_details1, str_details2); + + if (len > 0) { + size_t num, i; + + BIO_printf(bio, " "); + num = len; + + for (i = 0; i < num; i++) { + if (i % 16 == 0 && i > 0) + BIO_printf(bio, "\n "); + BIO_printf(bio, " %02x", + ((const unsigned char *) buf)[i]); + } + if (i < len) + BIO_printf(bio, " ..."); + BIO_printf(bio, "\n"); + } + (void) BIO_flush(bio); +} + +void +tlsext_cb(SSL * s, int client_server, int type, unsigned char *data, int len, + void *arg) +{ + BIO *bio = arg; + char *extname; + + switch (type) { + case TLSEXT_TYPE_server_name: + extname = "server name"; + break; + + case TLSEXT_TYPE_max_fragment_length: + extname = "max fragment length"; + break; + + case TLSEXT_TYPE_client_certificate_url: + extname = "client certificate URL"; + break; + + case TLSEXT_TYPE_trusted_ca_keys: + extname = "trusted CA keys"; + break; + + case TLSEXT_TYPE_truncated_hmac: + extname = "truncated HMAC"; + break; + + case TLSEXT_TYPE_status_request: + extname = "status request"; + break; + + case TLSEXT_TYPE_user_mapping: + extname = "user mapping"; + break; + + case TLSEXT_TYPE_client_authz: + extname = "client authz"; + break; + + case TLSEXT_TYPE_server_authz: + extname = "server authz"; + break; + + case TLSEXT_TYPE_cert_type: + extname = "cert type"; + break; + + case TLSEXT_TYPE_elliptic_curves: + extname = "elliptic curves"; + break; + + case TLSEXT_TYPE_ec_point_formats: + extname = "EC point formats"; + break; + + case TLSEXT_TYPE_srp: + extname = "SRP"; + break; + + case TLSEXT_TYPE_signature_algorithms: + extname = "signature algorithms"; + break; + + case TLSEXT_TYPE_use_srtp: + extname = "use SRTP"; + break; + + case TLSEXT_TYPE_heartbeat: + extname = "heartbeat"; + break; + + case TLSEXT_TYPE_session_ticket: + extname = "session ticket"; + break; + + case TLSEXT_TYPE_renegotiate: + extname = "renegotiation info"; + break; + +#ifdef TLSEXT_TYPE_next_proto_neg + case TLSEXT_TYPE_next_proto_neg: + extname = "next protocol"; + break; +#endif + + default: + extname = "unknown"; + break; + + } + + BIO_printf(bio, "TLS %s extension \"%s\" (id=%d), len=%d\n", + client_server ? "server" : "client", extname, type, len); + BIO_dump(bio, (char *) data, len); + (void) BIO_flush(bio); +} + +int +generate_cookie_callback(SSL * ssl, unsigned char *cookie, + unsigned int *cookie_len) +{ + unsigned char *buffer, result[EVP_MAX_MD_SIZE]; + unsigned int length, resultlength; + union { + struct sockaddr sa; + struct sockaddr_in s4; + struct sockaddr_in6 s6; + } peer; + + /* Initialize a random secret */ + if (!cookie_initialized) { + arc4random_buf(cookie_secret, COOKIE_SECRET_LENGTH); + cookie_initialized = 1; + } + /* Read peer information */ + (void) BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer); + + /* Create buffer with peer's address and port */ + length = 0; + switch (peer.sa.sa_family) { + case AF_INET: + length += sizeof(struct in_addr); + length += sizeof(peer.s4.sin_port); + break; + case AF_INET6: + length += sizeof(struct in6_addr); + length += sizeof(peer.s6.sin6_port); + break; + default: + OPENSSL_assert(0); + break; + } + buffer = malloc(length); + + if (buffer == NULL) { + BIO_printf(bio_err, "out of memory\n"); + return 0; + } + switch (peer.sa.sa_family) { + case AF_INET: + memcpy(buffer, &peer.s4.sin_port, sizeof(peer.s4.sin_port)); + memcpy(buffer + sizeof(peer.s4.sin_port), + &peer.s4.sin_addr, sizeof(struct in_addr)); + break; + case AF_INET6: + memcpy(buffer, &peer.s6.sin6_port, sizeof(peer.s6.sin6_port)); + memcpy(buffer + sizeof(peer.s6.sin6_port), + &peer.s6.sin6_addr, sizeof(struct in6_addr)); + break; + default: + OPENSSL_assert(0); + break; + } + + /* Calculate HMAC of buffer using the secret */ + HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH, + buffer, length, result, &resultlength); + free(buffer); + + memcpy(cookie, result, resultlength); + *cookie_len = resultlength; + + return 1; +} + +int +verify_cookie_callback(SSL * ssl, unsigned char *cookie, unsigned int cookie_len) +{ + unsigned char *buffer, result[EVP_MAX_MD_SIZE]; + unsigned int length, resultlength; + union { + struct sockaddr sa; + struct sockaddr_in s4; + struct sockaddr_in6 s6; + } peer; + + /* If secret isn't initialized yet, the cookie can't be valid */ + if (!cookie_initialized) + return 0; + + /* Read peer information */ + (void) BIO_dgram_get_peer(SSL_get_rbio(ssl), &peer); + + /* Create buffer with peer's address and port */ + length = 0; + switch (peer.sa.sa_family) { + case AF_INET: + length += sizeof(struct in_addr); + length += sizeof(peer.s4.sin_port); + break; + case AF_INET6: + length += sizeof(struct in6_addr); + length += sizeof(peer.s6.sin6_port); + break; + default: + OPENSSL_assert(0); + break; + } + buffer = malloc(length); + + if (buffer == NULL) { + BIO_printf(bio_err, "out of memory\n"); + return 0; + } + switch (peer.sa.sa_family) { + case AF_INET: + memcpy(buffer, &peer.s4.sin_port, sizeof(peer.s4.sin_port)); + memcpy(buffer + sizeof(peer.s4.sin_port), + &peer.s4.sin_addr, sizeof(struct in_addr)); + break; + case AF_INET6: + memcpy(buffer, &peer.s6.sin6_port, sizeof(peer.s6.sin6_port)); + memcpy(buffer + sizeof(peer.s6.sin6_port), + &peer.s6.sin6_addr, sizeof(struct in6_addr)); + break; + default: + OPENSSL_assert(0); + break; + } + + /* Calculate HMAC of buffer using the secret */ + HMAC(EVP_sha1(), cookie_secret, COOKIE_SECRET_LENGTH, + buffer, length, result, &resultlength); + free(buffer); + + if (cookie_len == resultlength && + memcmp(result, cookie, resultlength) == 0) + return 1; + + return 0; +} diff --git a/bin/openssl/s_client.c b/bin/openssl/s_client.c new file mode 100644 index 0000000000..4a0a832c12 --- /dev/null +++ b/bin/openssl/s_client.c @@ -0,0 +1,1501 @@ +/* $OpenBSD: s_client.c,v 1.31 2017/01/24 09:07:40 jsing Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2005 Nokia. All rights reserved. + * + * The portions of the attached software ("Contribution") is developed by + * Nokia Corporation and is licensed pursuant to the OpenSSL open source + * license. + * + * The Contribution, originally written by Mika Kousa and Pasi Eronen of + * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites + * support (see RFC 4279) to OpenSSL. + * + * No patent licenses or other rights except those expressly stated in + * the OpenSSL open source license shall be deemed granted or received + * expressly, by implication, estoppel, or otherwise. + * + * No assurances are provided by Nokia that the Contribution does not + * infringe the patent or other intellectual property rights of any third + * party or that the license provides you with all the necessary rights + * to make use of the Contribution. + * + * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN + * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA + * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY + * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR + * OTHERWISE. + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "apps.h" + +#include +#include +#include +#include +#include +#include + +#include "s_apps.h" +#include "timeouts.h" + +/*#define SSL_HOST_NAME "www.netscape.com" */ +/*#define SSL_HOST_NAME "193.118.187.102" */ +#define SSL_HOST_NAME "localhost" + + /*#define TEST_CERT "client.pem" *//* no default cert. */ + +#define BUFSIZZ 1024*8 + +static int c_nbio = 0; +static int c_Pause = 0; +static int c_debug = 0; +static int c_tlsextdebug = 0; +static int c_status_req = 0; +static int c_msg = 0; +static int c_showcerts = 0; + +static char *keymatexportlabel = NULL; +static int keymatexportlen = 20; + +static void sc_usage(void); +static void print_stuff(BIO * berr, SSL * con, int full); +static int ocsp_resp_cb(SSL * s, void *arg); +static BIO *bio_c_out = NULL; +static int c_quiet = 0; +static int c_ign_eof = 0; + + +static void +sc_usage(void) +{ + BIO_printf(bio_err, "usage: s_client args\n"); + BIO_printf(bio_err, "\n"); + BIO_printf(bio_err, " -4 - Force IPv4\n"); + BIO_printf(bio_err, " -6 - Force IPv6\n"); + BIO_printf(bio_err, " -host host - use -connect instead\n"); + BIO_printf(bio_err, " -port port - use -connect instead\n"); + BIO_printf(bio_err, " -connect host:port - who to connect to (default is %s:%s)\n", SSL_HOST_NAME, PORT_STR); + BIO_printf(bio_err, " -proxy host:port - connect to http proxy\n"); + + BIO_printf(bio_err, " -verify arg - turn on peer certificate verification\n"); + BIO_printf(bio_err, " -cert arg - certificate file to use, PEM format assumed\n"); + BIO_printf(bio_err, " -certform arg - certificate format (PEM or DER) PEM default\n"); + BIO_printf(bio_err, " -key arg - Private key file to use, in cert file if\n"); + BIO_printf(bio_err, " not specified but cert file is.\n"); + BIO_printf(bio_err, " -keyform arg - key format (PEM or DER) PEM default\n"); + BIO_printf(bio_err, " -pass arg - private key file pass phrase source\n"); + BIO_printf(bio_err, " -CApath arg - PEM format directory of CA's\n"); + BIO_printf(bio_err, " -CAfile arg - PEM format file of CA's\n"); + BIO_printf(bio_err, " -reconnect - Drop and re-make the connection with the same Session-ID\n"); + BIO_printf(bio_err, " -pause - sleep(1) after each read(2) and write(2) system call\n"); + BIO_printf(bio_err, " -showcerts - show all certificates in the chain\n"); + BIO_printf(bio_err, " -debug - extra output\n"); + BIO_printf(bio_err, " -msg - Show protocol messages\n"); + BIO_printf(bio_err, " -nbio_test - more ssl protocol testing\n"); + BIO_printf(bio_err, " -state - print the 'ssl' states\n"); + BIO_printf(bio_err, " -nbio - Run with non-blocking IO\n"); + BIO_printf(bio_err, " -crlf - convert LF from terminal into CRLF\n"); + BIO_printf(bio_err, " -quiet - no s_client output\n"); + BIO_printf(bio_err, " -ign_eof - ignore input eof (default when -quiet)\n"); + BIO_printf(bio_err, " -no_ign_eof - don't ignore input eof\n"); + BIO_printf(bio_err, " -tls1_2 - just use TLSv1.2\n"); + BIO_printf(bio_err, " -tls1_1 - just use TLSv1.1\n"); + BIO_printf(bio_err, " -tls1 - just use TLSv1\n"); + BIO_printf(bio_err, " -dtls1 - just use DTLSv1\n"); + BIO_printf(bio_err, " -mtu - set the link layer MTU\n"); + BIO_printf(bio_err, " -no_tls1_2/-no_tls1_1/-no_tls1/-no_ssl3/-no_ssl2 - turn off that protocol\n"); + BIO_printf(bio_err, " -bugs - Switch on all SSL implementation bug workarounds\n"); + BIO_printf(bio_err, " -cipher - preferred cipher to use, use the 'openssl ciphers'\n"); + BIO_printf(bio_err, " command to see what is available\n"); + BIO_printf(bio_err, " -starttls prot - use the STARTTLS command before starting TLS\n"); + BIO_printf(bio_err, " for those protocols that support it, where\n"); + BIO_printf(bio_err, " 'prot' defines which one to assume. Currently,\n"); + BIO_printf(bio_err, " only \"smtp\", \"lmtp\", \"pop3\", \"imap\", \"ftp\" and \"xmpp\"\n"); + BIO_printf(bio_err, " are supported.\n"); + BIO_printf(bio_err, " -xmpphost host - connect to this virtual host on the xmpp server\n"); + BIO_printf(bio_err, " -sess_out arg - file to write SSL session to\n"); + BIO_printf(bio_err, " -sess_in arg - file to read SSL session from\n"); + BIO_printf(bio_err, " -servername host - Set TLS extension servername in ClientHello\n"); + BIO_printf(bio_err, " -tlsextdebug - hex dump of all TLS extensions received\n"); + BIO_printf(bio_err, " -status - request certificate status from server\n"); + BIO_printf(bio_err, " -no_ticket - disable use of RFC4507bis session tickets\n"); + BIO_printf(bio_err, " -nextprotoneg arg - enable NPN extension, considering named protocols supported (comma-separated list)\n"); + BIO_printf(bio_err, " -alpn arg - enable ALPN extension, considering named protocols supported (comma-separated list)\n"); + BIO_printf(bio_err, " -groups arg - specify EC curve groups (colon-separated list)\n"); +#ifndef OPENSSL_NO_SRTP + BIO_printf(bio_err, " -use_srtp profiles - Offer SRTP key management with a colon-separated profile list\n"); +#endif + BIO_printf(bio_err, " -keymatexport label - Export keying material using label\n"); + BIO_printf(bio_err, " -keymatexportlen len - Export len bytes of keying material (default 20)\n"); +} + + +/* This is a context that we pass to callbacks */ +typedef struct tlsextctx_st { + BIO *biodebug; + int ack; +} tlsextctx; + + +static int +ssl_servername_cb(SSL * s, int *ad, void *arg) +{ + tlsextctx *p = (tlsextctx *) arg; + const char *hn = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); + if (SSL_get_servername_type(s) != -1) + p->ack = !SSL_session_reused(s) && hn != NULL; + else + BIO_printf(bio_err, "Can't use SSL_get_servername\n"); + + return SSL_TLSEXT_ERR_OK; +} + +#ifndef OPENSSL_NO_SRTP +char *srtp_profiles = NULL; +#endif + +/* This the context that we pass to next_proto_cb */ +typedef struct tlsextnextprotoctx_st { + unsigned char *data; + unsigned short len; + int status; +} tlsextnextprotoctx; + +static tlsextnextprotoctx next_proto; + +static int +next_proto_cb(SSL * s, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg) +{ + tlsextnextprotoctx *ctx = arg; + + if (!c_quiet) { + /* We can assume that |in| is syntactically valid. */ + unsigned i; + BIO_printf(bio_c_out, "Protocols advertised by server: "); + for (i = 0; i < inlen;) { + if (i) + BIO_write(bio_c_out, ", ", 2); + BIO_write(bio_c_out, &in[i + 1], in[i]); + i += in[i] + 1; + } + BIO_write(bio_c_out, "\n", 1); + } + ctx->status = SSL_select_next_proto(out, outlen, in, inlen, ctx->data, ctx->len); + return SSL_TLSEXT_ERR_OK; +} + +enum { + PROTO_OFF = 0, + PROTO_SMTP, + PROTO_LMTP, + PROTO_POP3, + PROTO_IMAP, + PROTO_FTP, + PROTO_XMPP +}; + +int +s_client_main(int argc, char **argv) +{ + unsigned int off = 0, clr = 0; + SSL *con = NULL; + int s, k, state = 0, af = AF_UNSPEC; + char *cbuf = NULL, *sbuf = NULL, *mbuf = NULL; + int cbuf_len, cbuf_off; + int sbuf_len, sbuf_off; + char *port = PORT_STR; + int full_log = 1; + char *host = SSL_HOST_NAME; + char *xmpphost = NULL; + char *proxy = NULL, *connect = NULL; + char *cert_file = NULL, *key_file = NULL; + int cert_format = FORMAT_PEM, key_format = FORMAT_PEM; + char *passarg = NULL, *pass = NULL; + X509 *cert = NULL; + EVP_PKEY *key = NULL; + char *CApath = NULL, *CAfile = NULL, *cipher = NULL; + int reconnect = 0, badop = 0, verify = SSL_VERIFY_NONE, bugs = 0; + int crlf = 0; + int write_tty, read_tty, write_ssl, read_ssl, tty_on, ssl_pending; + SSL_CTX *ctx = NULL; + int ret = 1, in_init = 1, i, nbio_test = 0; + int starttls_proto = PROTO_OFF; + int prexit = 0; + X509_VERIFY_PARAM *vpm = NULL; + int badarg = 0; + const SSL_METHOD *meth = NULL; + int socket_type = SOCK_STREAM; + BIO *sbio; + int mbuf_len = 0; + struct timeval timeout; + const char *errstr = NULL; + char *servername = NULL; + tlsextctx tlsextcbp = + {NULL, 0}; + const char *next_proto_neg_in = NULL; + const char *alpn_in = NULL; + const char *groups_in = NULL; + char *sess_in = NULL; + char *sess_out = NULL; + struct sockaddr peer; + int peerlen = sizeof(peer); + int enable_timeouts = 0; + long socket_mtu = 0; + + if (single_execution) { + if (pledge("stdio cpath wpath rpath inet dns tty", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + meth = SSLv23_client_method(); + + c_Pause = 0; + c_quiet = 0; + c_ign_eof = 0; + c_debug = 0; + c_msg = 0; + c_showcerts = 0; + + if (((cbuf = malloc(BUFSIZZ)) == NULL) || + ((sbuf = malloc(BUFSIZZ)) == NULL) || + ((mbuf = malloc(BUFSIZZ + 1)) == NULL)) { /* NUL byte */ + BIO_printf(bio_err, "out of memory\n"); + goto end; + } + verify_depth = 0; + c_nbio = 0; + + argc--; + argv++; + while (argc >= 1) { + if (strcmp(*argv, "-host") == 0) { + if (--argc < 1) + goto bad; + host = *(++argv); + } else if (strcmp(*argv, "-port") == 0) { + if (--argc < 1) + goto bad; + port = *(++argv); + if (port == NULL || *port == '\0') + goto bad; + } else if (strcmp(*argv, "-connect") == 0) { + if (--argc < 1) + goto bad; + connect = *(++argv); + } else if (strcmp(*argv, "-proxy") == 0) { + if (--argc < 1) + goto bad; + proxy = *(++argv); + } else if (strcmp(*argv,"-xmpphost") == 0) { + if (--argc < 1) + goto bad; + xmpphost= *(++argv); + } else if (strcmp(*argv, "-verify") == 0) { + verify = SSL_VERIFY_PEER; + if (--argc < 1) + goto bad; + verify_depth = strtonum(*(++argv), 0, INT_MAX, &errstr); + if (errstr) + goto bad; + BIO_printf(bio_err, "verify depth is %d\n", verify_depth); + } else if (strcmp(*argv, "-cert") == 0) { + if (--argc < 1) + goto bad; + cert_file = *(++argv); + } else if (strcmp(*argv, "-sess_out") == 0) { + if (--argc < 1) + goto bad; + sess_out = *(++argv); + } else if (strcmp(*argv, "-sess_in") == 0) { + if (--argc < 1) + goto bad; + sess_in = *(++argv); + } else if (strcmp(*argv, "-certform") == 0) { + if (--argc < 1) + goto bad; + cert_format = str2fmt(*(++argv)); + } else if (args_verify(&argv, &argc, &badarg, bio_err, &vpm)) { + if (badarg) + goto bad; + continue; + } else if (strcmp(*argv, "-verify_return_error") == 0) + verify_return_error = 1; + else if (strcmp(*argv, "-prexit") == 0) + prexit = 1; + else if (strcmp(*argv, "-crlf") == 0) + crlf = 1; + else if (strcmp(*argv, "-quiet") == 0) { + c_quiet = 1; + c_ign_eof = 1; + } else if (strcmp(*argv, "-ign_eof") == 0) + c_ign_eof = 1; + else if (strcmp(*argv, "-no_ign_eof") == 0) + c_ign_eof = 0; + else if (strcmp(*argv, "-pause") == 0) + c_Pause = 1; + else if (strcmp(*argv, "-debug") == 0) + c_debug = 1; + else if (strcmp(*argv, "-tlsextdebug") == 0) + c_tlsextdebug = 1; + else if (strcmp(*argv, "-status") == 0) + c_status_req = 1; + else if (strcmp(*argv, "-msg") == 0) + c_msg = 1; + else if (strcmp(*argv, "-showcerts") == 0) + c_showcerts = 1; + else if (strcmp(*argv, "-nbio_test") == 0) + nbio_test = 1; + else if (strcmp(*argv, "-state") == 0) + state = 1; + else if (strcmp(*argv, "-tls1_2") == 0) + meth = TLSv1_2_client_method(); + else if (strcmp(*argv, "-tls1_1") == 0) + meth = TLSv1_1_client_method(); + else if (strcmp(*argv, "-tls1") == 0) + meth = TLSv1_client_method(); +#ifndef OPENSSL_NO_DTLS1 + else if (strcmp(*argv, "-dtls1") == 0) { + meth = DTLSv1_client_method(); + socket_type = SOCK_DGRAM; + } else if (strcmp(*argv, "-timeout") == 0) + enable_timeouts = 1; + else if (strcmp(*argv, "-mtu") == 0) { + if (--argc < 1) + goto bad; + socket_mtu = strtonum(*(++argv), 0, LONG_MAX, &errstr); + if (errstr) + goto bad; + } +#endif + else if (strcmp(*argv, "-bugs") == 0) + bugs = 1; + else if (strcmp(*argv, "-keyform") == 0) { + if (--argc < 1) + goto bad; + key_format = str2fmt(*(++argv)); + } else if (strcmp(*argv, "-pass") == 0) { + if (--argc < 1) + goto bad; + passarg = *(++argv); + } else if (strcmp(*argv, "-key") == 0) { + if (--argc < 1) + goto bad; + key_file = *(++argv); + } else if (strcmp(*argv, "-reconnect") == 0) { + reconnect = 5; + } else if (strcmp(*argv, "-CApath") == 0) { + if (--argc < 1) + goto bad; + CApath = *(++argv); + } else if (strcmp(*argv, "-CAfile") == 0) { + if (--argc < 1) + goto bad; + CAfile = *(++argv); + } else if (strcmp(*argv, "-no_tls1_2") == 0) + off |= SSL_OP_NO_TLSv1_2; + else if (strcmp(*argv, "-no_tls1_1") == 0) + off |= SSL_OP_NO_TLSv1_1; + else if (strcmp(*argv, "-no_tls1") == 0) + off |= SSL_OP_NO_TLSv1; + else if (strcmp(*argv, "-no_ssl3") == 0) + off |= SSL_OP_NO_SSLv3; + else if (strcmp(*argv, "-no_ssl2") == 0) + off |= SSL_OP_NO_SSLv2; + else if (strcmp(*argv, "-no_comp") == 0) { + off |= SSL_OP_NO_COMPRESSION; + } else if (strcmp(*argv, "-no_ticket") == 0) { + off |= SSL_OP_NO_TICKET; + } else if (strcmp(*argv, "-nextprotoneg") == 0) { + if (--argc < 1) + goto bad; + next_proto_neg_in = *(++argv); + } else if (strcmp(*argv, "-alpn") == 0) { + if (--argc < 1) + goto bad; + alpn_in = *(++argv); + } else if (strcmp(*argv, "-groups") == 0) { + if (--argc < 1) + goto bad; + groups_in = *(++argv); + } else if (strcmp(*argv, "-serverpref") == 0) + off |= SSL_OP_CIPHER_SERVER_PREFERENCE; + else if (strcmp(*argv, "-legacy_renegotiation") == 0) + ; /* no-op */ + else if (strcmp(*argv, "-legacy_server_connect") == 0) { + off |= SSL_OP_LEGACY_SERVER_CONNECT; + } else if (strcmp(*argv, "-no_legacy_server_connect") == 0) { + clr |= SSL_OP_LEGACY_SERVER_CONNECT; + } else if (strcmp(*argv, "-cipher") == 0) { + if (--argc < 1) + goto bad; + cipher = *(++argv); + } + else if (strcmp(*argv, "-nbio") == 0) { + c_nbio = 1; + } + else if (strcmp(*argv, "-starttls") == 0) { + if (--argc < 1) + goto bad; + ++argv; + if (strcmp(*argv, "smtp") == 0) + starttls_proto = PROTO_SMTP; + else if (strcmp(*argv, "lmtp") == 0) + starttls_proto = PROTO_LMTP; + else if (strcmp(*argv, "pop3") == 0) + starttls_proto = PROTO_POP3; + else if (strcmp(*argv, "imap") == 0) + starttls_proto = PROTO_IMAP; + else if (strcmp(*argv, "ftp") == 0) + starttls_proto = PROTO_FTP; + else if (strcmp(*argv, "xmpp") == 0) + starttls_proto = PROTO_XMPP; + else + goto bad; + } + else if (strcmp(*argv, "-4") == 0) { + af = AF_INET; + } else if (strcmp(*argv, "-6") == 0) { + af = AF_INET6; + } + else if (strcmp(*argv, "-servername") == 0) { + if (--argc < 1) + goto bad; + servername = *(++argv); + /* meth=TLSv1_client_method(); */ + } +#ifndef OPENSSL_NO_SRTP + else if (strcmp(*argv, "-use_srtp") == 0) { + if (--argc < 1) + goto bad; + srtp_profiles = *(++argv); + } +#endif + else if (strcmp(*argv, "-keymatexport") == 0) { + if (--argc < 1) + goto bad; + keymatexportlabel = *(++argv); + } else if (strcmp(*argv, "-keymatexportlen") == 0) { + if (--argc < 1) + goto bad; + keymatexportlen = strtonum(*(++argv), 1, INT_MAX, &errstr); + if (errstr) + goto bad; + } else { + BIO_printf(bio_err, "unknown option %s\n", *argv); + badop = 1; + break; + } + argc--; + argv++; + } + if (proxy != NULL) { + if (!extract_host_port(proxy, &host, NULL, &port)) + goto bad; + if (connect == NULL) + connect = SSL_HOST_NAME; + } else if (connect != NULL) { + if (!extract_host_port(connect, &host, NULL, &port)) + goto bad; + } + if (badop) { +bad: + if (errstr) + BIO_printf(bio_err, "invalid argument %s: %s\n", + *argv, errstr); + else + sc_usage(); + goto end; + } + + next_proto.status = -1; + if (next_proto_neg_in) { + next_proto.data = next_protos_parse(&next_proto.len, next_proto_neg_in); + if (next_proto.data == NULL) { + BIO_printf(bio_err, "Error parsing -nextprotoneg argument\n"); + goto end; + } + } else + next_proto.data = NULL; + + if (!app_passwd(bio_err, passarg, NULL, &pass, NULL)) { + BIO_printf(bio_err, "Error getting password\n"); + goto end; + } + if (key_file == NULL) + key_file = cert_file; + + + if (key_file) { + + key = load_key(bio_err, key_file, key_format, 0, pass, + "client certificate private key file"); + if (!key) { + ERR_print_errors(bio_err); + goto end; + } + } + if (cert_file) { + cert = load_cert(bio_err, cert_file, cert_format, + NULL, "client certificate file"); + + if (!cert) { + ERR_print_errors(bio_err); + goto end; + } + } + if (bio_c_out == NULL) { + if (c_quiet && !c_debug && !c_msg) { + bio_c_out = BIO_new(BIO_s_null()); + } else { + if (bio_c_out == NULL) + bio_c_out = BIO_new_fp(stdout, BIO_NOCLOSE); + } + } + + ctx = SSL_CTX_new(meth); + if (ctx == NULL) { + ERR_print_errors(bio_err); + goto end; + } + if (vpm) + SSL_CTX_set1_param(ctx, vpm); + +#ifndef OPENSSL_NO_SRTP + if (srtp_profiles != NULL) + SSL_CTX_set_tlsext_use_srtp(ctx, srtp_profiles); +#endif + if (bugs) + SSL_CTX_set_options(ctx, SSL_OP_ALL | off); + else + SSL_CTX_set_options(ctx, off); + + if (clr) + SSL_CTX_clear_options(ctx, clr); + /* + * DTLS: partial reads end up discarding unread UDP bytes :-( Setting + * read ahead solves this problem. + */ + if (socket_type == SOCK_DGRAM) + SSL_CTX_set_read_ahead(ctx, 1); + + if (next_proto.data) + SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &next_proto); + if (alpn_in) { + unsigned short alpn_len; + unsigned char *alpn = next_protos_parse(&alpn_len, alpn_in); + + if (alpn == NULL) { + BIO_printf(bio_err, "Error parsing -alpn argument\n"); + goto end; + } + SSL_CTX_set_alpn_protos(ctx, alpn, alpn_len); + free(alpn); + } + if (groups_in != NULL) { + if (SSL_CTX_set1_groups_list(ctx, groups_in) != 1) { + BIO_printf(bio_err, "Failed to set groups '%s'\n", + groups_in); + goto end; + } + } + + if (state) + SSL_CTX_set_info_callback(ctx, apps_ssl_info_callback); + if (cipher != NULL) + if (!SSL_CTX_set_cipher_list(ctx, cipher)) { + BIO_printf(bio_err, "error setting cipher list\n"); + ERR_print_errors(bio_err); + goto end; + } + + SSL_CTX_set_verify(ctx, verify, verify_callback); + if (!set_cert_key_stuff(ctx, cert, key)) + goto end; + + if ((CAfile || CApath) + && !SSL_CTX_load_verify_locations(ctx, CAfile, CApath)) + ERR_print_errors(bio_err); + + if (!SSL_CTX_set_default_verify_paths(ctx)) + ERR_print_errors(bio_err); + + if (servername != NULL) { + tlsextcbp.biodebug = bio_err; + SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb); + SSL_CTX_set_tlsext_servername_arg(ctx, &tlsextcbp); + } + + con = SSL_new(ctx); + if (sess_in) { + SSL_SESSION *sess; + BIO *stmp = BIO_new_file(sess_in, "r"); + if (!stmp) { + BIO_printf(bio_err, "Can't open session file %s\n", + sess_in); + ERR_print_errors(bio_err); + goto end; + } + sess = PEM_read_bio_SSL_SESSION(stmp, NULL, 0, NULL); + BIO_free(stmp); + if (!sess) { + BIO_printf(bio_err, "Can't open session file %s\n", + sess_in); + ERR_print_errors(bio_err); + goto end; + } + SSL_set_session(con, sess); + SSL_SESSION_free(sess); + } + if (servername != NULL) { + if (!SSL_set_tlsext_host_name(con, servername)) { + BIO_printf(bio_err, "Unable to set TLS servername extension.\n"); + ERR_print_errors(bio_err); + goto end; + } + } +/* SSL_set_cipher_list(con,"RC4-MD5"); */ + +re_start: + + if (init_client(&s, host, port, socket_type, af) == 0) { + BIO_printf(bio_err, "connect:errno=%d\n", errno); + goto end; + } + BIO_printf(bio_c_out, "CONNECTED(%08X)\n", s); + + if (c_nbio) { + if (!c_quiet) + BIO_printf(bio_c_out, "turning on non blocking io\n"); + if (!BIO_socket_nbio(s, 1)) { + ERR_print_errors(bio_err); + goto end; + } + } + if (c_Pause & 0x01) + SSL_set_debug(con, 1); + + if (SSL_version(con) == DTLS1_VERSION) { + + sbio = BIO_new_dgram(s, BIO_NOCLOSE); + if (getsockname(s, &peer, (void *) &peerlen) < 0) { + BIO_printf(bio_err, "getsockname:errno=%d\n", + errno); + shutdown(s, SHUT_RD); + close(s); + goto end; + } + (void) BIO_ctrl_set_connected(sbio, 1, &peer); + + if (enable_timeouts) { + timeout.tv_sec = 0; + timeout.tv_usec = DGRAM_RCV_TIMEOUT; + BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout); + + timeout.tv_sec = 0; + timeout.tv_usec = DGRAM_SND_TIMEOUT; + BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout); + } + if (socket_mtu > 28) { + SSL_set_options(con, SSL_OP_NO_QUERY_MTU); + SSL_set_mtu(con, socket_mtu - 28); + } else + /* want to do MTU discovery */ + BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL); + } else + sbio = BIO_new_socket(s, BIO_NOCLOSE); + + if (nbio_test) { + BIO *test; + + test = BIO_new(BIO_f_nbio_test()); + sbio = BIO_push(test, sbio); + } + if (c_debug) { + SSL_set_debug(con, 1); + BIO_set_callback(sbio, bio_dump_callback); + BIO_set_callback_arg(sbio, (char *) bio_c_out); + } + if (c_msg) { + SSL_set_msg_callback(con, msg_cb); + SSL_set_msg_callback_arg(con, bio_c_out); + } + if (c_tlsextdebug) { + SSL_set_tlsext_debug_callback(con, tlsext_cb); + SSL_set_tlsext_debug_arg(con, bio_c_out); + } + if (c_status_req) { + SSL_set_tlsext_status_type(con, TLSEXT_STATUSTYPE_ocsp); + SSL_CTX_set_tlsext_status_cb(ctx, ocsp_resp_cb); + SSL_CTX_set_tlsext_status_arg(ctx, bio_c_out); + } + + SSL_set_bio(con, sbio, sbio); + SSL_set_connect_state(con); + + /* ok, lets connect */ + read_tty = 1; + write_tty = 0; + tty_on = 0; + read_ssl = 1; + write_ssl = 1; + + cbuf_len = 0; + cbuf_off = 0; + sbuf_len = 0; + sbuf_off = 0; + + /* This is an ugly hack that does a lot of assumptions */ + /* + * We do have to handle multi-line responses which may come in a + * single packet or not. We therefore have to use BIO_gets() which + * does need a buffering BIO. So during the initial chitchat we do + * push a buffering BIO into the chain that is removed again later on + * to not disturb the rest of the s_client operation. + */ + if (starttls_proto == PROTO_SMTP || starttls_proto == PROTO_LMTP) { + int foundit = 0; + BIO *fbio = BIO_new(BIO_f_buffer()); + BIO_push(fbio, sbio); + /* wait for multi-line response to end from SMTP */ + do { + mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); + } + while (mbuf_len > 3 && mbuf[3] == '-'); + /* STARTTLS command requires EHLO... */ + BIO_printf(fbio, "%cHLO openssl.client.net\r\n", + starttls_proto == PROTO_SMTP ? 'E' : 'L'); + (void) BIO_flush(fbio); + /* wait for multi-line response to end EHLO SMTP response */ + do { + mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); + if (strstr(mbuf, "STARTTLS")) + foundit = 1; + } + while (mbuf_len > 3 && mbuf[3] == '-'); + (void) BIO_flush(fbio); + BIO_pop(fbio); + BIO_free(fbio); + if (!foundit) + BIO_printf(bio_err, + "didn't found starttls in server response," + " try anyway...\n"); + BIO_printf(sbio, "STARTTLS\r\n"); + BIO_read(sbio, sbuf, BUFSIZZ); + } else if (starttls_proto == PROTO_POP3) { + mbuf_len = BIO_read(sbio, mbuf, BUFSIZZ); + if (mbuf_len == -1) { + BIO_printf(bio_err, "BIO_read failed\n"); + goto end; + } + BIO_printf(sbio, "STLS\r\n"); + BIO_read(sbio, sbuf, BUFSIZZ); + } else if (starttls_proto == PROTO_IMAP) { + int foundit = 0; + BIO *fbio = BIO_new(BIO_f_buffer()); + BIO_push(fbio, sbio); + BIO_gets(fbio, mbuf, BUFSIZZ); + /* STARTTLS command requires CAPABILITY... */ + BIO_printf(fbio, ". CAPABILITY\r\n"); + (void) BIO_flush(fbio); + /* wait for multi-line CAPABILITY response */ + do { + mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); + if (strstr(mbuf, "STARTTLS")) + foundit = 1; + } + while (mbuf_len > 3 && mbuf[0] != '.'); + (void) BIO_flush(fbio); + BIO_pop(fbio); + BIO_free(fbio); + if (!foundit) + BIO_printf(bio_err, + "didn't found STARTTLS in server response," + " try anyway...\n"); + BIO_printf(sbio, ". STARTTLS\r\n"); + BIO_read(sbio, sbuf, BUFSIZZ); + } else if (starttls_proto == PROTO_FTP) { + BIO *fbio = BIO_new(BIO_f_buffer()); + BIO_push(fbio, sbio); + /* wait for multi-line response to end from FTP */ + do { + mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); + } + while (mbuf_len > 3 && mbuf[3] == '-'); + (void) BIO_flush(fbio); + BIO_pop(fbio); + BIO_free(fbio); + BIO_printf(sbio, "AUTH TLS\r\n"); + BIO_read(sbio, sbuf, BUFSIZZ); + } else if (starttls_proto == PROTO_XMPP) { + int seen = 0; + BIO_printf(sbio, "", xmpphost ? xmpphost : host); + seen = BIO_read(sbio, mbuf, BUFSIZZ); + + if (seen <= 0) + goto shut; + + mbuf[seen] = 0; + while (!strstr(mbuf, ""); + seen = BIO_read(sbio, sbuf, BUFSIZZ); + sbuf[seen] = 0; + if (!strstr(sbuf, " 0) + full_log--; + + if (starttls_proto) { + BIO_write(bio_err, mbuf, mbuf_len); + /* We don't need to know any more */ + starttls_proto = PROTO_OFF; + } + if (reconnect) { + reconnect--; + BIO_printf(bio_c_out, "drop connection and then reconnect\n"); + SSL_shutdown(con); + SSL_set_connect_state(con); + shutdown(SSL_get_fd(con), SHUT_RD); + close(SSL_get_fd(con)); + goto re_start; + } + } + } + + ssl_pending = read_ssl && SSL_pending(con); + + pfd[0].fd = -1; + pfd[1].fd = -1; + if (!ssl_pending) { + if (tty_on) { + if (read_tty) { + pfd[0].fd = fileno(stdin); + pfd[0].events = POLLIN; + } + if (write_tty) { + pfd[1].fd = fileno(stdout); + pfd[1].events = POLLOUT; + } + } + + pfd[2].fd = SSL_get_fd(con); + pfd[2].events = 0; + if (read_ssl) + pfd[2].events |= POLLIN; + if (write_ssl) + pfd[2].events |= POLLOUT; + +/* printf("mode tty(%d %d%d) ssl(%d%d)\n", + tty_on,read_tty,write_tty,read_ssl,write_ssl);*/ + + i = poll(pfd, 3, ptimeout); + if (i < 0) { + BIO_printf(bio_err, "bad select %d\n", + errno); + goto shut; + /* goto end; */ + } + } + if ((SSL_version(con) == DTLS1_VERSION) && DTLSv1_handle_timeout(con) > 0) { + BIO_printf(bio_err, "TIMEOUT occured\n"); + } + if (!ssl_pending && (pfd[2].revents & (POLLOUT|POLLERR|POLLNVAL))) { + if (pfd[2].revents & (POLLERR|POLLNVAL)) { + BIO_printf(bio_err, "poll error"); + goto shut; + } + k = SSL_write(con, &(cbuf[cbuf_off]), + (unsigned int) cbuf_len); + switch (SSL_get_error(con, k)) { + case SSL_ERROR_NONE: + cbuf_off += k; + cbuf_len -= k; + if (k <= 0) + goto end; + /* we have done a write(con,NULL,0); */ + if (cbuf_len <= 0) { + read_tty = 1; + write_ssl = 0; + } else { /* if (cbuf_len > 0) */ + read_tty = 0; + write_ssl = 1; + } + break; + case SSL_ERROR_WANT_WRITE: + BIO_printf(bio_c_out, "write W BLOCK\n"); + write_ssl = 1; + read_tty = 0; + break; + case SSL_ERROR_WANT_READ: + BIO_printf(bio_c_out, "write R BLOCK\n"); + write_tty = 0; + read_ssl = 1; + write_ssl = 0; + break; + case SSL_ERROR_WANT_X509_LOOKUP: + BIO_printf(bio_c_out, "write X BLOCK\n"); + break; + case SSL_ERROR_ZERO_RETURN: + if (cbuf_len != 0) { + BIO_printf(bio_c_out, "shutdown\n"); + ret = 0; + goto shut; + } else { + read_tty = 1; + write_ssl = 0; + break; + } + + case SSL_ERROR_SYSCALL: + if ((k != 0) || (cbuf_len != 0)) { + BIO_printf(bio_err, "write:errno=%d\n", + errno); + goto shut; + } else { + read_tty = 1; + write_ssl = 0; + } + break; + case SSL_ERROR_SSL: + ERR_print_errors(bio_err); + goto shut; + } + } else if (!ssl_pending && + (pfd[1].revents & (POLLOUT|POLLERR|POLLNVAL))) { + if (pfd[1].revents & (POLLERR|POLLNVAL)) { + BIO_printf(bio_err, "poll error"); + goto shut; + } + i = write(fileno(stdout), &(sbuf[sbuf_off]), sbuf_len); + + if (i <= 0) { + BIO_printf(bio_c_out, "DONE\n"); + ret = 0; + goto shut; + /* goto end; */ + } + sbuf_len -= i; + sbuf_off += i; + if (sbuf_len <= 0) { + read_ssl = 1; + write_tty = 0; + } + } else if (ssl_pending || (pfd[2].revents & (POLLIN|POLLHUP))) { +#ifdef RENEG + { + static int iiii; + if (++iiii == 52) { + SSL_renegotiate(con); + iiii = 0; + } + } +#endif + k = SSL_read(con, sbuf, 1024 /* BUFSIZZ */ ); + + switch (SSL_get_error(con, k)) { + case SSL_ERROR_NONE: + if (k <= 0) + goto end; + sbuf_off = 0; + sbuf_len = k; + + read_ssl = 0; + write_tty = 1; + break; + case SSL_ERROR_WANT_WRITE: + BIO_printf(bio_c_out, "read W BLOCK\n"); + write_ssl = 1; + read_tty = 0; + break; + case SSL_ERROR_WANT_READ: + BIO_printf(bio_c_out, "read R BLOCK\n"); + write_tty = 0; + read_ssl = 1; + if ((read_tty == 0) && (write_ssl == 0)) + write_ssl = 1; + break; + case SSL_ERROR_WANT_X509_LOOKUP: + BIO_printf(bio_c_out, "read X BLOCK\n"); + break; + case SSL_ERROR_SYSCALL: + ret = errno; + BIO_printf(bio_err, "read:errno=%d\n", ret); + goto shut; + case SSL_ERROR_ZERO_RETURN: + BIO_printf(bio_c_out, "closed\n"); + ret = 0; + goto shut; + case SSL_ERROR_SSL: + ERR_print_errors(bio_err); + goto shut; + /* break; */ + } + } else if (pfd[0].revents) { + if (pfd[0].revents & (POLLERR|POLLNVAL)) { + BIO_printf(bio_err, "poll error"); + goto shut; + } + if (crlf) { + int j, lf_num; + + i = read(fileno(stdin), cbuf, BUFSIZZ / 2); + lf_num = 0; + /* both loops are skipped when i <= 0 */ + for (j = 0; j < i; j++) + if (cbuf[j] == '\n') + lf_num++; + for (j = i - 1; j >= 0; j--) { + cbuf[j + lf_num] = cbuf[j]; + if (cbuf[j] == '\n') { + lf_num--; + i++; + cbuf[j + lf_num] = '\r'; + } + } + assert(lf_num == 0); + } else + i = read(fileno(stdin), cbuf, BUFSIZZ); + + if ((!c_ign_eof) && ((i <= 0) || (cbuf[0] == 'Q'))) { + BIO_printf(bio_err, "DONE\n"); + ret = 0; + goto shut; + } + if ((!c_ign_eof) && (cbuf[0] == 'R')) { + BIO_printf(bio_err, "RENEGOTIATING\n"); + SSL_renegotiate(con); + cbuf_len = 0; + } else { + cbuf_len = i; + cbuf_off = 0; + } + + write_ssl = 1; + read_tty = 0; + } + } + + ret = 0; +shut: + if (in_init) + print_stuff(bio_c_out, con, full_log); + SSL_shutdown(con); + shutdown(SSL_get_fd(con), SHUT_RD); + close(SSL_get_fd(con)); +end: + if (con != NULL) { + if (prexit != 0) + print_stuff(bio_c_out, con, 1); + SSL_free(con); + } + free(next_proto.data); + if (ctx != NULL) + SSL_CTX_free(ctx); + if (cert) + X509_free(cert); + if (key) + EVP_PKEY_free(key); + free(pass); + if (vpm) + X509_VERIFY_PARAM_free(vpm); + if (cbuf != NULL) { + explicit_bzero(cbuf, BUFSIZZ); + free(cbuf); + } + if (sbuf != NULL) { + explicit_bzero(sbuf, BUFSIZZ); + free(sbuf); + } + if (mbuf != NULL) { + explicit_bzero(mbuf, BUFSIZZ); + free(mbuf); + } + if (bio_c_out != NULL) { + BIO_free(bio_c_out); + bio_c_out = NULL; + } + + return (ret); +} + + +static void +print_stuff(BIO * bio, SSL * s, int full) +{ + X509 *peer = NULL; + char *p; + static const char *space = " "; + char buf[BUFSIZ]; + STACK_OF(X509) * sk; + STACK_OF(X509_NAME) * sk2; + const SSL_CIPHER *c; + X509_NAME *xn; + int j, i; + unsigned char *exportedkeymat; + + if (full) { + int got_a_chain = 0; + + sk = SSL_get_peer_cert_chain(s); + if (sk != NULL) { + got_a_chain = 1; /* we don't have it for SSL2 + * (yet) */ + + BIO_printf(bio, "---\nCertificate chain\n"); + for (i = 0; i < sk_X509_num(sk); i++) { + X509_NAME_oneline(X509_get_subject_name( + sk_X509_value(sk, i)), buf, sizeof buf); + BIO_printf(bio, "%2d s:%s\n", i, buf); + X509_NAME_oneline(X509_get_issuer_name( + sk_X509_value(sk, i)), buf, sizeof buf); + BIO_printf(bio, " i:%s\n", buf); + if (c_showcerts) + PEM_write_bio_X509(bio, sk_X509_value(sk, i)); + } + } + BIO_printf(bio, "---\n"); + peer = SSL_get_peer_certificate(s); + if (peer != NULL) { + BIO_printf(bio, "Server certificate\n"); + if (!(c_showcerts && got_a_chain)) /* Redundant if we + * showed the whole + * chain */ + PEM_write_bio_X509(bio, peer); + X509_NAME_oneline(X509_get_subject_name(peer), + buf, sizeof buf); + BIO_printf(bio, "subject=%s\n", buf); + X509_NAME_oneline(X509_get_issuer_name(peer), + buf, sizeof buf); + BIO_printf(bio, "issuer=%s\n", buf); + } else + BIO_printf(bio, "no peer certificate available\n"); + + sk2 = SSL_get_client_CA_list(s); + if ((sk2 != NULL) && (sk_X509_NAME_num(sk2) > 0)) { + BIO_printf(bio, "---\nAcceptable client certificate CA names\n"); + for (i = 0; i < sk_X509_NAME_num(sk2); i++) { + xn = sk_X509_NAME_value(sk2, i); + X509_NAME_oneline(xn, buf, sizeof(buf)); + BIO_write(bio, buf, strlen(buf)); + BIO_write(bio, "\n", 1); + } + } else { + BIO_printf(bio, "---\nNo client certificate CA names sent\n"); + } + p = SSL_get_shared_ciphers(s, buf, sizeof buf); + if (p != NULL) { + /* + * This works only for SSL 2. In later protocol + * versions, the client does not know what other + * ciphers (in addition to the one to be used in the + * current connection) the server supports. + */ + + BIO_printf(bio, "---\nCiphers common between both SSL endpoints:\n"); + j = i = 0; + while (*p) { + if (*p == ':') { + BIO_write(bio, space, 15 - j % 25); + i++; + j = 0; + BIO_write(bio, ((i % 3) ? " " : "\n"), 1); + } else { + BIO_write(bio, p, 1); + j++; + } + p++; + } + BIO_write(bio, "\n", 1); + } + + ssl_print_tmp_key(bio, s); + + BIO_printf(bio, "---\nSSL handshake has read %ld bytes and written %ld bytes\n", + BIO_number_read(SSL_get_rbio(s)), + BIO_number_written(SSL_get_wbio(s))); + } + BIO_printf(bio, (SSL_cache_hit(s) ? "---\nReused, " : "---\nNew, ")); + c = SSL_get_current_cipher(s); + BIO_printf(bio, "%s, Cipher is %s\n", + SSL_CIPHER_get_version(c), + SSL_CIPHER_get_name(c)); + if (peer != NULL) { + EVP_PKEY *pktmp; + pktmp = X509_get_pubkey(peer); + BIO_printf(bio, "Server public key is %d bit\n", + EVP_PKEY_bits(pktmp)); + EVP_PKEY_free(pktmp); + } + BIO_printf(bio, "Secure Renegotiation IS%s supported\n", + SSL_get_secure_renegotiation_support(s) ? "" : " NOT"); + + /* Compression is not supported and will always be none. */ + BIO_printf(bio, "Compression: NONE\n"); + BIO_printf(bio, "Expansion: NONE\n"); + +#ifdef SSL_DEBUG + { + /* Print out local port of connection: useful for debugging */ + int sock; + struct sockaddr_in ladd; + socklen_t ladd_size = sizeof(ladd); + sock = SSL_get_fd(s); + getsockname(sock, (struct sockaddr *) & ladd, &ladd_size); + BIO_printf(bio_c_out, "LOCAL PORT is %u\n", ntohs(ladd.sin_port)); + } +#endif + + if (next_proto.status != -1) { + const unsigned char *proto; + unsigned int proto_len; + SSL_get0_next_proto_negotiated(s, &proto, &proto_len); + BIO_printf(bio, "Next protocol: (%d) ", next_proto.status); + BIO_write(bio, proto, proto_len); + BIO_write(bio, "\n", 1); + } + { + const unsigned char *proto; + unsigned int proto_len; + SSL_get0_alpn_selected(s, &proto, &proto_len); + if (proto_len > 0) { + BIO_printf(bio, "ALPN protocol: "); + BIO_write(bio, proto, proto_len); + BIO_write(bio, "\n", 1); + } else + BIO_printf(bio, "No ALPN negotiated\n"); + } + +#ifndef OPENSSL_NO_SRTP + { + SRTP_PROTECTION_PROFILE *srtp_profile = SSL_get_selected_srtp_profile(s); + + if (srtp_profile) + BIO_printf(bio, "SRTP Extension negotiated, profile=%s\n", + srtp_profile->name); + } +#endif + + SSL_SESSION_print(bio, SSL_get_session(s)); + if (keymatexportlabel != NULL) { + BIO_printf(bio, "Keying material exporter:\n"); + BIO_printf(bio, " Label: '%s'\n", keymatexportlabel); + BIO_printf(bio, " Length: %i bytes\n", keymatexportlen); + exportedkeymat = malloc(keymatexportlen); + if (exportedkeymat != NULL) { + if (!SSL_export_keying_material(s, exportedkeymat, + keymatexportlen, + keymatexportlabel, + strlen(keymatexportlabel), + NULL, 0, 0)) { + BIO_printf(bio, " Error\n"); + } else { + BIO_printf(bio, " Keying material: "); + for (i = 0; i < keymatexportlen; i++) + BIO_printf(bio, "%02X", + exportedkeymat[i]); + BIO_printf(bio, "\n"); + } + free(exportedkeymat); + } + } + BIO_printf(bio, "---\n"); + if (peer != NULL) + X509_free(peer); + /* flush, or debugging output gets mixed with http response */ + (void) BIO_flush(bio); +} + + +static int +ocsp_resp_cb(SSL * s, void *arg) +{ + const unsigned char *p; + int len; + OCSP_RESPONSE *rsp; + len = SSL_get_tlsext_status_ocsp_resp(s, &p); + BIO_puts(arg, "OCSP response: "); + if (!p) { + BIO_puts(arg, "no response sent\n"); + return 1; + } + rsp = d2i_OCSP_RESPONSE(NULL, &p, len); + if (!rsp) { + BIO_puts(arg, "response parse error\n"); + BIO_dump_indent(arg, (char *) p, len, 4); + return 0; + } + BIO_puts(arg, "\n======================================\n"); + OCSP_RESPONSE_print(arg, rsp, 0); + BIO_puts(arg, "======================================\n"); + OCSP_RESPONSE_free(rsp); + return 1; +} + diff --git a/bin/openssl/s_server.c b/bin/openssl/s_server.c new file mode 100644 index 0000000000..d73a11799b --- /dev/null +++ b/bin/openssl/s_server.c @@ -0,0 +1,2037 @@ +/* $OpenBSD: s_server.c,v 1.25 2017/01/20 08:57:12 deraadt Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECC cipher suite support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ +/* ==================================================================== + * Copyright 2005 Nokia. All rights reserved. + * + * The portions of the attached software ("Contribution") is developed by + * Nokia Corporation and is licensed pursuant to the OpenSSL open source + * license. + * + * The Contribution, originally written by Mika Kousa and Pasi Eronen of + * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites + * support (see RFC 4279) to OpenSSL. + * + * No patent licenses or other rights except those expressly stated in + * the OpenSSL open source license shall be deemed granted or received + * expressly, by implication, estoppel, or otherwise. + * + * No assurances are provided by Nokia that the Contribution does not + * infringe the patent or other intellectual property rights of any third + * party or that the license provides you with all the necessary rights + * to make use of the Contribution. + * + * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN + * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA + * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY + * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR + * OTHERWISE. + */ + +/* Until the key-gen callbacks are modified to use newer prototypes, we allow + * deprecated functions for openssl-internal code */ +#ifdef OPENSSL_NO_DEPRECATED +#undef OPENSSL_NO_DEPRECATED +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "apps.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifndef OPENSSL_NO_DH +#include +#endif + +#include + +#include "s_apps.h" +#include "timeouts.h" + +static int sv_body(char *hostname, int s, unsigned char *context); +static int www_body(char *hostname, int s, unsigned char *context); +static void close_accept_socket(void); +static void sv_usage(void); +static int init_ssl_connection(SSL * s); +static void print_stats(BIO * bp, SSL_CTX * ctx); +static int +generate_session_id(const SSL * ssl, unsigned char *id, + unsigned int *id_len); +#ifndef OPENSSL_NO_DH +static DH *load_dh_param(const char *dhfile); +#endif + +static void s_server_init(void); + +/* static int load_CA(SSL_CTX *ctx, char *file);*/ + +#define BUFSIZZ 16*1024 +static int bufsize = BUFSIZZ; +static int accept_socket = -1; + +#define TEST_CERT "server.pem" +#define TEST_CERT2 "server2.pem" + +static char *cipher = NULL; +static int s_server_verify = SSL_VERIFY_NONE; +static int s_server_session_id_context = 1; /* anything will do */ +static const char *s_cert_file = TEST_CERT, *s_key_file = NULL; +static const char *s_cert_file2 = TEST_CERT2, *s_key_file2 = NULL; +static char *s_dcert_file = NULL, *s_dkey_file = NULL; +static int s_nbio = 0; +static int s_nbio_test = 0; +int s_crlf = 0; +static SSL_CTX *ctx = NULL; +static SSL_CTX *ctx2 = NULL; +static int www = 0; + +static BIO *bio_s_out = NULL; +static int s_debug = 0; +static int s_tlsextdebug = 0; +static int s_tlsextstatus = 0; +static int cert_status_cb(SSL * s, void *arg); +static int s_msg = 0; +static int s_quiet = 0; + +static char *keymatexportlabel = NULL; +static int keymatexportlen = 20; + +static const char *session_id_prefix = NULL; + +static int enable_timeouts = 0; +static long socket_mtu; +#ifndef OPENSSL_NO_DTLS1 +static int cert_chain = 0; +#endif + + + + +static void +s_server_init(void) +{ + accept_socket = -1; + cipher = NULL; + s_server_verify = SSL_VERIFY_NONE; + s_dcert_file = NULL; + s_dkey_file = NULL; + s_cert_file = TEST_CERT; + s_key_file = NULL; + s_cert_file2 = TEST_CERT2; + s_key_file2 = NULL; + ctx2 = NULL; + s_nbio = 0; + s_nbio_test = 0; + ctx = NULL; + www = 0; + + bio_s_out = NULL; + s_debug = 0; + s_msg = 0; + s_quiet = 0; +} + +static void +sv_usage(void) +{ + BIO_printf(bio_err, "usage: s_server [args ...]\n"); + BIO_printf(bio_err, "\n"); + BIO_printf(bio_err, " -accept arg - port to accept on (default is %d)\n", PORT); + BIO_printf(bio_err, " -context arg - set session ID context\n"); + BIO_printf(bio_err, " -verify arg - turn on peer certificate verification\n"); + BIO_printf(bio_err, " -Verify arg - turn on peer certificate verification, must have a cert.\n"); + BIO_printf(bio_err, " -cert arg - certificate file to use\n"); + BIO_printf(bio_err, " (default is %s)\n", TEST_CERT); + BIO_printf(bio_err, " -crl_check - check the peer certificate has not been revoked by its CA.\n" \ + " The CRL(s) are appended to the certificate file\n"); + BIO_printf(bio_err, " -crl_check_all - check the peer certificate has not been revoked by its CA\n" \ + " or any other CRL in the CA chain. CRL(s) are appended to the\n" \ + " the certificate file.\n"); + BIO_printf(bio_err, " -certform arg - certificate format (PEM or DER) PEM default\n"); + BIO_printf(bio_err, " -key arg - Private Key file to use, in cert file if\n"); + BIO_printf(bio_err, " not specified (default is %s)\n", TEST_CERT); + BIO_printf(bio_err, " -keyform arg - key format (PEM or DER) PEM default\n"); + BIO_printf(bio_err, " -pass arg - private key file pass phrase source\n"); + BIO_printf(bio_err, " -dcert arg - second certificate file to use (usually for DSA)\n"); + BIO_printf(bio_err, " -dcertform x - second certificate format (PEM or DER) PEM default\n"); + BIO_printf(bio_err, " -dkey arg - second private key file to use (usually for DSA)\n"); + BIO_printf(bio_err, " -dkeyform arg - second key format (PEM or DER) PEM default\n"); + BIO_printf(bio_err, " -dpass arg - second private key file pass phrase source\n"); + BIO_printf(bio_err, " -dhparam arg - DH parameter file to use, in cert file if not specified\n"); + BIO_printf(bio_err, " or a default set of parameters is used\n"); + BIO_printf(bio_err, " -named_curve arg - Elliptic curve name to use for ephemeral ECDH keys.\n" \ + " Use \"openssl ecparam -list_curves\" for all names\n" \ + " (default is nistp256).\n"); + BIO_printf(bio_err, " -nbio - Run with non-blocking IO\n"); + BIO_printf(bio_err, " -nbio_test - test with the non-blocking test bio\n"); + BIO_printf(bio_err, " -crlf - convert LF from terminal into CRLF\n"); + BIO_printf(bio_err, " -debug - Print more output\n"); + BIO_printf(bio_err, " -msg - Show protocol messages\n"); + BIO_printf(bio_err, " -state - Print the SSL states\n"); + BIO_printf(bio_err, " -CApath arg - PEM format directory of CA's\n"); + BIO_printf(bio_err, " -CAfile arg - PEM format file of CA's\n"); + BIO_printf(bio_err, " -nocert - Don't use any certificates (Anon-DH)\n"); + BIO_printf(bio_err, " -cipher arg - play with 'openssl ciphers' to see what goes here\n"); + BIO_printf(bio_err, " -serverpref - Use server's cipher preferences\n"); + BIO_printf(bio_err, " -quiet - Inhibit printing of session and certificate information\n"); + BIO_printf(bio_err, " -tls1_2 - Just talk TLSv1.2\n"); + BIO_printf(bio_err, " -tls1_1 - Just talk TLSv1.1\n"); + BIO_printf(bio_err, " -tls1 - Just talk TLSv1\n"); + BIO_printf(bio_err, " -dtls1 - Just talk DTLSv1\n"); + BIO_printf(bio_err, " -timeout - Enable timeouts\n"); + BIO_printf(bio_err, " -mtu - Set link layer MTU\n"); + BIO_printf(bio_err, " -chain - Read a certificate chain\n"); + BIO_printf(bio_err, " -no_ssl2 - Just disable SSLv2\n"); + BIO_printf(bio_err, " -no_ssl3 - Just disable SSLv3\n"); + BIO_printf(bio_err, " -no_tls1 - Just disable TLSv1\n"); + BIO_printf(bio_err, " -no_tls1_1 - Just disable TLSv1.1\n"); + BIO_printf(bio_err, " -no_tls1_2 - Just disable TLSv1.2\n"); +#ifndef OPENSSL_NO_DH + BIO_printf(bio_err, " -no_dhe - Disable ephemeral DH\n"); +#endif + BIO_printf(bio_err, " -no_ecdhe - Disable ephemeral ECDH\n"); + BIO_printf(bio_err, " -bugs - Turn on SSL bug compatibility\n"); + BIO_printf(bio_err, " -www - Respond to a 'GET /' with a status page\n"); + BIO_printf(bio_err, " -WWW - Respond to a 'GET / HTTP/1.0' with file ./\n"); + BIO_printf(bio_err, " -HTTP - Respond to a 'GET / HTTP/1.0' with file ./\n"); + BIO_printf(bio_err, " with the assumption it contains a complete HTTP response.\n"); + BIO_printf(bio_err, " -id_prefix arg - Generate SSL/TLS session IDs prefixed by 'arg'\n"); + BIO_printf(bio_err, " -servername host - servername for HostName TLS extension\n"); + BIO_printf(bio_err, " -servername_fatal - on mismatch send fatal alert (default warning alert)\n"); + BIO_printf(bio_err, " -cert2 arg - certificate file to use for servername\n"); + BIO_printf(bio_err, " (default is %s)\n", TEST_CERT2); + BIO_printf(bio_err, " -key2 arg - Private Key file to use for servername, in cert file if\n"); + BIO_printf(bio_err, " not specified (default is %s)\n", TEST_CERT2); + BIO_printf(bio_err, " -tlsextdebug - hex dump of all TLS extensions received\n"); + BIO_printf(bio_err, " -no_ticket - disable use of RFC4507bis session tickets\n"); + BIO_printf(bio_err, " -nextprotoneg arg - set the advertised protocols for the NPN extension (comma-separated list)\n"); + BIO_printf(bio_err," -alpn arg - set the advertised protocols for the ALPN extension (comma-separated list)\n"); +#ifndef OPENSSL_NO_SRTP + BIO_printf(bio_err, " -use_srtp profiles - Offer SRTP key management with a colon-separated profile list\n"); +#endif + BIO_printf(bio_err, " -keymatexport label - Export keying material using label\n"); + BIO_printf(bio_err, " -keymatexportlen len - Export len bytes of keying material (default 20)\n"); +} + +static int local_argc = 0; +static char **local_argv; + + +/* This is a context that we pass to callbacks */ +typedef struct tlsextctx_st { + char *servername; + BIO *biodebug; + int extension_error; +} tlsextctx; + + +static int +ssl_servername_cb(SSL * s, int *ad, void *arg) +{ + tlsextctx *p = (tlsextctx *) arg; + const char *servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); + if (servername && p->biodebug) + BIO_printf(p->biodebug, "Hostname in TLS extension: \"%s\"\n", servername); + + if (!p->servername) + return SSL_TLSEXT_ERR_NOACK; + + if (servername) { + if (strcmp(servername, p->servername)) + return p->extension_error; + if (ctx2) { + BIO_printf(p->biodebug, "Switching server context.\n"); + SSL_set_SSL_CTX(s, ctx2); + } + } + return SSL_TLSEXT_ERR_OK; +} + +/* Structure passed to cert status callback */ + +typedef struct tlsextstatusctx_st { + /* Default responder to use */ + char *host, *path, *port; + int use_ssl; + int timeout; + BIO *err; + int verbose; +} tlsextstatusctx; + +static tlsextstatusctx tlscstatp = {NULL, NULL, NULL, 0, -1, NULL, 0}; + +/* Certificate Status callback. This is called when a client includes a + * certificate status request extension. + * + * This is a simplified version. It examines certificates each time and + * makes one OCSP responder query for each request. + * + * A full version would store details such as the OCSP certificate IDs and + * minimise the number of OCSP responses by caching them until they were + * considered "expired". + */ + +static int +cert_status_cb(SSL * s, void *arg) +{ + tlsextstatusctx *srctx = arg; + BIO *err = srctx->err; + char *host, *port, *path; + int use_ssl; + unsigned char *rspder = NULL; + int rspderlen; + STACK_OF(OPENSSL_STRING) * aia = NULL; + X509 *x = NULL; + X509_STORE_CTX inctx; + X509_OBJECT obj; + OCSP_REQUEST *req = NULL; + OCSP_RESPONSE *resp = NULL; + OCSP_CERTID *id = NULL; + STACK_OF(X509_EXTENSION) * exts; + int ret = SSL_TLSEXT_ERR_NOACK; + int i; + + if (srctx->verbose) + BIO_puts(err, "cert_status: callback called\n"); + /* Build up OCSP query from server certificate */ + x = SSL_get_certificate(s); + aia = X509_get1_ocsp(x); + if (aia) { + if (!OCSP_parse_url(sk_OPENSSL_STRING_value(aia, 0), + &host, &port, &path, &use_ssl)) { + BIO_puts(err, "cert_status: can't parse AIA URL\n"); + goto err; + } + if (srctx->verbose) + BIO_printf(err, "cert_status: AIA URL: %s\n", + sk_OPENSSL_STRING_value(aia, 0)); + } else { + if (!srctx->host) { + BIO_puts(srctx->err, "cert_status: no AIA and no default responder URL\n"); + goto done; + } + host = srctx->host; + path = srctx->path; + port = srctx->port; + use_ssl = srctx->use_ssl; + } + + if (!X509_STORE_CTX_init(&inctx, + SSL_CTX_get_cert_store(SSL_get_SSL_CTX(s)), + NULL, NULL)) + goto err; + if (X509_STORE_get_by_subject(&inctx, X509_LU_X509, + X509_get_issuer_name(x), &obj) <= 0) { + BIO_puts(err, "cert_status: Can't retrieve issuer certificate.\n"); + X509_STORE_CTX_cleanup(&inctx); + goto done; + } + req = OCSP_REQUEST_new(); + if (!req) + goto err; + id = OCSP_cert_to_id(NULL, x, obj.data.x509); + X509_free(obj.data.x509); + X509_STORE_CTX_cleanup(&inctx); + if (!id) + goto err; + if (!OCSP_request_add0_id(req, id)) + goto err; + id = NULL; + /* Add any extensions to the request */ + SSL_get_tlsext_status_exts(s, &exts); + for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) { + X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i); + if (!OCSP_REQUEST_add_ext(req, ext, -1)) + goto err; + } + resp = process_responder(err, req, host, path, port, use_ssl, NULL, + srctx->timeout); + if (!resp) { + BIO_puts(err, "cert_status: error querying responder\n"); + goto done; + } + rspderlen = i2d_OCSP_RESPONSE(resp, &rspder); + if (rspderlen <= 0) + goto err; + SSL_set_tlsext_status_ocsp_resp(s, rspder, rspderlen); + if (srctx->verbose) { + BIO_puts(err, "cert_status: ocsp response sent:\n"); + OCSP_RESPONSE_print(err, resp, 2); + } + ret = SSL_TLSEXT_ERR_OK; +done: + if (ret != SSL_TLSEXT_ERR_OK) + ERR_print_errors(err); + if (aia) { + free(host); + free(path); + free(port); + X509_email_free(aia); + } + if (id) + OCSP_CERTID_free(id); + if (req) + OCSP_REQUEST_free(req); + if (resp) + OCSP_RESPONSE_free(resp); + return ret; +err: + ret = SSL_TLSEXT_ERR_ALERT_FATAL; + goto done; +} + +/* This is the context that we pass to next_proto_cb */ +typedef struct tlsextnextprotoctx_st { + unsigned char *data; + unsigned int len; +} tlsextnextprotoctx; + +static int +next_proto_cb(SSL * s, const unsigned char **data, unsigned int *len, void *arg) +{ + tlsextnextprotoctx *next_proto = arg; + + *data = next_proto->data; + *len = next_proto->len; + + return SSL_TLSEXT_ERR_OK; +} + + +/* This the context that we pass to alpn_cb */ +typedef struct tlsextalpnctx_st { + unsigned char *data; + unsigned short len; +} tlsextalpnctx; + +static int +alpn_cb(SSL *s, const unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, void *arg) +{ + tlsextalpnctx *alpn_ctx = arg; + + if (!s_quiet) { + /* We can assume that in is syntactically valid. */ + unsigned i; + + BIO_printf(bio_s_out, + "ALPN protocols advertised by the client: "); + for (i = 0; i < inlen; ) { + if (i) + BIO_write(bio_s_out, ", ", 2); + BIO_write(bio_s_out, &in[i + 1], in[i]); + i += in[i] + 1; + } + BIO_write(bio_s_out, "\n", 1); + } + + if (SSL_select_next_proto((unsigned char**)out, outlen, alpn_ctx->data, + alpn_ctx->len, in, inlen) != OPENSSL_NPN_NEGOTIATED) + return (SSL_TLSEXT_ERR_NOACK); + + if (!s_quiet) { + BIO_printf(bio_s_out, "ALPN protocols selected: "); + BIO_write(bio_s_out, *out, *outlen); + BIO_write(bio_s_out, "\n", 1); + } + + return (SSL_TLSEXT_ERR_OK); +} + +#ifndef OPENSSL_NO_SRTP +static char *srtp_profiles = NULL; +#endif + +int +s_server_main(int argc, char *argv[]) +{ + X509_VERIFY_PARAM *vpm = NULL; + int badarg = 0; + short port = PORT; + char *CApath = NULL, *CAfile = NULL; + unsigned char *context = NULL; + char *dhfile = NULL; + char *named_curve = NULL; + int badop = 0, bugs = 0; + int ret = 1; + int off = 0; + int no_dhe = 0, no_ecdhe = 0, nocert = 0; + int state = 0; + const SSL_METHOD *meth = NULL; + int socket_type = SOCK_STREAM; + int s_cert_format = FORMAT_PEM, s_key_format = FORMAT_PEM; + char *passarg = NULL, *pass = NULL; + char *dpassarg = NULL, *dpass = NULL; + int s_dcert_format = FORMAT_PEM, s_dkey_format = FORMAT_PEM; + X509 *s_cert = NULL, *s_dcert = NULL; + EVP_PKEY *s_key = NULL, *s_dkey = NULL; + int no_cache = 0; + const char *errstr = NULL; + EVP_PKEY *s_key2 = NULL; + X509 *s_cert2 = NULL; + tlsextctx tlsextcbp = {NULL, NULL, SSL_TLSEXT_ERR_ALERT_WARNING}; + const char *next_proto_neg_in = NULL; + tlsextnextprotoctx next_proto = { NULL, 0 }; + const char *alpn_in = NULL; + tlsextalpnctx alpn_ctx = { NULL, 0 }; + + if (single_execution) { + if (pledge("stdio rpath inet dns tty", NULL) == -1) { + perror("pledge"); + exit(1); + } + } + + meth = SSLv23_server_method(); + + local_argc = argc; + local_argv = argv; + + s_server_init(); + + verify_depth = 0; + s_nbio = 0; + s_nbio_test = 0; + + argc--; + argv++; + + while (argc >= 1) { + if ((strcmp(*argv, "-port") == 0) || + (strcmp(*argv, "-accept") == 0)) { + if (--argc < 1) + goto bad; + if (!extract_port(*(++argv), &port)) + goto bad; + } else if (strcmp(*argv, "-verify") == 0) { + s_server_verify = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE; + if (--argc < 1) + goto bad; + verify_depth = strtonum(*(++argv), 0, INT_MAX, &errstr); + if (errstr) + goto bad; + BIO_printf(bio_err, "verify depth is %d\n", verify_depth); + } else if (strcmp(*argv, "-Verify") == 0) { + s_server_verify = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT | + SSL_VERIFY_CLIENT_ONCE; + if (--argc < 1) + goto bad; + verify_depth = strtonum(*(++argv), 0, INT_MAX, &errstr); + if (errstr) + goto bad; + BIO_printf(bio_err, "verify depth is %d, must return a certificate\n", verify_depth); + } else if (strcmp(*argv, "-context") == 0) { + if (--argc < 1) + goto bad; + context = (unsigned char *) *(++argv); + } else if (strcmp(*argv, "-cert") == 0) { + if (--argc < 1) + goto bad; + s_cert_file = *(++argv); + } else if (strcmp(*argv, "-certform") == 0) { + if (--argc < 1) + goto bad; + s_cert_format = str2fmt(*(++argv)); + } else if (strcmp(*argv, "-key") == 0) { + if (--argc < 1) + goto bad; + s_key_file = *(++argv); + } else if (strcmp(*argv, "-keyform") == 0) { + if (--argc < 1) + goto bad; + s_key_format = str2fmt(*(++argv)); + } else if (strcmp(*argv, "-pass") == 0) { + if (--argc < 1) + goto bad; + passarg = *(++argv); + } else if (strcmp(*argv, "-dhparam") == 0) { + if (--argc < 1) + goto bad; + dhfile = *(++argv); + } + else if (strcmp(*argv, "-named_curve") == 0) { + if (--argc < 1) + goto bad; + named_curve = *(++argv); + } + else if (strcmp(*argv, "-dcertform") == 0) { + if (--argc < 1) + goto bad; + s_dcert_format = str2fmt(*(++argv)); + } else if (strcmp(*argv, "-dcert") == 0) { + if (--argc < 1) + goto bad; + s_dcert_file = *(++argv); + } else if (strcmp(*argv, "-dkeyform") == 0) { + if (--argc < 1) + goto bad; + s_dkey_format = str2fmt(*(++argv)); + } else if (strcmp(*argv, "-dpass") == 0) { + if (--argc < 1) + goto bad; + dpassarg = *(++argv); + } else if (strcmp(*argv, "-dkey") == 0) { + if (--argc < 1) + goto bad; + s_dkey_file = *(++argv); + } else if (strcmp(*argv, "-nocert") == 0) { + nocert = 1; + } else if (strcmp(*argv, "-CApath") == 0) { + if (--argc < 1) + goto bad; + CApath = *(++argv); + } else if (strcmp(*argv, "-no_cache") == 0) + no_cache = 1; + else if (args_verify(&argv, &argc, &badarg, bio_err, &vpm)) { + if (badarg) + goto bad; + continue; + } else if (strcmp(*argv, "-verify_return_error") == 0) + verify_return_error = 1; + else if (strcmp(*argv, "-serverpref") == 0) { + off |= SSL_OP_CIPHER_SERVER_PREFERENCE; + } else if (strcmp(*argv, "-legacy_renegotiation") == 0) + ; /* no-op */ + else if (strcmp(*argv, "-cipher") == 0) { + if (--argc < 1) + goto bad; + cipher = *(++argv); + } else if (strcmp(*argv, "-CAfile") == 0) { + if (--argc < 1) + goto bad; + CAfile = *(++argv); + } + else if (strcmp(*argv, "-nbio") == 0) { + s_nbio = 1; + } + else if (strcmp(*argv, "-nbio_test") == 0) { + s_nbio = 1; + s_nbio_test = 1; + } else if (strcmp(*argv, "-debug") == 0) { + s_debug = 1; + } + else if (strcmp(*argv, "-tlsextdebug") == 0) + s_tlsextdebug = 1; + else if (strcmp(*argv, "-status") == 0) + s_tlsextstatus = 1; + else if (strcmp(*argv, "-status_verbose") == 0) { + s_tlsextstatus = 1; + tlscstatp.verbose = 1; + } else if (!strcmp(*argv, "-status_timeout")) { + s_tlsextstatus = 1; + if (--argc < 1) + goto bad; + tlscstatp.timeout = strtonum(*(++argv), 0, INT_MAX, &errstr); + if (errstr) + goto bad; + } else if (!strcmp(*argv, "-status_url")) { + s_tlsextstatus = 1; + if (--argc < 1) + goto bad; + if (!OCSP_parse_url(*(++argv), + &tlscstatp.host, + &tlscstatp.port, + &tlscstatp.path, + &tlscstatp.use_ssl)) { + BIO_printf(bio_err, "Error parsing URL\n"); + goto bad; + } + } + else if (strcmp(*argv, "-msg") == 0) { + s_msg = 1; + } else if (strcmp(*argv, "-state") == 0) { + state = 1; + } else if (strcmp(*argv, "-crlf") == 0) { + s_crlf = 1; + } else if (strcmp(*argv, "-quiet") == 0) { + s_quiet = 1; + } else if (strcmp(*argv, "-bugs") == 0) { + bugs = 1; + } else if (strcmp(*argv, "-no_tmp_rsa") == 0) { + /* No-op. */ + } else if (strcmp(*argv, "-no_dhe") == 0) { + no_dhe = 1; + } else if (strcmp(*argv, "-no_ecdhe") == 0) { + no_ecdhe = 1; + } else if (strcmp(*argv, "-www") == 0) { + www = 1; + } else if (strcmp(*argv, "-WWW") == 0) { + www = 2; + } else if (strcmp(*argv, "-HTTP") == 0) { + www = 3; + } else if (strcmp(*argv, "-no_ssl2") == 0) { + off |= SSL_OP_NO_SSLv2; + } else if (strcmp(*argv, "-no_ssl3") == 0) { + off |= SSL_OP_NO_SSLv3; + } else if (strcmp(*argv, "-no_tls1") == 0) { + off |= SSL_OP_NO_TLSv1; + } else if (strcmp(*argv, "-no_tls1_1") == 0) { + off |= SSL_OP_NO_TLSv1_1; + } else if (strcmp(*argv, "-no_tls1_2") == 0) { + off |= SSL_OP_NO_TLSv1_2; + } else if (strcmp(*argv, "-no_comp") == 0) { + off |= SSL_OP_NO_COMPRESSION; + } else if (strcmp(*argv, "-no_ticket") == 0) { + off |= SSL_OP_NO_TICKET; + } else if (strcmp(*argv, "-tls1") == 0) { + meth = TLSv1_server_method(); + } else if (strcmp(*argv, "-tls1_1") == 0) { + meth = TLSv1_1_server_method(); + } else if (strcmp(*argv, "-tls1_2") == 0) { + meth = TLSv1_2_server_method(); + } +#ifndef OPENSSL_NO_DTLS1 + else if (strcmp(*argv, "-dtls1") == 0) { + meth = DTLSv1_server_method(); + socket_type = SOCK_DGRAM; + } else if (strcmp(*argv, "-timeout") == 0) + enable_timeouts = 1; + else if (strcmp(*argv, "-mtu") == 0) { + if (--argc < 1) + goto bad; + socket_mtu = strtonum(*(++argv), 0, LONG_MAX, &errstr); + if (errstr) + goto bad; + } else if (strcmp(*argv, "-chain") == 0) + cert_chain = 1; +#endif + else if (strcmp(*argv, "-id_prefix") == 0) { + if (--argc < 1) + goto bad; + session_id_prefix = *(++argv); + } + else if (strcmp(*argv, "-servername") == 0) { + if (--argc < 1) + goto bad; + tlsextcbp.servername = *(++argv); + } else if (strcmp(*argv, "-servername_fatal") == 0) { + tlsextcbp.extension_error = SSL_TLSEXT_ERR_ALERT_FATAL; + } else if (strcmp(*argv, "-cert2") == 0) { + if (--argc < 1) + goto bad; + s_cert_file2 = *(++argv); + } else if (strcmp(*argv, "-key2") == 0) { + if (--argc < 1) + goto bad; + s_key_file2 = *(++argv); + } + else if (strcmp(*argv, "-nextprotoneg") == 0) { + if (--argc < 1) + goto bad; + next_proto_neg_in = *(++argv); + } + else if (strcmp(*argv,"-alpn") == 0) { + if (--argc < 1) + goto bad; + alpn_in = *(++argv); + } +#ifndef OPENSSL_NO_SRTP + else if (strcmp(*argv, "-use_srtp") == 0) { + if (--argc < 1) + goto bad; + srtp_profiles = *(++argv); + } +#endif + else if (strcmp(*argv, "-keymatexport") == 0) { + if (--argc < 1) + goto bad; + keymatexportlabel = *(++argv); + } else if (strcmp(*argv, "-keymatexportlen") == 0) { + if (--argc < 1) + goto bad; + keymatexportlen = strtonum(*(++argv), 1, INT_MAX, &errstr); + if (errstr) + goto bad; + } else { + BIO_printf(bio_err, "unknown option %s\n", *argv); + badop = 1; + break; + } + argc--; + argv++; + } + if (badop) { +bad: + if (errstr) + BIO_printf(bio_err, "invalid argument %s: %s\n", + *argv, errstr); + else + sv_usage(); + goto end; + } + + if (!app_passwd(bio_err, passarg, dpassarg, &pass, &dpass)) { + BIO_printf(bio_err, "Error getting password\n"); + goto end; + } + if (s_key_file == NULL) + s_key_file = s_cert_file; + if (s_key_file2 == NULL) + s_key_file2 = s_cert_file2; + + if (nocert == 0) { + s_key = load_key(bio_err, s_key_file, s_key_format, 0, pass, + "server certificate private key file"); + if (!s_key) { + ERR_print_errors(bio_err); + goto end; + } + s_cert = load_cert(bio_err, s_cert_file, s_cert_format, + NULL, "server certificate file"); + + if (!s_cert) { + ERR_print_errors(bio_err); + goto end; + } + if (tlsextcbp.servername) { + s_key2 = load_key(bio_err, s_key_file2, s_key_format, 0, pass, + "second server certificate private key file"); + if (!s_key2) { + ERR_print_errors(bio_err); + goto end; + } + s_cert2 = load_cert(bio_err, s_cert_file2, s_cert_format, + NULL, "second server certificate file"); + + if (!s_cert2) { + ERR_print_errors(bio_err); + goto end; + } + } + } + if (next_proto_neg_in) { + unsigned short len; + next_proto.data = next_protos_parse(&len, next_proto_neg_in); + if (next_proto.data == NULL) + goto end; + next_proto.len = len; + } else { + next_proto.data = NULL; + } + alpn_ctx.data = NULL; + if (alpn_in) { + unsigned short len; + alpn_ctx.data = next_protos_parse(&len, alpn_in); + if (alpn_ctx.data == NULL) + goto end; + alpn_ctx.len = len; + } + + if (s_dcert_file) { + + if (s_dkey_file == NULL) + s_dkey_file = s_dcert_file; + + s_dkey = load_key(bio_err, s_dkey_file, s_dkey_format, + 0, dpass, "second certificate private key file"); + if (!s_dkey) { + ERR_print_errors(bio_err); + goto end; + } + s_dcert = load_cert(bio_err, s_dcert_file, s_dcert_format, + NULL, "second server certificate file"); + + if (!s_dcert) { + ERR_print_errors(bio_err); + goto end; + } + } + if (bio_s_out == NULL) { + if (s_quiet && !s_debug && !s_msg) { + bio_s_out = BIO_new(BIO_s_null()); + } else { + if (bio_s_out == NULL) + bio_s_out = BIO_new_fp(stdout, BIO_NOCLOSE); + } + } + if (nocert) { + s_cert_file = NULL; + s_key_file = NULL; + s_dcert_file = NULL; + s_dkey_file = NULL; + s_cert_file2 = NULL; + s_key_file2 = NULL; + } + ctx = SSL_CTX_new(meth); + if (ctx == NULL) { + ERR_print_errors(bio_err); + goto end; + } + if (session_id_prefix) { + if (strlen(session_id_prefix) >= 32) + BIO_printf(bio_err, + "warning: id_prefix is too long, only one new session will be possible\n"); + else if (strlen(session_id_prefix) >= 16) + BIO_printf(bio_err, + "warning: id_prefix is too long if you use SSLv2\n"); + if (!SSL_CTX_set_generate_session_id(ctx, generate_session_id)) { + BIO_printf(bio_err, "error setting 'id_prefix'\n"); + ERR_print_errors(bio_err); + goto end; + } + BIO_printf(bio_err, "id_prefix '%s' set.\n", session_id_prefix); + } + SSL_CTX_set_quiet_shutdown(ctx, 1); + if (bugs) + SSL_CTX_set_options(ctx, SSL_OP_ALL); + SSL_CTX_set_options(ctx, off); + /* + * DTLS: partial reads end up discarding unread UDP bytes :-( Setting + * read ahead solves this problem. + */ + if (socket_type == SOCK_DGRAM) + SSL_CTX_set_read_ahead(ctx, 1); + + if (state) + SSL_CTX_set_info_callback(ctx, apps_ssl_info_callback); + if (no_cache) + SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); + else + SSL_CTX_sess_set_cache_size(ctx, 128); + +#ifndef OPENSSL_NO_SRTP + if (srtp_profiles != NULL) + SSL_CTX_set_tlsext_use_srtp(ctx, srtp_profiles); +#endif + + + if ((!SSL_CTX_load_verify_locations(ctx, CAfile, CApath)) || + (!SSL_CTX_set_default_verify_paths(ctx))) { + /* BIO_printf(bio_err,"X509_load_verify_locations\n"); */ + ERR_print_errors(bio_err); + /* goto end; */ + } + if (vpm) + SSL_CTX_set1_param(ctx, vpm); + + if (s_cert2) { + ctx2 = SSL_CTX_new(meth); + if (ctx2 == NULL) { + ERR_print_errors(bio_err); + goto end; + } + } + if (ctx2) { + BIO_printf(bio_s_out, "Setting secondary ctx parameters\n"); + + if (session_id_prefix) { + if (strlen(session_id_prefix) >= 32) + BIO_printf(bio_err, + "warning: id_prefix is too long, only one new session will be possible\n"); + else if (strlen(session_id_prefix) >= 16) + BIO_printf(bio_err, + "warning: id_prefix is too long if you use SSLv2\n"); + if (!SSL_CTX_set_generate_session_id(ctx2, generate_session_id)) { + BIO_printf(bio_err, "error setting 'id_prefix'\n"); + ERR_print_errors(bio_err); + goto end; + } + BIO_printf(bio_err, "id_prefix '%s' set.\n", session_id_prefix); + } + SSL_CTX_set_quiet_shutdown(ctx2, 1); + if (bugs) + SSL_CTX_set_options(ctx2, SSL_OP_ALL); + SSL_CTX_set_options(ctx2, off); + /* + * DTLS: partial reads end up discarding unread UDP bytes :-( + * Setting read ahead solves this problem. + */ + if (socket_type == SOCK_DGRAM) + SSL_CTX_set_read_ahead(ctx2, 1); + + if (state) + SSL_CTX_set_info_callback(ctx2, apps_ssl_info_callback); + + if (no_cache) + SSL_CTX_set_session_cache_mode(ctx2, SSL_SESS_CACHE_OFF); + else + SSL_CTX_sess_set_cache_size(ctx2, 128); + + if ((!SSL_CTX_load_verify_locations(ctx2, CAfile, CApath)) || + (!SSL_CTX_set_default_verify_paths(ctx2))) { + ERR_print_errors(bio_err); + } + if (vpm) + SSL_CTX_set1_param(ctx2, vpm); + } + if (next_proto.data) + SSL_CTX_set_next_protos_advertised_cb(ctx, next_proto_cb, &next_proto); + if (alpn_ctx.data) + SSL_CTX_set_alpn_select_cb(ctx, alpn_cb, &alpn_ctx); + +#ifndef OPENSSL_NO_DH + if (!no_dhe) { + DH *dh = NULL; + + if (dhfile) + dh = load_dh_param(dhfile); + else if (s_cert_file) + dh = load_dh_param(s_cert_file); + + if (dh != NULL) + BIO_printf(bio_s_out, "Setting temp DH parameters\n"); + else + BIO_printf(bio_s_out, "Using auto DH parameters\n"); + (void) BIO_flush(bio_s_out); + + if (dh == NULL) + SSL_CTX_set_dh_auto(ctx, 1); + else if (!SSL_CTX_set_tmp_dh(ctx, dh)) { + BIO_printf(bio_err, + "Error setting temp DH parameters\n"); + ERR_print_errors(bio_err); + DH_free(dh); + goto end; + } + + if (ctx2) { + if (!dhfile) { + DH *dh2 = NULL; + + if (s_cert_file2 != NULL) + dh2 = load_dh_param(s_cert_file2); + if (dh2 != NULL) { + BIO_printf(bio_s_out, "Setting temp DH parameters\n"); + (void) BIO_flush(bio_s_out); + + DH_free(dh); + dh = dh2; + } + } + if (dh == NULL) + SSL_CTX_set_dh_auto(ctx2, 1); + else if (!SSL_CTX_set_tmp_dh(ctx2, dh)) { + BIO_printf(bio_err, + "Error setting temp DH parameters\n"); + ERR_print_errors(bio_err); + DH_free(dh); + goto end; + } + } + DH_free(dh); + } +#endif + + if (!no_ecdhe) { + EC_KEY *ecdh = NULL; + + if (named_curve) { + int nid = OBJ_sn2nid(named_curve); + + if (nid == 0) { + BIO_printf(bio_err, "unknown curve name (%s)\n", + named_curve); + goto end; + } + ecdh = EC_KEY_new_by_curve_name(nid); + if (ecdh == NULL) { + BIO_printf(bio_err, "unable to create curve (%s)\n", + named_curve); + goto end; + } + } + if (ecdh != NULL) { + BIO_printf(bio_s_out, "Setting temp ECDH parameters\n"); + } else { + BIO_printf(bio_s_out, "Using default temp ECDH parameters\n"); + ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + if (ecdh == NULL) { + BIO_printf(bio_err, "unable to create curve (nistp256)\n"); + goto end; + } + } + (void) BIO_flush(bio_s_out); + + SSL_CTX_set_tmp_ecdh(ctx, ecdh); + if (ctx2) + SSL_CTX_set_tmp_ecdh(ctx2, ecdh); + EC_KEY_free(ecdh); + } + + if (!set_cert_key_stuff(ctx, s_cert, s_key)) + goto end; + if (ctx2 && !set_cert_key_stuff(ctx2, s_cert2, s_key2)) + goto end; + if (s_dcert != NULL) { + if (!set_cert_key_stuff(ctx, s_dcert, s_dkey)) + goto end; + } + + if (cipher != NULL) { + if (!SSL_CTX_set_cipher_list(ctx, cipher)) { + BIO_printf(bio_err, "error setting cipher list\n"); + ERR_print_errors(bio_err); + goto end; + } + if (ctx2 && !SSL_CTX_set_cipher_list(ctx2, cipher)) { + BIO_printf(bio_err, "error setting cipher list\n"); + ERR_print_errors(bio_err); + goto end; + } + } + SSL_CTX_set_verify(ctx, s_server_verify, verify_callback); + SSL_CTX_set_session_id_context(ctx, (void *) &s_server_session_id_context, + sizeof s_server_session_id_context); + + /* Set DTLS cookie generation and verification callbacks */ + SSL_CTX_set_cookie_generate_cb(ctx, generate_cookie_callback); + SSL_CTX_set_cookie_verify_cb(ctx, verify_cookie_callback); + + if (ctx2) { + SSL_CTX_set_verify(ctx2, s_server_verify, verify_callback); + SSL_CTX_set_session_id_context(ctx2, (void *) &s_server_session_id_context, + sizeof s_server_session_id_context); + + tlsextcbp.biodebug = bio_s_out; + SSL_CTX_set_tlsext_servername_callback(ctx2, ssl_servername_cb); + SSL_CTX_set_tlsext_servername_arg(ctx2, &tlsextcbp); + SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb); + SSL_CTX_set_tlsext_servername_arg(ctx, &tlsextcbp); + } + + if (CAfile != NULL) { + SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(CAfile)); + if (ctx2) + SSL_CTX_set_client_CA_list(ctx2, SSL_load_client_CA_file(CAfile)); + } + BIO_printf(bio_s_out, "ACCEPT\n"); + (void) BIO_flush(bio_s_out); + if (www) + do_server(port, socket_type, &accept_socket, www_body, context); + else + do_server(port, socket_type, &accept_socket, sv_body, context); + print_stats(bio_s_out, ctx); + ret = 0; +end: + if (ctx != NULL) + SSL_CTX_free(ctx); + if (s_cert) + X509_free(s_cert); + if (s_dcert) + X509_free(s_dcert); + if (s_key) + EVP_PKEY_free(s_key); + if (s_dkey) + EVP_PKEY_free(s_dkey); + free(pass); + free(dpass); + if (vpm) + X509_VERIFY_PARAM_free(vpm); + free(tlscstatp.host); + free(tlscstatp.port); + free(tlscstatp.path); + if (ctx2 != NULL) + SSL_CTX_free(ctx2); + if (s_cert2) + X509_free(s_cert2); + if (s_key2) + EVP_PKEY_free(s_key2); + free(next_proto.data); + free(alpn_ctx.data); + if (bio_s_out != NULL) { + BIO_free(bio_s_out); + bio_s_out = NULL; + } + + return (ret); +} + +static void +print_stats(BIO * bio, SSL_CTX * ssl_ctx) +{ + BIO_printf(bio, "%4ld items in the session cache\n", + SSL_CTX_sess_number(ssl_ctx)); + BIO_printf(bio, "%4ld client connects (SSL_connect())\n", + SSL_CTX_sess_connect(ssl_ctx)); + BIO_printf(bio, "%4ld client renegotiates (SSL_connect())\n", + SSL_CTX_sess_connect_renegotiate(ssl_ctx)); + BIO_printf(bio, "%4ld client connects that finished\n", + SSL_CTX_sess_connect_good(ssl_ctx)); + BIO_printf(bio, "%4ld server accepts (SSL_accept())\n", + SSL_CTX_sess_accept(ssl_ctx)); + BIO_printf(bio, "%4ld server renegotiates (SSL_accept())\n", + SSL_CTX_sess_accept_renegotiate(ssl_ctx)); + BIO_printf(bio, "%4ld server accepts that finished\n", + SSL_CTX_sess_accept_good(ssl_ctx)); + BIO_printf(bio, "%4ld session cache hits\n", SSL_CTX_sess_hits(ssl_ctx)); + BIO_printf(bio, "%4ld session cache misses\n", SSL_CTX_sess_misses(ssl_ctx)); + BIO_printf(bio, "%4ld session cache timeouts\n", SSL_CTX_sess_timeouts(ssl_ctx)); + BIO_printf(bio, "%4ld callback cache hits\n", SSL_CTX_sess_cb_hits(ssl_ctx)); + BIO_printf(bio, "%4ld cache full overflows (%ld allowed)\n", + SSL_CTX_sess_cache_full(ssl_ctx), + SSL_CTX_sess_get_cache_size(ssl_ctx)); +} + +static int +sv_body(char *hostname, int s, unsigned char *context) +{ + char *buf = NULL; + int ret = 1; + int k, i; + unsigned long l; + SSL *con = NULL; + BIO *sbio; + struct timeval timeout; + + if ((buf = malloc(bufsize)) == NULL) { + BIO_printf(bio_err, "out of memory\n"); + goto err; + } + if (s_nbio) { + if (!s_quiet) + BIO_printf(bio_err, "turning on non blocking io\n"); + if (!BIO_socket_nbio(s, 1)) + ERR_print_errors(bio_err); + } + + if (con == NULL) { + con = SSL_new(ctx); + if (s_tlsextdebug) { + SSL_set_tlsext_debug_callback(con, tlsext_cb); + SSL_set_tlsext_debug_arg(con, bio_s_out); + } + if (s_tlsextstatus) { + SSL_CTX_set_tlsext_status_cb(ctx, cert_status_cb); + tlscstatp.err = bio_err; + SSL_CTX_set_tlsext_status_arg(ctx, &tlscstatp); + } + if (context) + SSL_set_session_id_context(con, context, + strlen((char *) context)); + } + SSL_clear(con); + + if (SSL_version(con) == DTLS1_VERSION) { + + sbio = BIO_new_dgram(s, BIO_NOCLOSE); + + if (enable_timeouts) { + timeout.tv_sec = 0; + timeout.tv_usec = DGRAM_RCV_TIMEOUT; + BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout); + + timeout.tv_sec = 0; + timeout.tv_usec = DGRAM_SND_TIMEOUT; + BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout); + } + if (socket_mtu > 28) { + SSL_set_options(con, SSL_OP_NO_QUERY_MTU); + SSL_set_mtu(con, socket_mtu - 28); + } else + /* want to do MTU discovery */ + BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL); + + /* turn on cookie exchange */ + SSL_set_options(con, SSL_OP_COOKIE_EXCHANGE); + } else + sbio = BIO_new_socket(s, BIO_NOCLOSE); + + if (s_nbio_test) { + BIO *test; + + test = BIO_new(BIO_f_nbio_test()); + sbio = BIO_push(test, sbio); + } + + SSL_set_bio(con, sbio, sbio); + SSL_set_accept_state(con); + /* SSL_set_fd(con,s); */ + + if (s_debug) { + SSL_set_debug(con, 1); + BIO_set_callback(SSL_get_rbio(con), bio_dump_callback); + BIO_set_callback_arg(SSL_get_rbio(con), (char *) bio_s_out); + } + if (s_msg) { + SSL_set_msg_callback(con, msg_cb); + SSL_set_msg_callback_arg(con, bio_s_out); + } + if (s_tlsextdebug) { + SSL_set_tlsext_debug_callback(con, tlsext_cb); + SSL_set_tlsext_debug_arg(con, bio_s_out); + } + + for (;;) { + int read_from_terminal; + int read_from_sslcon; + struct pollfd pfd[2]; + int ptimeout; + + read_from_terminal = 0; + read_from_sslcon = SSL_pending(con); + + if (!read_from_sslcon) { + pfd[0].fd = fileno(stdin); + pfd[0].events = POLLIN; + pfd[1].fd = s; + pfd[1].events = POLLIN; + + if ((SSL_version(con) == DTLS1_VERSION) && + DTLSv1_get_timeout(con, &timeout)) + ptimeout = timeout.tv_sec * 1000 + + timeout.tv_usec / 1000; + else + ptimeout = -1; + + i = poll(pfd, 2, ptimeout); + + if ((SSL_version(con) == DTLS1_VERSION) && DTLSv1_handle_timeout(con) > 0) { + BIO_printf(bio_err, "TIMEOUT occured\n"); + } + if (i <= 0) + continue; + if (pfd[0].revents) { + if ((pfd[0].revents & (POLLERR|POLLNVAL))) + continue; + read_from_terminal = 1; + } + if (pfd[1].revents) { + if ((pfd[1].revents & (POLLERR|POLLNVAL))) + continue; + read_from_sslcon = 1; + } + } + if (read_from_terminal) { + if (s_crlf) { + int j, lf_num; + + i = read(fileno(stdin), buf, bufsize / 2); + lf_num = 0; + /* both loops are skipped when i <= 0 */ + for (j = 0; j < i; j++) + if (buf[j] == '\n') + lf_num++; + for (j = i - 1; j >= 0; j--) { + buf[j + lf_num] = buf[j]; + if (buf[j] == '\n') { + lf_num--; + i++; + buf[j + lf_num] = '\r'; + } + } + assert(lf_num == 0); + } else + i = read(fileno(stdin), buf, bufsize); + if (!s_quiet) { + if ((i <= 0) || (buf[0] == 'Q')) { + BIO_printf(bio_s_out, "DONE\n"); + shutdown(s, SHUT_RD); + close(s); + close_accept_socket(); + ret = -11; + goto err; + } + if ((i <= 0) || (buf[0] == 'q')) { + BIO_printf(bio_s_out, "DONE\n"); + if (SSL_version(con) != DTLS1_VERSION) { + shutdown(s, SHUT_RD); + close(s); + } + /* + * close_accept_socket(); ret= -11; + */ + goto err; + } + if ((buf[0] == 'r') && + ((buf[1] == '\n') || (buf[1] == '\r'))) { + SSL_renegotiate(con); + i = SSL_do_handshake(con); + printf("SSL_do_handshake -> %d\n", i); + i = 0; /* 13; */ + continue; + /* + * RE-NEGOTIATE\n"); + */ + } + if ((buf[0] == 'R') && + ((buf[1] == '\n') || (buf[1] == '\r'))) { + SSL_set_verify(con, + SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, NULL); + SSL_renegotiate(con); + i = SSL_do_handshake(con); + printf("SSL_do_handshake -> %d\n", i); + i = 0; /* 13; */ + continue; + /* + * RE-NEGOTIATE asking for client + * cert\n"); + */ + } + if (buf[0] == 'P') { + static const char *str = "Lets print some clear text\n"; + BIO_write(SSL_get_wbio(con), str, strlen(str)); + } + if (buf[0] == 'S') { + print_stats(bio_s_out, SSL_get_SSL_CTX(con)); + } + } + l = k = 0; + for (;;) { + /* should do a select for the write */ +#ifdef RENEG + { + static count = 0; + if (++count == 100) { + count = 0; + SSL_renegotiate(con); + } + } +#endif + k = SSL_write(con, &(buf[l]), (unsigned int) i); + switch (SSL_get_error(con, k)) { + case SSL_ERROR_NONE: + break; + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_X509_LOOKUP: + BIO_printf(bio_s_out, "Write BLOCK\n"); + break; + case SSL_ERROR_SYSCALL: + case SSL_ERROR_SSL: + BIO_printf(bio_s_out, "ERROR\n"); + ERR_print_errors(bio_err); + ret = 1; + goto err; + /* break; */ + case SSL_ERROR_ZERO_RETURN: + BIO_printf(bio_s_out, "DONE\n"); + ret = 1; + goto err; + } + l += k; + i -= k; + if (i <= 0) + break; + } + } + if (read_from_sslcon) { + if (!SSL_is_init_finished(con)) { + i = init_ssl_connection(con); + + if (i < 0) { + ret = 0; + goto err; + } else if (i == 0) { + ret = 1; + goto err; + } + } else { + again: + i = SSL_read(con, (char *) buf, bufsize); + switch (SSL_get_error(con, i)) { + case SSL_ERROR_NONE: { + int len, n; + for (len = 0; len < i;) { + do { + n = write(fileno(stdout), buf + len, i - len); + } while (n == -1 && errno == EINTR); + + if (n < 0) { + BIO_printf(bio_s_out, "ERROR\n"); + goto err; + } + len += n; + } + } + if (SSL_pending(con)) + goto again; + break; + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_READ: + BIO_printf(bio_s_out, "Read BLOCK\n"); + break; + case SSL_ERROR_SYSCALL: + case SSL_ERROR_SSL: + BIO_printf(bio_s_out, "ERROR\n"); + ERR_print_errors(bio_err); + ret = 1; + goto err; + case SSL_ERROR_ZERO_RETURN: + BIO_printf(bio_s_out, "DONE\n"); + ret = 1; + goto err; + } + } + } + } +err: + if (con != NULL) { + BIO_printf(bio_s_out, "shutting down SSL\n"); + SSL_set_shutdown(con, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); + SSL_free(con); + } + BIO_printf(bio_s_out, "CONNECTION CLOSED\n"); + if (buf != NULL) { + explicit_bzero(buf, bufsize); + free(buf); + } + if (ret >= 0) + BIO_printf(bio_s_out, "ACCEPT\n"); + return (ret); +} + +static void +close_accept_socket(void) +{ + BIO_printf(bio_err, "shutdown accept socket\n"); + if (accept_socket >= 0) { + shutdown(accept_socket, SHUT_RDWR); + close(accept_socket); + } +} + +static int +init_ssl_connection(SSL * con) +{ + int i; + const char *str; + X509 *peer; + long verify_error; + char buf[BUFSIZ]; + const unsigned char *next_proto_neg; + unsigned next_proto_neg_len; + unsigned char *exportedkeymat; + + i = SSL_accept(con); + if (i <= 0) { + if (BIO_sock_should_retry(i)) { + BIO_printf(bio_s_out, "DELAY\n"); + return (1); + } + BIO_printf(bio_err, "ERROR\n"); + verify_error = SSL_get_verify_result(con); + if (verify_error != X509_V_OK) { + BIO_printf(bio_err, "verify error:%s\n", + X509_verify_cert_error_string(verify_error)); + } else + ERR_print_errors(bio_err); + return (0); + } + PEM_write_bio_SSL_SESSION(bio_s_out, SSL_get_session(con)); + + peer = SSL_get_peer_certificate(con); + if (peer != NULL) { + BIO_printf(bio_s_out, "Client certificate\n"); + PEM_write_bio_X509(bio_s_out, peer); + X509_NAME_oneline(X509_get_subject_name(peer), buf, sizeof buf); + BIO_printf(bio_s_out, "subject=%s\n", buf); + X509_NAME_oneline(X509_get_issuer_name(peer), buf, sizeof buf); + BIO_printf(bio_s_out, "issuer=%s\n", buf); + X509_free(peer); + } + if (SSL_get_shared_ciphers(con, buf, sizeof buf) != NULL) + BIO_printf(bio_s_out, "Shared ciphers:%s\n", buf); + str = SSL_CIPHER_get_name(SSL_get_current_cipher(con)); + BIO_printf(bio_s_out, "CIPHER is %s\n", (str != NULL) ? str : "(NONE)"); + + SSL_get0_next_proto_negotiated(con, &next_proto_neg, &next_proto_neg_len); + if (next_proto_neg) { + BIO_printf(bio_s_out, "NEXTPROTO is "); + BIO_write(bio_s_out, next_proto_neg, next_proto_neg_len); + BIO_printf(bio_s_out, "\n"); + } +#ifndef OPENSSL_NO_SRTP + { + SRTP_PROTECTION_PROFILE *srtp_profile + = SSL_get_selected_srtp_profile(con); + + if (srtp_profile) + BIO_printf(bio_s_out, "SRTP Extension negotiated, profile=%s\n", + srtp_profile->name); + } +#endif + if (SSL_cache_hit(con)) + BIO_printf(bio_s_out, "Reused session-id\n"); + BIO_printf(bio_s_out, "Secure Renegotiation IS%s supported\n", + SSL_get_secure_renegotiation_support(con) ? "" : " NOT"); + if (keymatexportlabel != NULL) { + BIO_printf(bio_s_out, "Keying material exporter:\n"); + BIO_printf(bio_s_out, " Label: '%s'\n", keymatexportlabel); + BIO_printf(bio_s_out, " Length: %i bytes\n", + keymatexportlen); + exportedkeymat = malloc(keymatexportlen); + if (exportedkeymat != NULL) { + if (!SSL_export_keying_material(con, exportedkeymat, + keymatexportlen, + keymatexportlabel, + strlen(keymatexportlabel), + NULL, 0, 0)) { + BIO_printf(bio_s_out, " Error\n"); + } else { + BIO_printf(bio_s_out, " Keying material: "); + for (i = 0; i < keymatexportlen; i++) + BIO_printf(bio_s_out, "%02X", + exportedkeymat[i]); + BIO_printf(bio_s_out, "\n"); + } + free(exportedkeymat); + } + } + return (1); +} + +#ifndef OPENSSL_NO_DH +static DH * +load_dh_param(const char *dhfile) +{ + DH *ret = NULL; + BIO *bio; + + if ((bio = BIO_new_file(dhfile, "r")) == NULL) + goto err; + ret = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); +err: + BIO_free(bio); + return (ret); +} +#endif + +static int +www_body(char *hostname, int s, unsigned char *context) +{ + char *buf = NULL; + int ret = 1; + int i, j, k, dot; + SSL *con; + const SSL_CIPHER *c; + BIO *io, *ssl_bio, *sbio; + + buf = malloc(bufsize); + if (buf == NULL) + return (0); + io = BIO_new(BIO_f_buffer()); + ssl_bio = BIO_new(BIO_f_ssl()); + if ((io == NULL) || (ssl_bio == NULL)) + goto err; + + if (s_nbio) { + if (!s_quiet) + BIO_printf(bio_err, "turning on non blocking io\n"); + if (!BIO_socket_nbio(s, 1)) + ERR_print_errors(bio_err); + } + + /* lets make the output buffer a reasonable size */ + if (!BIO_set_write_buffer_size(io, bufsize)) + goto err; + + if ((con = SSL_new(ctx)) == NULL) + goto err; + if (s_tlsextdebug) { + SSL_set_tlsext_debug_callback(con, tlsext_cb); + SSL_set_tlsext_debug_arg(con, bio_s_out); + } + if (context) + SSL_set_session_id_context(con, context, + strlen((char *) context)); + + sbio = BIO_new_socket(s, BIO_NOCLOSE); + if (s_nbio_test) { + BIO *test; + + test = BIO_new(BIO_f_nbio_test()); + sbio = BIO_push(test, sbio); + } + SSL_set_bio(con, sbio, sbio); + SSL_set_accept_state(con); + + /* SSL_set_fd(con,s); */ + BIO_set_ssl(ssl_bio, con, BIO_CLOSE); + BIO_push(io, ssl_bio); + + if (s_debug) { + SSL_set_debug(con, 1); + BIO_set_callback(SSL_get_rbio(con), bio_dump_callback); + BIO_set_callback_arg(SSL_get_rbio(con), (char *) bio_s_out); + } + if (s_msg) { + SSL_set_msg_callback(con, msg_cb); + SSL_set_msg_callback_arg(con, bio_s_out); + } + for (;;) { + i = BIO_gets(io, buf, bufsize - 1); + if (i < 0) { /* error */ + if (!BIO_should_retry(io)) { + if (!s_quiet) + ERR_print_errors(bio_err); + goto err; + } else { + BIO_printf(bio_s_out, "read R BLOCK\n"); + sleep(1); + continue; + } + } else if (i == 0) { /* end of input */ + ret = 1; + goto end; + } + /* else we have data */ + if (((www == 1) && (strncmp("GET ", buf, 4) == 0)) || + ((www == 2) && (strncmp("GET /stats ", buf, 11) == 0))) { + char *p; + X509 *peer; + STACK_OF(SSL_CIPHER) * sk; + static const char *space = " "; + + BIO_puts(io, "HTTP/1.0 200 ok\r\nContent-type: text/html\r\n\r\n"); + BIO_puts(io, "\n"); + BIO_puts(io, "
\n");
+/*			BIO_puts(io,SSLeay_version(SSLEAY_VERSION));*/
+			BIO_puts(io, "\n");
+			for (i = 0; i < local_argc; i++) {
+				BIO_puts(io, local_argv[i]);
+				BIO_write(io, " ", 1);
+			}
+			BIO_puts(io, "\n");
+
+			BIO_printf(io,
+			    "Secure Renegotiation IS%s supported\n",
+			    SSL_get_secure_renegotiation_support(con) ?
+			    "" : " NOT");
+
+			/*
+			 * The following is evil and should not really be
+			 * done
+			 */
+			BIO_printf(io, "Ciphers supported in s_server binary\n");
+			sk = SSL_get_ciphers(con);
+			j = sk_SSL_CIPHER_num(sk);
+			for (i = 0; i < j; i++) {
+				c = sk_SSL_CIPHER_value(sk, i);
+				BIO_printf(io, "%-11s:%-25s",
+				    SSL_CIPHER_get_version(c),
+				    SSL_CIPHER_get_name(c));
+				if ((((i + 1) % 2) == 0) && (i + 1 != j))
+					BIO_puts(io, "\n");
+			}
+			BIO_puts(io, "\n");
+			p = SSL_get_shared_ciphers(con, buf, bufsize);
+			if (p != NULL) {
+				BIO_printf(io, "---\nCiphers common between both SSL end points:\n");
+				j = i = 0;
+				while (*p) {
+					if (*p == ':') {
+						BIO_write(io, space, 26 - j);
+						i++;
+						j = 0;
+						BIO_write(io, ((i % 3) ? " " : "\n"), 1);
+					} else {
+						BIO_write(io, p, 1);
+						j++;
+					}
+					p++;
+				}
+				BIO_puts(io, "\n");
+			}
+			BIO_printf(io, (SSL_cache_hit(con)
+				? "---\nReused, "
+				: "---\nNew, "));
+			c = SSL_get_current_cipher(con);
+			BIO_printf(io, "%s, Cipher is %s\n",
+			    SSL_CIPHER_get_version(c),
+			    SSL_CIPHER_get_name(c));
+			SSL_SESSION_print(io, SSL_get_session(con));
+			BIO_printf(io, "---\n");
+			print_stats(io, SSL_get_SSL_CTX(con));
+			BIO_printf(io, "---\n");
+			peer = SSL_get_peer_certificate(con);
+			if (peer != NULL) {
+				BIO_printf(io, "Client certificate\n");
+				X509_print(io, peer);
+				PEM_write_bio_X509(io, peer);
+			} else
+				BIO_puts(io, "no client certificate available\n");
+			BIO_puts(io, "\r\n\r\n");
+			break;
+		} else if ((www == 2 || www == 3)
+		    && (strncmp("GET /", buf, 5) == 0)) {
+			BIO *file;
+			char *p, *e;
+			static const char *text = "HTTP/1.0 200 ok\r\nContent-type: text/plain\r\n\r\n";
+
+			/* skip the '/' */
+			p = &(buf[5]);
+
+			dot = 1;
+			for (e = p; *e != '\0'; e++) {
+				if (e[0] == ' ')
+					break;
+
+				switch (dot) {
+				case 1:
+					dot = (e[0] == '.') ? 2 : 0;
+					break;
+				case 2:
+					dot = (e[0] == '.') ? 3 : 0;
+					break;
+				case 3:
+					dot = (e[0] == '/') ? -1 : 0;
+					break;
+				}
+				if (dot == 0)
+					dot = (e[0] == '/') ? 1 : 0;
+			}
+			dot = (dot == 3) || (dot == -1);	/* filename contains
+								 * ".." component */
+
+			if (*e == '\0') {
+				BIO_puts(io, text);
+				BIO_printf(io, "'%s' is an invalid file name\r\n", p);
+				break;
+			}
+			*e = '\0';
+
+			if (dot) {
+				BIO_puts(io, text);
+				BIO_printf(io, "'%s' contains '..' reference\r\n", p);
+				break;
+			}
+			if (*p == '/') {
+				BIO_puts(io, text);
+				BIO_printf(io, "'%s' is an invalid path\r\n", p);
+				break;
+			}
+			/* if a directory, do the index thang */
+			if (app_isdir(p) > 0) {
+				BIO_puts(io, text);
+				BIO_printf(io, "'%s' is a directory\r\n", p);
+				break;
+			}
+			if ((file = BIO_new_file(p, "r")) == NULL) {
+				BIO_puts(io, text);
+				BIO_printf(io, "Error opening '%s'\r\n", p);
+				ERR_print_errors(io);
+				break;
+			}
+			if (!s_quiet)
+				BIO_printf(bio_err, "FILE:%s\n", p);
+
+			if (www == 2) {
+				i = strlen(p);
+				if (((i > 5) && (strcmp(&(p[i - 5]), ".html") == 0)) ||
+				    ((i > 4) && (strcmp(&(p[i - 4]), ".php") == 0)) ||
+				    ((i > 4) && (strcmp(&(p[i - 4]), ".htm") == 0)))
+					BIO_puts(io, "HTTP/1.0 200 ok\r\nContent-type: text/html\r\n\r\n");
+				else
+					BIO_puts(io, "HTTP/1.0 200 ok\r\nContent-type: text/plain\r\n\r\n");
+			}
+			/* send the file */
+			for (;;) {
+				i = BIO_read(file, buf, bufsize);
+				if (i <= 0)
+					break;
+
+#ifdef RENEG
+				total_bytes += i;
+				fprintf(stderr, "%d\n", i);
+				if (total_bytes > 3 * 1024) {
+					total_bytes = 0;
+					fprintf(stderr, "RENEGOTIATE\n");
+					SSL_renegotiate(con);
+				}
+#endif
+
+				for (j = 0; j < i;) {
+#ifdef RENEG
+					{
+						static count = 0;
+						if (++count == 13) {
+							SSL_renegotiate(con);
+						}
+					}
+#endif
+					k = BIO_write(io, &(buf[j]), i - j);
+					if (k <= 0) {
+						if (!BIO_should_retry(io))
+							goto write_error;
+						else {
+							BIO_printf(bio_s_out, "rwrite W BLOCK\n");
+						}
+					} else {
+						j += k;
+					}
+				}
+			}
+	write_error:
+			BIO_free(file);
+			break;
+		}
+	}
+
+	for (;;) {
+		i = (int) BIO_flush(io);
+		if (i <= 0) {
+			if (!BIO_should_retry(io))
+				break;
+		} else
+			break;
+	}
+end:
+	/* make sure we re-use sessions */
+	SSL_set_shutdown(con, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
+
+err:
+
+	if (ret >= 0)
+		BIO_printf(bio_s_out, "ACCEPT\n");
+
+	free(buf);
+	if (io != NULL)
+		BIO_free_all(io);
+/*	if (ssl_bio != NULL) BIO_free(ssl_bio);*/
+	return (ret);
+}
+
+#define MAX_SESSION_ID_ATTEMPTS 10
+static int
+generate_session_id(const SSL * ssl, unsigned char *id,
+    unsigned int *id_len)
+{
+	unsigned int count = 0;
+	do {
+		arc4random_buf(id, *id_len);
+		/*
+		 * Prefix the session_id with the required prefix. NB: If our
+		 * prefix is too long, clip it - but there will be worse
+		 * effects anyway, eg. the server could only possibly create
+		 * 1 session ID (ie. the prefix!) so all future session
+		 * negotiations will fail due to conflicts.
+		 */
+		memcpy(id, session_id_prefix,
+		    (strlen(session_id_prefix) < *id_len) ?
+		    strlen(session_id_prefix) : *id_len);
+	}
+	while (SSL_has_matching_session_id(ssl, id, *id_len) &&
+	    (++count < MAX_SESSION_ID_ATTEMPTS));
+	if (count >= MAX_SESSION_ID_ATTEMPTS)
+		return 0;
+	return 1;
+}
diff --git a/bin/openssl/s_socket.c b/bin/openssl/s_socket.c
new file mode 100644
index 0000000000..869211de73
--- /dev/null
+++ b/bin/openssl/s_socket.c
@@ -0,0 +1,338 @@
+/* $OpenBSD: s_socket.c,v 1.8 2015/09/10 02:23:29 lteo Exp $ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include 
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "apps.h"
+
+#include 
+
+#include "s_apps.h"
+
+static int init_server(int *sock, int port, int type);
+static int init_server_long(int *sock, int port, char *ip, int type);
+static int do_accept(int acc_sock, int *sock, char **host);
+
+int
+init_client(int *sock, char *host, char *port, int type, int af)
+{
+	struct addrinfo hints, *ai_top, *ai;
+	int i, s = -1;
+
+	memset(&hints, '\0', sizeof(hints));
+	hints.ai_family = af;
+	hints.ai_socktype = type;
+
+	if ((i = getaddrinfo(host, port, &hints, &ai_top)) != 0) {
+		BIO_printf(bio_err, "getaddrinfo: %s\n", gai_strerror(i));
+		return (0);
+	}
+	if (ai_top == NULL || ai_top->ai_addr == NULL) {
+		BIO_printf(bio_err, "getaddrinfo returned no addresses\n");
+		if (ai_top != NULL) {
+			freeaddrinfo(ai_top);
+		}
+		return (0);
+	}
+	for (ai = ai_top; ai != NULL; ai = ai->ai_next) {
+		s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+		if (s == -1) {
+			continue;
+		}
+		if (type == SOCK_STREAM) {
+			i = 0;
+			i = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
+			    (char *) &i, sizeof(i));
+			if (i < 0) {
+				perror("keepalive");
+				goto out;
+			}
+		}
+		if ((i = connect(s, ai->ai_addr, ai->ai_addrlen)) == 0) {
+			*sock = s;
+			freeaddrinfo(ai_top);
+			return (1);
+		}
+		close(s);
+		s = -1;
+	}
+
+	perror("connect");
+out:
+	if (s != -1)
+		close(s);
+	freeaddrinfo(ai_top);
+	return (0);
+}
+
+int
+do_server(int port, int type, int *ret,
+    int (*cb) (char *hostname, int s, unsigned char *context),
+    unsigned char *context)
+{
+	int sock;
+	char *name = NULL;
+	int accept_socket = 0;
+	int i;
+
+	if (!init_server(&accept_socket, port, type))
+		return (0);
+
+	if (ret != NULL) {
+		*ret = accept_socket;
+		/* return(1); */
+	}
+	for (;;) {
+		if (type == SOCK_STREAM) {
+			if (do_accept(accept_socket, &sock, &name) == 0) {
+				shutdown(accept_socket, SHUT_RD);
+				close(accept_socket);
+				return (0);
+			}
+		} else
+			sock = accept_socket;
+		i = (*cb) (name, sock, context);
+		free(name);
+		if (type == SOCK_STREAM) {
+			shutdown(sock, SHUT_RDWR);
+			close(sock);
+		}
+		if (i < 0) {
+			shutdown(accept_socket, SHUT_RDWR);
+			close(accept_socket);
+			return (i);
+		}
+	}
+}
+
+static int
+init_server_long(int *sock, int port, char *ip, int type)
+{
+	int ret = 0;
+	struct sockaddr_in server;
+	int s = -1;
+
+	memset((char *) &server, 0, sizeof(server));
+	server.sin_family = AF_INET;
+	server.sin_port = htons((unsigned short) port);
+	if (ip == NULL)
+		server.sin_addr.s_addr = INADDR_ANY;
+	else
+		memcpy(&server.sin_addr.s_addr, ip, 4);
+
+	if (type == SOCK_STREAM)
+		s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+	else			/* type == SOCK_DGRAM */
+		s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+
+	if (s == -1)
+		goto err;
+#if defined SOL_SOCKET && defined SO_REUSEADDR
+	{
+		int j = 1;
+		if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+		    (void *) &j, sizeof j) == -1) {
+			perror("setsockopt");
+			goto err;
+		}
+	}
+#endif
+	if (bind(s, (struct sockaddr *) & server, sizeof(server)) == -1) {
+		perror("bind");
+		goto err;
+	}
+	/* Make it 128 for linux */
+	if (type == SOCK_STREAM && listen(s, 128) == -1)
+		goto err;
+	*sock = s;
+	ret = 1;
+err:
+	if ((ret == 0) && (s != -1)) {
+		shutdown(s, SHUT_RD);
+		close(s);
+	}
+	return (ret);
+}
+
+static int
+init_server(int *sock, int port, int type)
+{
+	return (init_server_long(sock, port, NULL, type));
+}
+
+static int
+do_accept(int acc_sock, int *sock, char **host)
+{
+	int ret;
+	struct hostent *h1, *h2;
+	static struct sockaddr_in from;
+	socklen_t len;
+/*	struct linger ling; */
+
+redoit:
+
+	memset((char *) &from, 0, sizeof(from));
+	len = sizeof(from);
+	ret = accept(acc_sock, (struct sockaddr *) & from, &len);
+	if (ret == -1) {
+		if (errno == EINTR) {
+			/* check_timeout(); */
+			goto redoit;
+		}
+		fprintf(stderr, "errno=%d ", errno);
+		perror("accept");
+		return (0);
+	}
+/*
+	ling.l_onoff=1;
+	ling.l_linger=0;
+	i=setsockopt(ret,SOL_SOCKET,SO_LINGER,(char *)&ling,sizeof(ling));
+	if (i < 0) { perror("linger"); return(0); }
+	i=0;
+	i=setsockopt(ret,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
+	if (i < 0) { perror("keepalive"); return(0); }
+*/
+
+	if (host == NULL)
+		goto end;
+	h1 = gethostbyaddr((char *) &from.sin_addr.s_addr,
+	    sizeof(from.sin_addr.s_addr), AF_INET);
+	if (h1 == NULL) {
+		BIO_printf(bio_err, "bad gethostbyaddr\n");
+		*host = NULL;
+		/* return(0); */
+	} else {
+		if ((*host = strdup(h1->h_name)) == NULL) {
+			perror("strdup");
+			close(ret);
+			return (0);
+		}
+
+		h2 = gethostbyname(*host);
+		if (h2 == NULL) {
+			BIO_printf(bio_err, "gethostbyname failure\n");
+			close(ret);
+			return (0);
+		}
+		if (h2->h_addrtype != AF_INET) {
+			BIO_printf(bio_err, "gethostbyname addr is not AF_INET\n");
+			close(ret);
+			return (0);
+		}
+	}
+
+end:
+	*sock = ret;
+	return (1);
+}
+
+int
+extract_host_port(char *str, char **host_ptr, unsigned char *ip,
+    char **port_ptr)
+{
+	char *h, *p;
+
+	h = str;
+	p = strrchr(str, '/');	/* IPv6 host/port */
+	if (p == NULL) {
+		p = strrchr(str, ':');
+	}
+	if (p == NULL) {
+		BIO_printf(bio_err, "no port defined\n");
+		return (0);
+	}
+	*(p++) = '\0';
+
+	if (host_ptr != NULL)
+		*host_ptr = h;
+
+	if (port_ptr != NULL && p != NULL && *p != '\0')
+		*port_ptr = p;
+
+	return (1);
+}
+
+int
+extract_port(char *str, short *port_ptr)
+{
+	int i;
+	const char *errstr;
+	struct servent *s;
+
+	i = strtonum(str, 1, 65535, &errstr);
+	if (!errstr) {
+		*port_ptr = (unsigned short) i;
+	} else {
+		s = getservbyname(str, "tcp");
+		if (s == NULL) {
+			BIO_printf(bio_err, "getservbyname failure for %s\n", str);
+			return (0);
+		}
+		*port_ptr = ntohs((unsigned short) s->s_port);
+	}
+	return (1);
+}
diff --git a/bin/openssl/s_time.c b/bin/openssl/s_time.c
new file mode 100644
index 0000000000..3644e108f8
--- /dev/null
+++ b/bin/openssl/s_time.c
@@ -0,0 +1,552 @@
+/* $OpenBSD: s_time.c,v 1.17 2017/01/20 08:57:12 deraadt Exp $ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+/*-----------------------------------------
+   s_time - SSL client connection timer program
+   Written and donated by Larry Streepy 
+  -----------------------------------------*/
+
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "apps.h"
+
+#include 
+#include 
+#include 
+#include 
+
+#include "s_apps.h"
+
+#define SSL_CONNECT_NAME	"localhost:4433"
+
+#define BUFSIZZ 1024*10
+
+#define MYBUFSIZ 1024*8
+
+#define SECONDS	30
+extern int verify_depth;
+extern int verify_error;
+
+static void s_time_usage(void);
+static SSL *doConnection(SSL * scon);
+
+static SSL_CTX *tm_ctx = NULL;
+static const SSL_METHOD *s_time_meth = NULL;
+static long bytes_read = 0;
+
+struct {
+	int bugs;
+	char *CAfile;
+	char *CApath;
+	char *certfile;
+	char *cipher;
+	char *host;
+	char *keyfile;
+	time_t maxtime;
+	int nbio;
+	int no_shutdown;
+	int perform;
+	int verify;
+	int verify_depth;
+	char *www_path;
+} s_time_config;
+
+struct option s_time_options[] = {
+	{
+		.name = "bugs",
+		.desc = "Enable workarounds for known SSL/TLS bugs",
+		.type = OPTION_FLAG,
+		.opt.flag = &s_time_config.bugs,
+	},
+	{
+		.name = "CAfile",
+		.argname = "file",
+		.desc = "File containing trusted certificates in PEM format",
+		.type = OPTION_ARG,
+		.opt.arg = &s_time_config.CAfile,
+	},
+	{
+		.name = "CApath",
+		.argname = "path",
+		.desc = "Directory containing trusted certificates",
+		.type = OPTION_ARG,
+		.opt.arg = &s_time_config.CApath,
+	},
+	{
+		.name = "cert",
+		.argname = "file",
+		.desc = "Client certificate to use, if one is requested",
+		.type = OPTION_ARG,
+		.opt.arg = &s_time_config.certfile,
+	},
+	{
+		.name = "cipher",
+		.argname = "list",
+		.desc = "List of cipher suites to send to the server",
+		.type = OPTION_ARG,
+		.opt.arg = &s_time_config.cipher,
+	},
+	{
+		.name = "connect",
+		.argname = "host:port",
+		.desc = "Host and port to connect to (default "
+		    SSL_CONNECT_NAME ")",
+		.type = OPTION_ARG,
+		.opt.arg = &s_time_config.host,
+	},
+	{
+		.name = "key",
+		.argname = "file",
+		.desc = "Client private key to use, if one is required",
+		.type = OPTION_ARG,
+		.opt.arg = &s_time_config.keyfile,
+	},
+	{
+		.name = "nbio",
+		.desc = "Use non-blocking I/O",
+		.type = OPTION_FLAG,
+		.opt.flag = &s_time_config.nbio,
+	},
+	{
+		.name = "new",
+		.desc = "Use a new session ID for each connection",
+		.type = OPTION_VALUE,
+		.opt.value = &s_time_config.perform,
+		.value = 1,
+	},
+	{
+		.name = "no_shutdown",
+		.desc = "Shut down the connection without notifying the server",
+		.type = OPTION_FLAG,
+		.opt.flag = &s_time_config.no_shutdown,
+	},
+	{
+		.name = "reuse",
+		.desc = "Reuse the same session ID for each connection",
+		.type = OPTION_VALUE,
+		.opt.value = &s_time_config.perform,
+		.value = 2,
+	},
+	{
+		.name = "time",
+		.argname = "seconds",
+		.desc = "Duration to perform timing tests for (default 30)",
+		.type = OPTION_ARG_TIME,
+		.opt.tvalue = &s_time_config.maxtime,
+	},
+	{
+		.name = "verify",
+		.argname = "depth",
+		.desc = "Enable peer certificate verification with given depth",
+		.type = OPTION_ARG_INT,
+		.opt.value = &s_time_config.verify_depth,
+	},
+	{
+		.name = "www",
+		.argname = "page",
+		.desc = "Page to GET from the server (default none)",
+		.type = OPTION_ARG,
+		.opt.arg = &s_time_config.www_path,
+	},
+	{ NULL },
+};
+
+static void
+s_time_usage(void)
+{
+	fprintf(stderr,
+	    "usage: s_time "
+	    "[-bugs] [-CAfile file] [-CApath directory] [-cert file]\n"
+	    "    [-cipher cipherlist] [-connect host:port] [-key keyfile]\n"
+	    "    [-nbio] [-new] [-no_shutdown] [-reuse] [-time seconds]\n"
+	    "    [-verify depth] [-www page]\n\n");
+	options_usage(s_time_options);
+}
+
+/***********************************************************************
+ * TIME - time functions
+ */
+#define START	0
+#define STOP	1
+
+static double
+tm_Time_F(int s)
+{
+	return app_tminterval(s, 1);
+}
+
+/***********************************************************************
+ * MAIN - main processing area for client
+ *			real name depends on MONOLITH
+ */
+int
+s_time_main(int argc, char **argv)
+{
+	double totalTime = 0.0;
+	int nConn = 0;
+	SSL *scon = NULL;
+	time_t finishtime;
+	int ret = 1;
+	char buf[1024 * 8];
+	int ver;
+
+	if (single_execution) {
+		if (pledge("stdio rpath inet", NULL) == -1) {
+			perror("pledge");
+			exit(1);
+		}
+	}
+
+	s_time_meth = SSLv23_client_method();
+
+	verify_depth = 0;
+
+	memset(&s_time_config, 0, sizeof(s_time_config));
+
+	s_time_config.host = SSL_CONNECT_NAME;
+	s_time_config.maxtime = SECONDS;
+	s_time_config.perform = 3;
+	s_time_config.verify = SSL_VERIFY_NONE;
+	s_time_config.verify_depth = -1;
+
+	if (options_parse(argc, argv, s_time_options, NULL, NULL) != 0) {
+		s_time_usage();
+		goto end;
+	}
+
+	if (s_time_config.verify_depth >= 0) {
+		s_time_config.verify = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE;
+		verify_depth = s_time_config.verify_depth;
+		BIO_printf(bio_err, "verify depth is %d\n", verify_depth);
+	}
+
+	if (s_time_config.www_path != NULL &&
+	    strlen(s_time_config.www_path) > MYBUFSIZ - 100) {
+		BIO_printf(bio_err, "-www option too long\n");
+		goto end;
+	}
+
+	if ((tm_ctx = SSL_CTX_new(s_time_meth)) == NULL)
+		return (1);
+
+	SSL_CTX_set_quiet_shutdown(tm_ctx, 1);
+
+	if (s_time_config.bugs)
+		SSL_CTX_set_options(tm_ctx, SSL_OP_ALL);
+
+	if (s_time_config.cipher != NULL) {
+		if (!SSL_CTX_set_cipher_list(tm_ctx, s_time_config.cipher)) {
+			BIO_printf(bio_err, "error setting cipher list\n");
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+	}
+
+	SSL_CTX_set_verify(tm_ctx, s_time_config.verify, NULL);
+
+	if (!set_cert_stuff(tm_ctx, s_time_config.certfile,
+	    s_time_config.keyfile))
+		goto end;
+
+	if ((!SSL_CTX_load_verify_locations(tm_ctx, s_time_config.CAfile,
+	    s_time_config.CApath)) ||
+	    (!SSL_CTX_set_default_verify_paths(tm_ctx))) {
+		/*
+		 * BIO_printf(bio_err,"error setting default verify
+		 * locations\n");
+		 */
+		ERR_print_errors(bio_err);
+		/* goto end; */
+	}
+
+	if (!(s_time_config.perform & 1))
+		goto next;
+	printf("Collecting connection statistics for %lld seconds\n",
+	    (long long)s_time_config.maxtime);
+
+	/* Loop and time how long it takes to make connections */
+
+	bytes_read = 0;
+	finishtime = time(NULL) + s_time_config.maxtime;
+	tm_Time_F(START);
+	for (;;) {
+		if (finishtime < time(NULL))
+			break;
+		if ((scon = doConnection(NULL)) == NULL)
+			goto end;
+
+		if (s_time_config.www_path != NULL) {
+			int i, retval = snprintf(buf, sizeof buf,
+			    "GET %s HTTP/1.0\r\n\r\n", s_time_config.www_path);
+			if ((size_t)retval >= sizeof buf) {
+				fprintf(stderr, "URL too long\n");
+				goto end;
+			}
+			SSL_write(scon, buf, strlen(buf));
+			while ((i = SSL_read(scon, buf, sizeof(buf))) > 0)
+				bytes_read += i;
+		}
+		if (s_time_config.no_shutdown)
+			SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN |
+			    SSL_RECEIVED_SHUTDOWN);
+		else
+			SSL_shutdown(scon);
+		shutdown(SSL_get_fd(scon), SHUT_RDWR);
+		close(SSL_get_fd(scon));
+
+		nConn += 1;
+		if (SSL_session_reused(scon))
+			ver = 'r';
+		else {
+			ver = SSL_version(scon);
+			if (ver == TLS1_VERSION)
+				ver = 't';
+			else if (ver == SSL3_VERSION)
+				ver = '3';
+			else if (ver == SSL2_VERSION)
+				ver = '2';
+			else
+				ver = '*';
+		}
+		fputc(ver, stdout);
+		fflush(stdout);
+
+		SSL_free(scon);
+		scon = NULL;
+	}
+	totalTime += tm_Time_F(STOP);	/* Add the time for this iteration */
+
+	printf("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n",
+	    nConn, totalTime, ((double) nConn / totalTime), bytes_read);
+	printf("%d connections in %lld real seconds, %ld bytes read per connection\n",
+	    nConn,
+	    (long long)(time(NULL) - finishtime + s_time_config.maxtime),
+	    bytes_read / nConn);
+
+	/*
+	 * Now loop and time connections using the same session id over and
+	 * over
+	 */
+
+next:
+	if (!(s_time_config.perform & 2))
+		goto end;
+	printf("\n\nNow timing with session id reuse.\n");
+
+	/* Get an SSL object so we can reuse the session id */
+	if ((scon = doConnection(NULL)) == NULL) {
+		fprintf(stderr, "Unable to get connection\n");
+		goto end;
+	}
+	if (s_time_config.www_path != NULL) {
+		int retval = snprintf(buf, sizeof buf,
+		    "GET %s HTTP/1.0\r\n\r\n", s_time_config.www_path);
+		if ((size_t)retval >= sizeof buf) {
+			fprintf(stderr, "URL too long\n");
+			goto end;
+		}
+		SSL_write(scon, buf, strlen(buf));
+		while (SSL_read(scon, buf, sizeof(buf)) > 0);
+	}
+	if (s_time_config.no_shutdown)
+		SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN |
+		    SSL_RECEIVED_SHUTDOWN);
+	else
+		SSL_shutdown(scon);
+	shutdown(SSL_get_fd(scon), SHUT_RDWR);
+	close(SSL_get_fd(scon));
+
+	nConn = 0;
+	totalTime = 0.0;
+
+	finishtime = time(NULL) + s_time_config.maxtime;
+
+	printf("starting\n");
+	bytes_read = 0;
+	tm_Time_F(START);
+
+	for (;;) {
+		if (finishtime < time(NULL))
+			break;
+		if ((doConnection(scon)) == NULL)
+			goto end;
+
+		if (s_time_config.www_path) {
+			int i, retval = snprintf(buf, sizeof buf,
+			    "GET %s HTTP/1.0\r\n\r\n", s_time_config.www_path);
+			if ((size_t)retval >= sizeof buf) {
+				fprintf(stderr, "URL too long\n");
+				goto end;
+			}
+			SSL_write(scon, buf, strlen(buf));
+			while ((i = SSL_read(scon, buf, sizeof(buf))) > 0)
+				bytes_read += i;
+		}
+		if (s_time_config.no_shutdown)
+			SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN |
+			    SSL_RECEIVED_SHUTDOWN);
+		else
+			SSL_shutdown(scon);
+		shutdown(SSL_get_fd(scon), SHUT_RDWR);
+		close(SSL_get_fd(scon));
+
+		nConn += 1;
+		if (SSL_session_reused(scon))
+			ver = 'r';
+		else {
+			ver = SSL_version(scon);
+			if (ver == TLS1_VERSION)
+				ver = 't';
+			else if (ver == SSL3_VERSION)
+				ver = '3';
+			else if (ver == SSL2_VERSION)
+				ver = '2';
+			else
+				ver = '*';
+		}
+		fputc(ver, stdout);
+		fflush(stdout);
+	}
+	totalTime += tm_Time_F(STOP);	/* Add the time for this iteration */
+
+	printf("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", nConn, totalTime, ((double) nConn / totalTime), bytes_read);
+	printf("%d connections in %lld real seconds, %ld bytes read per connection\n",
+	    nConn,
+	    (long long)(time(NULL) - finishtime + s_time_config.maxtime),
+	    bytes_read / nConn);
+
+	ret = 0;
+end:
+	if (scon != NULL)
+		SSL_free(scon);
+
+	if (tm_ctx != NULL) {
+		SSL_CTX_free(tm_ctx);
+		tm_ctx = NULL;
+	}
+
+	return (ret);
+}
+
+/***********************************************************************
+ * doConnection - make a connection
+ * Args:
+ *		scon	= earlier ssl connection for session id, or NULL
+ * Returns:
+ *		SSL *	= the connection pointer.
+ */
+static SSL *
+doConnection(SSL * scon)
+{
+	struct pollfd pfd[1];
+	SSL *serverCon;
+	BIO *conn;
+	long verify_error;
+	int i;
+
+	if ((conn = BIO_new(BIO_s_connect())) == NULL)
+		return (NULL);
+
+/*	BIO_set_conn_port(conn,port);*/
+	BIO_set_conn_hostname(conn, s_time_config.host);
+
+	if (scon == NULL)
+		serverCon = SSL_new(tm_ctx);
+	else {
+		serverCon = scon;
+		SSL_set_connect_state(serverCon);
+	}
+
+	SSL_set_bio(serverCon, conn, conn);
+
+	/* ok, lets connect */
+	for (;;) {
+		i = SSL_connect(serverCon);
+		if (BIO_sock_should_retry(i)) {
+			BIO_printf(bio_err, "DELAY\n");
+
+			i = SSL_get_fd(serverCon);
+			pfd[0].fd = i;
+			pfd[0].events = POLLIN;
+			poll(pfd, 1, -1);
+			continue;
+		}
+		break;
+	}
+	if (i <= 0) {
+		BIO_printf(bio_err, "ERROR\n");
+		verify_error = SSL_get_verify_result(serverCon);
+		if (verify_error != X509_V_OK)
+			BIO_printf(bio_err, "verify error:%s\n",
+			    X509_verify_cert_error_string(verify_error));
+		else
+			ERR_print_errors(bio_err);
+		if (scon == NULL)
+			SSL_free(serverCon);
+		return NULL;
+	}
+	return serverCon;
+}
diff --git a/bin/openssl/sess_id.c b/bin/openssl/sess_id.c
new file mode 100644
index 0000000000..3670f5404f
--- /dev/null
+++ b/bin/openssl/sess_id.c
@@ -0,0 +1,295 @@
+/* $OpenBSD: sess_id.c,v 1.8 2017/01/20 08:57:12 deraadt Exp $ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include 
+#include 
+#include 
+
+#include "apps.h"
+#include "progs.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+static struct {
+	int cert;
+	char *context;
+	char *infile;
+	int informat;
+	int noout;
+	char *outfile;
+	int outformat;
+	int text;
+} sess_id_config;
+
+static struct option sess_id_options[] = {
+	{
+		.name = "cert",
+		.desc = "Output certificate if present in session",
+		.type = OPTION_FLAG,
+		.opt.flag = &sess_id_config.cert,
+	},
+	{
+		.name = "context",
+		.argname = "id",
+		.desc = "Set the session ID context for output",
+		.type = OPTION_ARG,
+		.opt.arg = &sess_id_config.context,
+	},
+	{
+		.name = "in",
+		.argname = "file",
+		.desc = "Input file (default stdin)",
+		.type = OPTION_ARG,
+		.opt.arg = &sess_id_config.infile,
+	},
+	{
+		.name = "inform",
+		.argname = "format",
+		.desc = "Input format (DER or PEM (default))",
+		.type = OPTION_ARG_FORMAT,
+		.opt.value = &sess_id_config.informat,
+	},
+	{
+		.name = "noout",
+		.desc = "Do not output the encoded session info",
+		.type = OPTION_FLAG,
+		.opt.flag = &sess_id_config.noout,
+	},
+	{
+		.name = "out",
+		.argname = "file",
+		.desc = "Output file (default stdout)",
+		.type = OPTION_ARG,
+		.opt.arg = &sess_id_config.outfile,
+	},
+	{
+		.name = "outform",
+		.argname = "format",
+		.desc = "Output format (DER or PEM (default))",
+		.type = OPTION_ARG_FORMAT,
+		.opt.value = &sess_id_config.outformat,
+	},
+	{
+		.name = "text",
+		.desc = "Print various public or private key components in"
+		    " plain text",
+		.type = OPTION_FLAG,
+		.opt.flag = &sess_id_config.text,
+	},
+	{ NULL }
+};
+
+static void
+sess_id_usage(void)
+{
+	fprintf(stderr,
+	    "usage: sess_id [-cert] [-context id] [-in file] [-inform fmt] "
+	    "[-noout]\n"
+	    "    [-out file] [-outform fmt] [-text]\n\n");
+	options_usage(sess_id_options);
+}
+
+static SSL_SESSION *load_sess_id(char *file, int format);
+
+int
+sess_id_main(int argc, char **argv)
+{
+	SSL_SESSION *x = NULL;
+	X509 *peer = NULL;
+	int ret = 1, i;
+	BIO *out = NULL;
+
+	if (single_execution) {
+		if (pledge("stdio cpath wpath rpath", NULL) == -1) {
+			perror("pledge");
+			exit(1);
+		}
+	}
+
+	memset(&sess_id_config, 0, sizeof(sess_id_config));
+
+	sess_id_config.informat = FORMAT_PEM;
+	sess_id_config.outformat = FORMAT_PEM;
+
+	if (options_parse(argc, argv, sess_id_options, NULL, NULL) != 0) {
+		sess_id_usage();
+		return (1);
+	}
+
+	x = load_sess_id(sess_id_config.infile, sess_id_config.informat);
+	if (x == NULL) {
+		goto end;
+	}
+	peer = SSL_SESSION_get0_peer(x);
+
+	if (sess_id_config.context) {
+		size_t ctx_len = strlen(sess_id_config.context);
+		if (ctx_len > SSL_MAX_SID_CTX_LENGTH) {
+			BIO_printf(bio_err, "Context too long\n");
+			goto end;
+		}
+		SSL_SESSION_set1_id_context(x,
+		    (unsigned char *)sess_id_config.context, ctx_len);
+	}
+
+	if (!sess_id_config.noout || sess_id_config.text) {
+		out = BIO_new(BIO_s_file());
+		if (out == NULL) {
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+		if (sess_id_config.outfile == NULL) {
+			BIO_set_fp(out, stdout, BIO_NOCLOSE);
+		} else {
+			if (BIO_write_filename(out, sess_id_config.outfile)
+			    <= 0) {
+				perror(sess_id_config.outfile);
+				goto end;
+			}
+		}
+	}
+	if (sess_id_config.text) {
+		SSL_SESSION_print(out, x);
+
+		if (sess_id_config.cert) {
+			if (peer == NULL)
+				BIO_puts(out, "No certificate present\n");
+			else
+				X509_print(out, peer);
+		}
+	}
+	if (!sess_id_config.noout && !sess_id_config.cert) {
+		if (sess_id_config.outformat == FORMAT_ASN1)
+			i = i2d_SSL_SESSION_bio(out, x);
+		else if (sess_id_config.outformat == FORMAT_PEM)
+			i = PEM_write_bio_SSL_SESSION(out, x);
+		else {
+			BIO_printf(bio_err,
+			    "bad output format specified for outfile\n");
+			goto end;
+		}
+		if (!i) {
+			BIO_printf(bio_err, "unable to write SSL_SESSION\n");
+			goto end;
+		}
+	} else if (!sess_id_config.noout && (peer != NULL)) {
+		/* just print the certificate */
+		if (sess_id_config.outformat == FORMAT_ASN1)
+			i = (int) i2d_X509_bio(out, peer);
+		else if (sess_id_config.outformat == FORMAT_PEM)
+			i = PEM_write_bio_X509(out, peer);
+		else {
+			BIO_printf(bio_err,
+			    "bad output format specified for outfile\n");
+			goto end;
+		}
+		if (!i) {
+			BIO_printf(bio_err, "unable to write X509\n");
+			goto end;
+		}
+	}
+	ret = 0;
+
+end:
+	BIO_free_all(out);
+	SSL_SESSION_free(x);
+
+	return (ret);
+}
+
+static SSL_SESSION *
+load_sess_id(char *infile, int format)
+{
+	SSL_SESSION *x = NULL;
+	BIO *in = NULL;
+
+	in = BIO_new(BIO_s_file());
+	if (in == NULL) {
+		ERR_print_errors(bio_err);
+		goto end;
+	}
+	if (infile == NULL)
+		BIO_set_fp(in, stdin, BIO_NOCLOSE);
+	else {
+		if (BIO_read_filename(in, infile) <= 0) {
+			perror(infile);
+			goto end;
+		}
+	}
+	if (format == FORMAT_ASN1)
+		x = d2i_SSL_SESSION_bio(in, NULL);
+	else if (format == FORMAT_PEM)
+		x = PEM_read_bio_SSL_SESSION(in, NULL, NULL, NULL);
+	else {
+		BIO_printf(bio_err,
+		    "bad input format specified for input crl\n");
+		goto end;
+	}
+	if (x == NULL) {
+		BIO_printf(bio_err, "unable to load SSL_SESSION\n");
+		ERR_print_errors(bio_err);
+		goto end;
+	}
+end:
+	BIO_free(in);
+	return (x);
+}
diff --git a/bin/openssl/smime.c b/bin/openssl/smime.c
new file mode 100644
index 0000000000..847ee133b6
--- /dev/null
+++ b/bin/openssl/smime.c
@@ -0,0 +1,682 @@
+/* $OpenBSD: smime.c,v 1.8 2017/01/20 08:57:12 deraadt Exp $ */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2004 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+/* S/MIME utility function */
+
+#include 
+#include 
+
+#include "apps.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+static int save_certs(char *signerfile, STACK_OF(X509) * signers);
+static int smime_cb(int ok, X509_STORE_CTX * ctx);
+
+#define SMIME_OP	0x10
+#define SMIME_IP	0x20
+#define SMIME_SIGNERS	0x40
+#define SMIME_ENCRYPT	(1 | SMIME_OP)
+#define SMIME_DECRYPT	(2 | SMIME_IP)
+#define SMIME_SIGN	(3 | SMIME_OP | SMIME_SIGNERS)
+#define SMIME_VERIFY	(4 | SMIME_IP)
+#define SMIME_PK7OUT	(5 | SMIME_IP | SMIME_OP)
+#define SMIME_RESIGN	(6 | SMIME_IP | SMIME_OP | SMIME_SIGNERS)
+
+int
+smime_main(int argc, char **argv)
+{
+	int operation = 0;
+	int ret = 0;
+	char **args;
+	const char *inmode = "r", *outmode = "w";
+	char *infile = NULL, *outfile = NULL;
+	char *signerfile = NULL, *recipfile = NULL;
+	STACK_OF(OPENSSL_STRING) * sksigners = NULL, *skkeys = NULL;
+	char *certfile = NULL, *keyfile = NULL, *contfile = NULL;
+	const EVP_CIPHER *cipher = NULL;
+	PKCS7 *p7 = NULL;
+	X509_STORE *store = NULL;
+	X509 *cert = NULL, *recip = NULL, *signer = NULL;
+	EVP_PKEY *key = NULL;
+	STACK_OF(X509) * encerts = NULL, *other = NULL;
+	BIO *in = NULL, *out = NULL, *indata = NULL;
+	int badarg = 0;
+	int flags = PKCS7_DETACHED;
+	char *to = NULL, *from = NULL, *subject = NULL;
+	char *CAfile = NULL, *CApath = NULL;
+	char *passargin = NULL, *passin = NULL;
+	int indef = 0;
+	const EVP_MD *sign_md = NULL;
+	int informat = FORMAT_SMIME, outformat = FORMAT_SMIME;
+	int keyform = FORMAT_PEM;
+
+	X509_VERIFY_PARAM *vpm = NULL;
+
+	if (single_execution) {
+		if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
+			perror("pledge");
+			exit(1);
+		}
+	}
+
+	args = argv + 1;
+	ret = 1;
+
+	while (!badarg && *args && *args[0] == '-') {
+		if (!strcmp(*args, "-encrypt"))
+			operation = SMIME_ENCRYPT;
+		else if (!strcmp(*args, "-decrypt"))
+			operation = SMIME_DECRYPT;
+		else if (!strcmp(*args, "-sign"))
+			operation = SMIME_SIGN;
+		else if (!strcmp(*args, "-resign"))
+			operation = SMIME_RESIGN;
+		else if (!strcmp(*args, "-verify"))
+			operation = SMIME_VERIFY;
+		else if (!strcmp(*args, "-pk7out"))
+			operation = SMIME_PK7OUT;
+#ifndef OPENSSL_NO_DES
+		else if (!strcmp(*args, "-des3"))
+			cipher = EVP_des_ede3_cbc();
+		else if (!strcmp(*args, "-des"))
+			cipher = EVP_des_cbc();
+#endif
+#ifndef OPENSSL_NO_RC2
+		else if (!strcmp(*args, "-rc2-40"))
+			cipher = EVP_rc2_40_cbc();
+		else if (!strcmp(*args, "-rc2-128"))
+			cipher = EVP_rc2_cbc();
+		else if (!strcmp(*args, "-rc2-64"))
+			cipher = EVP_rc2_64_cbc();
+#endif
+#ifndef OPENSSL_NO_AES
+		else if (!strcmp(*args, "-aes128"))
+			cipher = EVP_aes_128_cbc();
+		else if (!strcmp(*args, "-aes192"))
+			cipher = EVP_aes_192_cbc();
+		else if (!strcmp(*args, "-aes256"))
+			cipher = EVP_aes_256_cbc();
+#endif
+#ifndef OPENSSL_NO_CAMELLIA
+		else if (!strcmp(*args, "-camellia128"))
+			cipher = EVP_camellia_128_cbc();
+		else if (!strcmp(*args, "-camellia192"))
+			cipher = EVP_camellia_192_cbc();
+		else if (!strcmp(*args, "-camellia256"))
+			cipher = EVP_camellia_256_cbc();
+#endif
+		else if (!strcmp(*args, "-text"))
+			flags |= PKCS7_TEXT;
+		else if (!strcmp(*args, "-nointern"))
+			flags |= PKCS7_NOINTERN;
+		else if (!strcmp(*args, "-noverify"))
+			flags |= PKCS7_NOVERIFY;
+		else if (!strcmp(*args, "-nochain"))
+			flags |= PKCS7_NOCHAIN;
+		else if (!strcmp(*args, "-nocerts"))
+			flags |= PKCS7_NOCERTS;
+		else if (!strcmp(*args, "-noattr"))
+			flags |= PKCS7_NOATTR;
+		else if (!strcmp(*args, "-nodetach"))
+			flags &= ~PKCS7_DETACHED;
+		else if (!strcmp(*args, "-nosmimecap"))
+			flags |= PKCS7_NOSMIMECAP;
+		else if (!strcmp(*args, "-binary"))
+			flags |= PKCS7_BINARY;
+		else if (!strcmp(*args, "-nosigs"))
+			flags |= PKCS7_NOSIGS;
+		else if (!strcmp(*args, "-stream"))
+			indef = 1;
+		else if (!strcmp(*args, "-indef"))
+			indef = 1;
+		else if (!strcmp(*args, "-noindef"))
+			indef = 0;
+		else if (!strcmp(*args, "-nooldmime"))
+			flags |= PKCS7_NOOLDMIMETYPE;
+		else if (!strcmp(*args, "-crlfeol"))
+			flags |= PKCS7_CRLFEOL;
+		else if (!strcmp(*args, "-passin")) {
+			if (!args[1])
+				goto argerr;
+			passargin = *++args;
+		} else if (!strcmp(*args, "-to")) {
+			if (!args[1])
+				goto argerr;
+			to = *++args;
+		} else if (!strcmp(*args, "-from")) {
+			if (!args[1])
+				goto argerr;
+			from = *++args;
+		} else if (!strcmp(*args, "-subject")) {
+			if (!args[1])
+				goto argerr;
+			subject = *++args;
+		} else if (!strcmp(*args, "-signer")) {
+			if (!args[1])
+				goto argerr;
+			/* If previous -signer argument add signer to list */
+
+			if (signerfile) {
+				if (!sksigners)
+					sksigners = sk_OPENSSL_STRING_new_null();
+				sk_OPENSSL_STRING_push(sksigners, signerfile);
+				if (!keyfile)
+					keyfile = signerfile;
+				if (!skkeys)
+					skkeys = sk_OPENSSL_STRING_new_null();
+				sk_OPENSSL_STRING_push(skkeys, keyfile);
+				keyfile = NULL;
+			}
+			signerfile = *++args;
+		} else if (!strcmp(*args, "-recip")) {
+			if (!args[1])
+				goto argerr;
+			recipfile = *++args;
+		} else if (!strcmp(*args, "-md")) {
+			if (!args[1])
+				goto argerr;
+			sign_md = EVP_get_digestbyname(*++args);
+			if (sign_md == NULL) {
+				BIO_printf(bio_err, "Unknown digest %s\n",
+				    *args);
+				goto argerr;
+			}
+		} else if (!strcmp(*args, "-inkey")) {
+			if (!args[1])
+				goto argerr;
+			/* If previous -inkey arument add signer to list */
+			if (keyfile) {
+				if (!signerfile) {
+					BIO_puts(bio_err, "Illegal -inkey without -signer\n");
+					goto argerr;
+				}
+				if (!sksigners)
+					sksigners = sk_OPENSSL_STRING_new_null();
+				sk_OPENSSL_STRING_push(sksigners, signerfile);
+				signerfile = NULL;
+				if (!skkeys)
+					skkeys = sk_OPENSSL_STRING_new_null();
+				sk_OPENSSL_STRING_push(skkeys, keyfile);
+			}
+			keyfile = *++args;
+		} else if (!strcmp(*args, "-keyform")) {
+			if (!args[1])
+				goto argerr;
+			keyform = str2fmt(*++args);
+		} else if (!strcmp(*args, "-certfile")) {
+			if (!args[1])
+				goto argerr;
+			certfile = *++args;
+		} else if (!strcmp(*args, "-CAfile")) {
+			if (!args[1])
+				goto argerr;
+			CAfile = *++args;
+		} else if (!strcmp(*args, "-CApath")) {
+			if (!args[1])
+				goto argerr;
+			CApath = *++args;
+		} else if (!strcmp(*args, "-in")) {
+			if (!args[1])
+				goto argerr;
+			infile = *++args;
+		} else if (!strcmp(*args, "-inform")) {
+			if (!args[1])
+				goto argerr;
+			informat = str2fmt(*++args);
+		} else if (!strcmp(*args, "-outform")) {
+			if (!args[1])
+				goto argerr;
+			outformat = str2fmt(*++args);
+		} else if (!strcmp(*args, "-out")) {
+			if (!args[1])
+				goto argerr;
+			outfile = *++args;
+		} else if (!strcmp(*args, "-content")) {
+			if (!args[1])
+				goto argerr;
+			contfile = *++args;
+		} else if (args_verify(&args, NULL, &badarg, bio_err, &vpm))
+			continue;
+		else if ((cipher = EVP_get_cipherbyname(*args + 1)) == NULL)
+			badarg = 1;
+		args++;
+	}
+
+	if (!(operation & SMIME_SIGNERS) && (skkeys || sksigners)) {
+		BIO_puts(bio_err, "Multiple signers or keys not allowed\n");
+		goto argerr;
+	}
+	if (operation & SMIME_SIGNERS) {
+		/* Check to see if any final signer needs to be appended */
+		if (keyfile && !signerfile) {
+			BIO_puts(bio_err, "Illegal -inkey without -signer\n");
+			goto argerr;
+		}
+		if (signerfile) {
+			if (!sksigners)
+				sksigners = sk_OPENSSL_STRING_new_null();
+			sk_OPENSSL_STRING_push(sksigners, signerfile);
+			if (!skkeys)
+				skkeys = sk_OPENSSL_STRING_new_null();
+			if (!keyfile)
+				keyfile = signerfile;
+			sk_OPENSSL_STRING_push(skkeys, keyfile);
+		}
+		if (!sksigners) {
+			BIO_printf(bio_err, "No signer certificate specified\n");
+			badarg = 1;
+		}
+		signerfile = NULL;
+		keyfile = NULL;
+	} else if (operation == SMIME_DECRYPT) {
+		if (!recipfile && !keyfile) {
+			BIO_printf(bio_err, "No recipient certificate or key specified\n");
+			badarg = 1;
+		}
+	} else if (operation == SMIME_ENCRYPT) {
+		if (!*args) {
+			BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n");
+			badarg = 1;
+		}
+	} else if (!operation)
+		badarg = 1;
+
+	if (badarg) {
+argerr:
+		BIO_printf(bio_err, "Usage smime [options] cert.pem ...\n");
+		BIO_printf(bio_err, "where options are\n");
+		BIO_printf(bio_err, "-encrypt       encrypt message\n");
+		BIO_printf(bio_err, "-decrypt       decrypt encrypted message\n");
+		BIO_printf(bio_err, "-sign          sign message\n");
+		BIO_printf(bio_err, "-verify        verify signed message\n");
+		BIO_printf(bio_err, "-pk7out        output PKCS#7 structure\n");
+#ifndef OPENSSL_NO_DES
+		BIO_printf(bio_err, "-des3          encrypt with triple DES\n");
+		BIO_printf(bio_err, "-des           encrypt with DES\n");
+#endif
+#ifndef OPENSSL_NO_RC2
+		BIO_printf(bio_err, "-rc2-40        encrypt with RC2-40 (default)\n");
+		BIO_printf(bio_err, "-rc2-64        encrypt with RC2-64\n");
+		BIO_printf(bio_err, "-rc2-128       encrypt with RC2-128\n");
+#endif
+#ifndef OPENSSL_NO_AES
+		BIO_printf(bio_err, "-aes128, -aes192, -aes256\n");
+		BIO_printf(bio_err, "               encrypt PEM output with cbc aes\n");
+#endif
+#ifndef OPENSSL_NO_CAMELLIA
+		BIO_printf(bio_err, "-camellia128, -camellia192, -camellia256\n");
+		BIO_printf(bio_err, "               encrypt PEM output with cbc camellia\n");
+#endif
+		BIO_printf(bio_err, "-nointern      don't search certificates in message for signer\n");
+		BIO_printf(bio_err, "-nosigs        don't verify message signature\n");
+		BIO_printf(bio_err, "-noverify      don't verify signers certificate\n");
+		BIO_printf(bio_err, "-nocerts       don't include signers certificate when signing\n");
+		BIO_printf(bio_err, "-nodetach      use opaque signing\n");
+		BIO_printf(bio_err, "-noattr        don't include any signed attributes\n");
+		BIO_printf(bio_err, "-binary        don't translate message to text\n");
+		BIO_printf(bio_err, "-certfile file other certificates file\n");
+		BIO_printf(bio_err, "-signer file   signer certificate file\n");
+		BIO_printf(bio_err, "-recip  file   recipient certificate file for decryption\n");
+		BIO_printf(bio_err, "-in file       input file\n");
+		BIO_printf(bio_err, "-inform arg    input format SMIME (default), PEM or DER\n");
+		BIO_printf(bio_err, "-inkey file    input private key (if not signer or recipient)\n");
+		BIO_printf(bio_err, "-keyform arg   input private key format (PEM)\n");
+		BIO_printf(bio_err, "-out file      output file\n");
+		BIO_printf(bio_err, "-outform arg   output format SMIME (default), PEM or DER\n");
+		BIO_printf(bio_err, "-content file  supply or override content for detached signature\n");
+		BIO_printf(bio_err, "-to addr       to address\n");
+		BIO_printf(bio_err, "-from ad       from address\n");
+		BIO_printf(bio_err, "-subject s     subject\n");
+		BIO_printf(bio_err, "-text          include or delete text MIME headers\n");
+		BIO_printf(bio_err, "-CApath dir    trusted certificates directory\n");
+		BIO_printf(bio_err, "-CAfile file   trusted certificates file\n");
+		BIO_printf(bio_err, "-crl_check     check revocation status of signer's certificate using CRLs\n");
+		BIO_printf(bio_err, "-crl_check_all check revocation status of signer's certificate chain using CRLs\n");
+		BIO_printf(bio_err, "-passin arg    input file pass phrase source\n");
+		BIO_printf(bio_err, "cert.pem       recipient certificate(s) for encryption\n");
+		goto end;
+	}
+
+	if (!app_passwd(bio_err, passargin, NULL, &passin, NULL)) {
+		BIO_printf(bio_err, "Error getting password\n");
+		goto end;
+	}
+	ret = 2;
+
+	if (!(operation & SMIME_SIGNERS))
+		flags &= ~PKCS7_DETACHED;
+
+	if (operation & SMIME_OP) {
+		if (outformat == FORMAT_ASN1)
+			outmode = "wb";
+	} else {
+		if (flags & PKCS7_BINARY)
+			outmode = "wb";
+	}
+
+	if (operation & SMIME_IP) {
+		if (informat == FORMAT_ASN1)
+			inmode = "rb";
+	} else {
+		if (flags & PKCS7_BINARY)
+			inmode = "rb";
+	}
+
+	if (operation == SMIME_ENCRYPT) {
+		if (!cipher) {
+#ifndef OPENSSL_NO_RC2
+			cipher = EVP_rc2_40_cbc();
+#else
+			BIO_printf(bio_err, "No cipher selected\n");
+			goto end;
+#endif
+		}
+		encerts = sk_X509_new_null();
+		while (*args) {
+			if (!(cert = load_cert(bio_err, *args, FORMAT_PEM,
+			    NULL, "recipient certificate file"))) {
+				goto end;
+			}
+			sk_X509_push(encerts, cert);
+			cert = NULL;
+			args++;
+		}
+	}
+	if (certfile) {
+		if (!(other = load_certs(bio_err, certfile, FORMAT_PEM, NULL,
+		    "certificate file"))) {
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+	}
+	if (recipfile && (operation == SMIME_DECRYPT)) {
+		if (!(recip = load_cert(bio_err, recipfile, FORMAT_PEM, NULL,
+		    "recipient certificate file"))) {
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+	}
+	if (operation == SMIME_DECRYPT) {
+		if (!keyfile)
+			keyfile = recipfile;
+	} else if (operation == SMIME_SIGN) {
+		if (!keyfile)
+			keyfile = signerfile;
+	} else
+		keyfile = NULL;
+
+	if (keyfile) {
+		key = load_key(bio_err, keyfile, keyform, 0, passin,
+		    "signing key file");
+		if (!key)
+			goto end;
+	}
+	if (infile) {
+		if (!(in = BIO_new_file(infile, inmode))) {
+			BIO_printf(bio_err,
+			    "Can't open input file %s\n", infile);
+			goto end;
+		}
+	} else
+		in = BIO_new_fp(stdin, BIO_NOCLOSE);
+
+	if (operation & SMIME_IP) {
+		if (informat == FORMAT_SMIME)
+			p7 = SMIME_read_PKCS7(in, &indata);
+		else if (informat == FORMAT_PEM)
+			p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL);
+		else if (informat == FORMAT_ASN1)
+			p7 = d2i_PKCS7_bio(in, NULL);
+		else {
+			BIO_printf(bio_err, "Bad input format for PKCS#7 file\n");
+			goto end;
+		}
+
+		if (!p7) {
+			BIO_printf(bio_err, "Error reading S/MIME message\n");
+			goto end;
+		}
+		if (contfile) {
+			BIO_free(indata);
+			if (!(indata = BIO_new_file(contfile, "rb"))) {
+				BIO_printf(bio_err, "Can't read content file %s\n", contfile);
+				goto end;
+			}
+		}
+	}
+	if (outfile) {
+		if (!(out = BIO_new_file(outfile, outmode))) {
+			BIO_printf(bio_err,
+			    "Can't open output file %s\n", outfile);
+			goto end;
+		}
+	} else {
+		out = BIO_new_fp(stdout, BIO_NOCLOSE);
+	}
+
+	if (operation == SMIME_VERIFY) {
+		if (!(store = setup_verify(bio_err, CAfile, CApath)))
+			goto end;
+		X509_STORE_set_verify_cb(store, smime_cb);
+		if (vpm)
+			X509_STORE_set1_param(store, vpm);
+	}
+	ret = 3;
+
+	if (operation == SMIME_ENCRYPT) {
+		if (indef)
+			flags |= PKCS7_STREAM;
+		p7 = PKCS7_encrypt(encerts, in, cipher, flags);
+	} else if (operation & SMIME_SIGNERS) {
+		int i;
+		/*
+		 * If detached data content we only enable streaming if
+		 * S/MIME output format.
+		 */
+		if (operation == SMIME_SIGN) {
+			if (flags & PKCS7_DETACHED) {
+				if (outformat == FORMAT_SMIME)
+					flags |= PKCS7_STREAM;
+			} else if (indef)
+				flags |= PKCS7_STREAM;
+			flags |= PKCS7_PARTIAL;
+			p7 = PKCS7_sign(NULL, NULL, other, in, flags);
+			if (!p7)
+				goto end;
+		} else
+			flags |= PKCS7_REUSE_DIGEST;
+		for (i = 0; i < sk_OPENSSL_STRING_num(sksigners); i++) {
+			signerfile = sk_OPENSSL_STRING_value(sksigners, i);
+			keyfile = sk_OPENSSL_STRING_value(skkeys, i);
+			signer = load_cert(bio_err, signerfile, FORMAT_PEM, NULL,
+			    "signer certificate");
+			if (!signer)
+				goto end;
+			key = load_key(bio_err, keyfile, keyform, 0, passin,
+			    "signing key file");
+			if (!key)
+				goto end;
+			if (!PKCS7_sign_add_signer(p7, signer, key,
+				sign_md, flags))
+				goto end;
+			X509_free(signer);
+			signer = NULL;
+			EVP_PKEY_free(key);
+			key = NULL;
+		}
+		/* If not streaming or resigning finalize structure */
+		if ((operation == SMIME_SIGN) && !(flags & PKCS7_STREAM)) {
+			if (!PKCS7_final(p7, in, flags))
+				goto end;
+		}
+	}
+	if (!p7) {
+		BIO_printf(bio_err, "Error creating PKCS#7 structure\n");
+		goto end;
+	}
+	ret = 4;
+	if (operation == SMIME_DECRYPT) {
+		if (!PKCS7_decrypt(p7, key, recip, out, flags)) {
+			BIO_printf(bio_err, "Error decrypting PKCS#7 structure\n");
+			goto end;
+		}
+	} else if (operation == SMIME_VERIFY) {
+		STACK_OF(X509) * signers;
+		if (PKCS7_verify(p7, other, store, indata, out, flags))
+			BIO_printf(bio_err, "Verification successful\n");
+		else {
+			BIO_printf(bio_err, "Verification failure\n");
+			goto end;
+		}
+		signers = PKCS7_get0_signers(p7, other, flags);
+		if (!save_certs(signerfile, signers)) {
+			BIO_printf(bio_err, "Error writing signers to %s\n",
+			    signerfile);
+			ret = 5;
+			goto end;
+		}
+		sk_X509_free(signers);
+	} else if (operation == SMIME_PK7OUT)
+		PEM_write_bio_PKCS7(out, p7);
+	else {
+		if (to)
+			BIO_printf(out, "To: %s\n", to);
+		if (from)
+			BIO_printf(out, "From: %s\n", from);
+		if (subject)
+			BIO_printf(out, "Subject: %s\n", subject);
+		if (outformat == FORMAT_SMIME) {
+			if (operation == SMIME_RESIGN)
+				SMIME_write_PKCS7(out, p7, indata, flags);
+			else
+				SMIME_write_PKCS7(out, p7, in, flags);
+		} else if (outformat == FORMAT_PEM)
+			PEM_write_bio_PKCS7_stream(out, p7, in, flags);
+		else if (outformat == FORMAT_ASN1)
+			i2d_PKCS7_bio_stream(out, p7, in, flags);
+		else {
+			BIO_printf(bio_err, "Bad output format for PKCS#7 file\n");
+			goto end;
+		}
+	}
+	ret = 0;
+end:
+	if (ret)
+		ERR_print_errors(bio_err);
+	sk_X509_pop_free(encerts, X509_free);
+	sk_X509_pop_free(other, X509_free);
+	if (vpm)
+		X509_VERIFY_PARAM_free(vpm);
+	if (sksigners)
+		sk_OPENSSL_STRING_free(sksigners);
+	if (skkeys)
+		sk_OPENSSL_STRING_free(skkeys);
+	X509_STORE_free(store);
+	X509_free(cert);
+	X509_free(recip);
+	X509_free(signer);
+	EVP_PKEY_free(key);
+	PKCS7_free(p7);
+	BIO_free(in);
+	BIO_free(indata);
+	BIO_free_all(out);
+	free(passin);
+
+	return (ret);
+}
+
+static int
+save_certs(char *signerfile, STACK_OF(X509) * signers)
+{
+	int i;
+	BIO *tmp;
+	if (!signerfile)
+		return 1;
+	tmp = BIO_new_file(signerfile, "w");
+	if (!tmp)
+		return 0;
+	for (i = 0; i < sk_X509_num(signers); i++)
+		PEM_write_bio_X509(tmp, sk_X509_value(signers, i));
+	BIO_free(tmp);
+	return 1;
+}
+
+
+/* Minimal callback just to output policy info (if any) */
+
+static int
+smime_cb(int ok, X509_STORE_CTX * ctx)
+{
+	int error;
+
+	error = X509_STORE_CTX_get_error(ctx);
+
+	if ((error != X509_V_ERR_NO_EXPLICIT_POLICY)
+	    && ((error != X509_V_OK) || (ok != 2)))
+		return ok;
+
+	policies_print(NULL, ctx);
+
+	return ok;
+
+}
diff --git a/bin/openssl/speed.c b/bin/openssl/speed.c
new file mode 100644
index 0000000000..0ca87687bd
--- /dev/null
+++ b/bin/openssl/speed.c
@@ -0,0 +1,2155 @@
+/* $OpenBSD: speed.c,v 1.19 2016/08/22 04:33:07 deraadt Exp $ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * The ECDH and ECDSA speed test software is originally written by
+ * Sumit Gupta of Sun Microsystems Laboratories.
+ *
+ */
+
+/* most of this code has been pilfered from my libdes speed.c program */
+
+#ifndef OPENSSL_NO_SPEED
+
+#define SECONDS		3
+#define RSA_SECONDS	10
+#define DSA_SECONDS	10
+#define ECDSA_SECONDS   10
+#define ECDH_SECONDS    10
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "apps.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#ifndef OPENSSL_NO_AES
+#include 
+#endif
+#ifndef OPENSSL_NO_BF
+#include 
+#endif
+#ifndef OPENSSL_NO_CAST
+#include 
+#endif
+#ifndef OPENSSL_NO_CAMELLIA
+#include 
+#endif
+#ifndef OPENSSL_NO_DES
+#include 
+#endif
+#include 
+#include 
+#include 
+#ifndef OPENSSL_NO_HMAC
+#include 
+#endif
+#ifndef OPENSSL_NO_IDEA
+#include 
+#endif
+#ifndef OPENSSL_NO_MD4
+#include 
+#endif
+#ifndef OPENSSL_NO_MD5
+#include 
+#endif
+#ifndef OPENSSL_NO_RC2
+#include 
+#endif
+#ifndef OPENSSL_NO_RC4
+#include 
+#endif
+#include 
+#ifndef OPENSSL_NO_RIPEMD
+#include 
+#endif
+#ifndef OPENSSL_NO_SHA
+#include 
+#endif
+#ifndef OPENSSL_NO_WHIRLPOOL
+#include 
+#endif
+
+#include "./testdsa.h"
+#include "./testrsa.h"
+
+#define BUFSIZE	(1024*8+64)
+int run = 0;
+
+static int mr = 0;
+static int usertime = 1;
+
+static double Time_F(int s);
+static void print_message(const char *s, long num, int length);
+static void
+pkey_print_message(const char *str, const char *str2,
+    long num, int bits, int sec);
+static void print_result(int alg, int run_no, int count, double time_used);
+static int do_multi(int multi);
+
+#define ALGOR_NUM	32
+#define SIZE_NUM	5
+#define RSA_NUM		4
+#define DSA_NUM		3
+
+#define EC_NUM       16
+#define MAX_ECDH_SIZE 256
+
+static const char *names[ALGOR_NUM] = {
+	"md2", "md4", "md5", "hmac(md5)", "sha1", "rmd160",
+	"rc4", "des cbc", "des ede3", "idea cbc", "seed cbc",
+	"rc2 cbc", "rc5-32/12 cbc", "blowfish cbc", "cast cbc",
+	"aes-128 cbc", "aes-192 cbc", "aes-256 cbc",
+	"camellia-128 cbc", "camellia-192 cbc", "camellia-256 cbc",
+	"evp", "sha256", "sha512", "whirlpool",
+	"aes-128 ige", "aes-192 ige", "aes-256 ige", "ghash",
+	"aes-128 gcm", "aes-256 gcm", "chacha20 poly1305",
+};
+static double results[ALGOR_NUM][SIZE_NUM];
+static int lengths[SIZE_NUM] = {16, 64, 256, 1024, 8 * 1024};
+static double rsa_results[RSA_NUM][2];
+static double dsa_results[DSA_NUM][2];
+static double ecdsa_results[EC_NUM][2];
+static double ecdh_results[EC_NUM][1];
+
+static void sig_done(int sig);
+
+static void
+sig_done(int sig)
+{
+	signal(SIGALRM, sig_done);
+	run = 0;
+}
+
+#define START	0
+#define STOP	1
+
+
+static double
+Time_F(int s)
+{
+	return app_tminterval(s, usertime);
+}
+
+
+static const int KDF1_SHA1_len = 20;
+static void *
+KDF1_SHA1(const void *in, size_t inlen, void *out, size_t * outlen)
+{
+#ifndef OPENSSL_NO_SHA
+	if (*outlen < SHA_DIGEST_LENGTH)
+		return NULL;
+	else
+		*outlen = SHA_DIGEST_LENGTH;
+	return SHA1(in, inlen, out);
+#else
+	return NULL;
+#endif				/* OPENSSL_NO_SHA */
+}
+
+int
+speed_main(int argc, char **argv)
+{
+	unsigned char *buf = NULL, *buf2 = NULL;
+	int mret = 1;
+	long count = 0, save_count = 0;
+	int i, j, k;
+	long rsa_count;
+	unsigned rsa_num;
+	unsigned char md[EVP_MAX_MD_SIZE];
+#ifndef OPENSSL_NO_MD4
+	unsigned char md4[MD4_DIGEST_LENGTH];
+#endif
+#ifndef OPENSSL_NO_MD5
+	unsigned char md5[MD5_DIGEST_LENGTH];
+	unsigned char hmac[MD5_DIGEST_LENGTH];
+#endif
+#ifndef OPENSSL_NO_SHA
+	unsigned char sha[SHA_DIGEST_LENGTH];
+#ifndef OPENSSL_NO_SHA256
+	unsigned char sha256[SHA256_DIGEST_LENGTH];
+#endif
+#ifndef OPENSSL_NO_SHA512
+	unsigned char sha512[SHA512_DIGEST_LENGTH];
+#endif
+#endif
+#ifndef OPENSSL_NO_WHIRLPOOL
+	unsigned char whirlpool[WHIRLPOOL_DIGEST_LENGTH];
+#endif
+#ifndef OPENSSL_NO_RIPEMD
+	unsigned char rmd160[RIPEMD160_DIGEST_LENGTH];
+#endif
+#ifndef OPENSSL_NO_RC4
+	RC4_KEY rc4_ks;
+#endif
+#ifndef OPENSSL_NO_RC2
+	RC2_KEY rc2_ks;
+#endif
+#ifndef OPENSSL_NO_IDEA
+	IDEA_KEY_SCHEDULE idea_ks;
+#endif
+#ifndef OPENSSL_NO_BF
+	BF_KEY bf_ks;
+#endif
+#ifndef OPENSSL_NO_CAST
+	CAST_KEY cast_ks;
+#endif
+	static const unsigned char key16[16] =
+	{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
+	0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12};
+#ifndef OPENSSL_NO_AES
+	static const unsigned char key24[24] =
+	{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
+		0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12,
+	0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34};
+	static const unsigned char key32[32] =
+	{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
+		0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12,
+		0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34,
+	0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56};
+#endif
+#ifndef OPENSSL_NO_CAMELLIA
+	static const unsigned char ckey24[24] =
+	{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
+		0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12,
+	0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34};
+	static const unsigned char ckey32[32] =
+	{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
+		0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12,
+		0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34,
+	0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56};
+#endif
+#ifndef OPENSSL_NO_AES
+#define MAX_BLOCK_SIZE 128
+#else
+#define MAX_BLOCK_SIZE 64
+#endif
+	unsigned char DES_iv[8];
+	unsigned char iv[2 * MAX_BLOCK_SIZE / 8];
+#ifndef OPENSSL_NO_DES
+	static DES_cblock key = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0};
+	static DES_cblock key2 = {0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12};
+	static DES_cblock key3 = {0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34};
+	DES_key_schedule sch;
+	DES_key_schedule sch2;
+	DES_key_schedule sch3;
+#endif
+#ifndef OPENSSL_NO_AES
+	AES_KEY aes_ks1, aes_ks2, aes_ks3;
+#endif
+#ifndef OPENSSL_NO_CAMELLIA
+	CAMELLIA_KEY camellia_ks1, camellia_ks2, camellia_ks3;
+#endif
+#define	D_MD2		0
+#define	D_MD4		1
+#define	D_MD5		2
+#define	D_HMAC		3
+#define	D_SHA1		4
+#define D_RMD160	5
+#define	D_RC4		6
+#define	D_CBC_DES	7
+#define	D_EDE3_DES	8
+#define	D_CBC_IDEA	9
+#define	D_CBC_SEED	10
+#define	D_CBC_RC2	11
+#define	D_CBC_RC5	12
+#define	D_CBC_BF	13
+#define	D_CBC_CAST	14
+#define D_CBC_128_AES	15
+#define D_CBC_192_AES	16
+#define D_CBC_256_AES	17
+#define D_CBC_128_CML   18
+#define D_CBC_192_CML   19
+#define D_CBC_256_CML   20
+#define D_EVP		21
+#define D_SHA256	22
+#define D_SHA512	23
+#define D_WHIRLPOOL	24
+#define D_IGE_128_AES   25
+#define D_IGE_192_AES   26
+#define D_IGE_256_AES   27
+#define D_GHASH		28
+#define D_AES_128_GCM	29
+#define D_AES_256_GCM	30
+#define D_CHACHA20_POLY1305	31
+	double d = 0.0;
+	long c[ALGOR_NUM][SIZE_NUM];
+#define	R_DSA_512	0
+#define	R_DSA_1024	1
+#define	R_DSA_2048	2
+#define	R_RSA_512	0
+#define	R_RSA_1024	1
+#define	R_RSA_2048	2
+#define	R_RSA_4096	3
+
+#define R_EC_P160    0
+#define R_EC_P192    1
+#define R_EC_P224    2
+#define R_EC_P256    3
+#define R_EC_P384    4
+#define R_EC_P521    5
+#define R_EC_K163    6
+#define R_EC_K233    7
+#define R_EC_K283    8
+#define R_EC_K409    9
+#define R_EC_K571    10
+#define R_EC_B163    11
+#define R_EC_B233    12
+#define R_EC_B283    13
+#define R_EC_B409    14
+#define R_EC_B571    15
+
+	RSA *rsa_key[RSA_NUM];
+	long rsa_c[RSA_NUM][2];
+	static unsigned int rsa_bits[RSA_NUM] = {512, 1024, 2048, 4096};
+	static unsigned char *rsa_data[RSA_NUM] =
+	{test512, test1024, test2048, test4096};
+	static int rsa_data_length[RSA_NUM] = {
+		sizeof(test512), sizeof(test1024),
+	sizeof(test2048), sizeof(test4096)};
+	DSA *dsa_key[DSA_NUM];
+	long dsa_c[DSA_NUM][2];
+	static unsigned int dsa_bits[DSA_NUM] = {512, 1024, 2048};
+#ifndef OPENSSL_NO_EC
+	/*
+	 * We only test over the following curves as they are representative,
+	 * To add tests over more curves, simply add the curve NID and curve
+	 * name to the following arrays and increase the EC_NUM value
+	 * accordingly.
+	 */
+	static unsigned int test_curves[EC_NUM] =
+	{
+		/* Prime Curves */
+		NID_secp160r1,
+		NID_X9_62_prime192v1,
+		NID_secp224r1,
+		NID_X9_62_prime256v1,
+		NID_secp384r1,
+		NID_secp521r1,
+		/* Binary Curves */
+		NID_sect163k1,
+		NID_sect233k1,
+		NID_sect283k1,
+		NID_sect409k1,
+		NID_sect571k1,
+		NID_sect163r2,
+		NID_sect233r1,
+		NID_sect283r1,
+		NID_sect409r1,
+		NID_sect571r1
+	};
+	static const char *test_curves_names[EC_NUM] =
+	{
+		/* Prime Curves */
+		"secp160r1",
+		"nistp192",
+		"nistp224",
+		"nistp256",
+		"nistp384",
+		"nistp521",
+		/* Binary Curves */
+		"nistk163",
+		"nistk233",
+		"nistk283",
+		"nistk409",
+		"nistk571",
+		"nistb163",
+		"nistb233",
+		"nistb283",
+		"nistb409",
+		"nistb571"
+	};
+	static int test_curves_bits[EC_NUM] =
+	{
+		160, 192, 224, 256, 384, 521,
+		163, 233, 283, 409, 571,
+		163, 233, 283, 409, 571
+	};
+
+#endif
+
+	unsigned char ecdsasig[256];
+	unsigned int ecdsasiglen;
+	EC_KEY *ecdsa[EC_NUM];
+	long ecdsa_c[EC_NUM][2];
+
+	EC_KEY *ecdh_a[EC_NUM], *ecdh_b[EC_NUM];
+	unsigned char secret_a[MAX_ECDH_SIZE], secret_b[MAX_ECDH_SIZE];
+	int secret_size_a, secret_size_b;
+	int ecdh_checks = 0;
+	int secret_idx = 0;
+	long ecdh_c[EC_NUM][2];
+
+	int rsa_doit[RSA_NUM];
+	int dsa_doit[DSA_NUM];
+	int ecdsa_doit[EC_NUM];
+	int ecdh_doit[EC_NUM];
+	int doit[ALGOR_NUM];
+	int pr_header = 0;
+	const EVP_CIPHER *evp_cipher = NULL;
+	const EVP_MD *evp_md = NULL;
+	int decrypt = 0;
+	int multi = 0;
+	const char *errstr = NULL;
+
+	if (single_execution) {
+		if (pledge("stdio proc", NULL) == -1) {
+			perror("pledge");
+			exit(1);
+		}
+	}
+
+	usertime = -1;
+
+	memset(results, 0, sizeof(results));
+	memset(dsa_key, 0, sizeof(dsa_key));
+	for (i = 0; i < EC_NUM; i++)
+		ecdsa[i] = NULL;
+	for (i = 0; i < EC_NUM; i++) {
+		ecdh_a[i] = NULL;
+		ecdh_b[i] = NULL;
+	}
+
+	memset(rsa_key, 0, sizeof(rsa_key));
+	for (i = 0; i < RSA_NUM; i++)
+		rsa_key[i] = NULL;
+
+	if ((buf = malloc(BUFSIZE)) == NULL) {
+		BIO_printf(bio_err, "out of memory\n");
+		goto end;
+	}
+	if ((buf2 = malloc(BUFSIZE)) == NULL) {
+		BIO_printf(bio_err, "out of memory\n");
+		goto end;
+	}
+	memset(c, 0, sizeof(c));
+	memset(DES_iv, 0, sizeof(DES_iv));
+	memset(iv, 0, sizeof(iv));
+
+	for (i = 0; i < ALGOR_NUM; i++)
+		doit[i] = 0;
+	for (i = 0; i < RSA_NUM; i++)
+		rsa_doit[i] = 0;
+	for (i = 0; i < DSA_NUM; i++)
+		dsa_doit[i] = 0;
+	for (i = 0; i < EC_NUM; i++)
+		ecdsa_doit[i] = 0;
+	for (i = 0; i < EC_NUM; i++)
+		ecdh_doit[i] = 0;
+
+
+	j = 0;
+	argc--;
+	argv++;
+	while (argc) {
+		if ((argc > 0) && (strcmp(*argv, "-elapsed") == 0)) {
+			usertime = 0;
+			j--;	/* Otherwise, -elapsed gets confused with an
+				 * algorithm. */
+		} else if ((argc > 0) && (strcmp(*argv, "-evp") == 0)) {
+			argc--;
+			argv++;
+			if (argc == 0) {
+				BIO_printf(bio_err, "no EVP given\n");
+				goto end;
+			}
+			evp_cipher = EVP_get_cipherbyname(*argv);
+			if (!evp_cipher) {
+				evp_md = EVP_get_digestbyname(*argv);
+			}
+			if (!evp_cipher && !evp_md) {
+				BIO_printf(bio_err, "%s is an unknown cipher or digest\n", *argv);
+				goto end;
+			}
+			doit[D_EVP] = 1;
+		} else if (argc > 0 && !strcmp(*argv, "-decrypt")) {
+			decrypt = 1;
+			j--;	/* Otherwise, -elapsed gets confused with an
+				 * algorithm. */
+		}
+		else if ((argc > 0) && (strcmp(*argv, "-multi") == 0)) {
+			argc--;
+			argv++;
+			if (argc == 0) {
+				BIO_printf(bio_err, "no multi count given\n");
+				goto end;
+			}
+			multi = strtonum(argv[0], 1, INT_MAX, &errstr);
+			if (errstr) {
+				BIO_printf(bio_err, "bad multi count: %s", errstr);
+				goto end;
+			}
+			j--;	/* Otherwise, -mr gets confused with an
+				 * algorithm. */
+		}
+		else if (argc > 0 && !strcmp(*argv, "-mr")) {
+			mr = 1;
+			j--;	/* Otherwise, -mr gets confused with an
+				 * algorithm. */
+		} else
+#ifndef OPENSSL_NO_MD4
+		if (strcmp(*argv, "md4") == 0)
+			doit[D_MD4] = 1;
+		else
+#endif
+#ifndef OPENSSL_NO_MD5
+		if (strcmp(*argv, "md5") == 0)
+			doit[D_MD5] = 1;
+		else
+#endif
+#ifndef OPENSSL_NO_MD5
+		if (strcmp(*argv, "hmac") == 0)
+			doit[D_HMAC] = 1;
+		else
+#endif
+#ifndef OPENSSL_NO_SHA
+		if (strcmp(*argv, "sha1") == 0)
+			doit[D_SHA1] = 1;
+		else if (strcmp(*argv, "sha") == 0)
+			doit[D_SHA1] = 1,
+			    doit[D_SHA256] = 1,
+			    doit[D_SHA512] = 1;
+		else
+#ifndef OPENSSL_NO_SHA256
+		if (strcmp(*argv, "sha256") == 0)
+			doit[D_SHA256] = 1;
+		else
+#endif
+#ifndef OPENSSL_NO_SHA512
+		if (strcmp(*argv, "sha512") == 0)
+			doit[D_SHA512] = 1;
+		else
+#endif
+#endif
+#ifndef OPENSSL_NO_WHIRLPOOL
+		if (strcmp(*argv, "whirlpool") == 0)
+			doit[D_WHIRLPOOL] = 1;
+		else
+#endif
+#ifndef OPENSSL_NO_RIPEMD
+		if (strcmp(*argv, "ripemd") == 0)
+			doit[D_RMD160] = 1;
+		else if (strcmp(*argv, "rmd160") == 0)
+			doit[D_RMD160] = 1;
+		else if (strcmp(*argv, "ripemd160") == 0)
+			doit[D_RMD160] = 1;
+		else
+#endif
+#ifndef OPENSSL_NO_RC4
+		if (strcmp(*argv, "rc4") == 0)
+			doit[D_RC4] = 1;
+		else
+#endif
+#ifndef OPENSSL_NO_DES
+		if (strcmp(*argv, "des-cbc") == 0)
+			doit[D_CBC_DES] = 1;
+		else if (strcmp(*argv, "des-ede3") == 0)
+			doit[D_EDE3_DES] = 1;
+		else
+#endif
+#ifndef OPENSSL_NO_AES
+		if (strcmp(*argv, "aes-128-cbc") == 0)
+			doit[D_CBC_128_AES] = 1;
+		else if (strcmp(*argv, "aes-192-cbc") == 0)
+			doit[D_CBC_192_AES] = 1;
+		else if (strcmp(*argv, "aes-256-cbc") == 0)
+			doit[D_CBC_256_AES] = 1;
+		else if (strcmp(*argv, "aes-128-ige") == 0)
+			doit[D_IGE_128_AES] = 1;
+		else if (strcmp(*argv, "aes-192-ige") == 0)
+			doit[D_IGE_192_AES] = 1;
+		else if (strcmp(*argv, "aes-256-ige") == 0)
+			doit[D_IGE_256_AES] = 1;
+		else
+#endif
+#ifndef OPENSSL_NO_CAMELLIA
+		if (strcmp(*argv, "camellia-128-cbc") == 0)
+			doit[D_CBC_128_CML] = 1;
+		else if (strcmp(*argv, "camellia-192-cbc") == 0)
+			doit[D_CBC_192_CML] = 1;
+		else if (strcmp(*argv, "camellia-256-cbc") == 0)
+			doit[D_CBC_256_CML] = 1;
+		else
+#endif
+#ifndef RSA_NULL
+		if (strcmp(*argv, "openssl") == 0) {
+			RSA_set_default_method(RSA_PKCS1_SSLeay());
+			j--;
+		} else
+#endif
+		if (strcmp(*argv, "dsa512") == 0)
+			dsa_doit[R_DSA_512] = 2;
+		else if (strcmp(*argv, "dsa1024") == 0)
+			dsa_doit[R_DSA_1024] = 2;
+		else if (strcmp(*argv, "dsa2048") == 0)
+			dsa_doit[R_DSA_2048] = 2;
+		else if (strcmp(*argv, "rsa512") == 0)
+			rsa_doit[R_RSA_512] = 2;
+		else if (strcmp(*argv, "rsa1024") == 0)
+			rsa_doit[R_RSA_1024] = 2;
+		else if (strcmp(*argv, "rsa2048") == 0)
+			rsa_doit[R_RSA_2048] = 2;
+		else if (strcmp(*argv, "rsa4096") == 0)
+			rsa_doit[R_RSA_4096] = 2;
+		else
+#ifndef OPENSSL_NO_RC2
+		if (strcmp(*argv, "rc2-cbc") == 0)
+			doit[D_CBC_RC2] = 1;
+		else if (strcmp(*argv, "rc2") == 0)
+			doit[D_CBC_RC2] = 1;
+		else
+#endif
+#ifndef OPENSSL_NO_IDEA
+		if (strcmp(*argv, "idea-cbc") == 0)
+			doit[D_CBC_IDEA] = 1;
+		else if (strcmp(*argv, "idea") == 0)
+			doit[D_CBC_IDEA] = 1;
+		else
+#endif
+#ifndef OPENSSL_NO_BF
+		if (strcmp(*argv, "bf-cbc") == 0)
+			doit[D_CBC_BF] = 1;
+		else if (strcmp(*argv, "blowfish") == 0)
+			doit[D_CBC_BF] = 1;
+		else if (strcmp(*argv, "bf") == 0)
+			doit[D_CBC_BF] = 1;
+		else
+#endif
+#ifndef OPENSSL_NO_CAST
+		if (strcmp(*argv, "cast-cbc") == 0)
+			doit[D_CBC_CAST] = 1;
+		else if (strcmp(*argv, "cast") == 0)
+			doit[D_CBC_CAST] = 1;
+		else if (strcmp(*argv, "cast5") == 0)
+			doit[D_CBC_CAST] = 1;
+		else
+#endif
+#ifndef OPENSSL_NO_DES
+		if (strcmp(*argv, "des") == 0) {
+			doit[D_CBC_DES] = 1;
+			doit[D_EDE3_DES] = 1;
+		} else
+#endif
+#ifndef OPENSSL_NO_AES
+		if (strcmp(*argv, "aes") == 0) {
+			doit[D_CBC_128_AES] = 1;
+			doit[D_CBC_192_AES] = 1;
+			doit[D_CBC_256_AES] = 1;
+		} else if (strcmp(*argv, "ghash") == 0)
+			doit[D_GHASH] = 1;
+		else if (strcmp(*argv,"aes-128-gcm") == 0)
+			doit[D_AES_128_GCM]=1;
+		else if (strcmp(*argv,"aes-256-gcm") == 0)
+			doit[D_AES_256_GCM]=1;
+		else
+#endif
+#ifndef OPENSSL_NO_CAMELLIA
+		if (strcmp(*argv, "camellia") == 0) {
+			doit[D_CBC_128_CML] = 1;
+			doit[D_CBC_192_CML] = 1;
+			doit[D_CBC_256_CML] = 1;
+		} else
+#endif
+#if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305)
+		if (strcmp(*argv,"chacha20-poly1305") == 0)
+			doit[D_CHACHA20_POLY1305]=1;
+		else
+#endif
+		if (strcmp(*argv, "rsa") == 0) {
+			rsa_doit[R_RSA_512] = 1;
+			rsa_doit[R_RSA_1024] = 1;
+			rsa_doit[R_RSA_2048] = 1;
+			rsa_doit[R_RSA_4096] = 1;
+		} else
+		if (strcmp(*argv, "dsa") == 0) {
+			dsa_doit[R_DSA_512] = 1;
+			dsa_doit[R_DSA_1024] = 1;
+			dsa_doit[R_DSA_2048] = 1;
+		} else
+		if (strcmp(*argv, "ecdsap160") == 0)
+			ecdsa_doit[R_EC_P160] = 2;
+		else if (strcmp(*argv, "ecdsap192") == 0)
+			ecdsa_doit[R_EC_P192] = 2;
+		else if (strcmp(*argv, "ecdsap224") == 0)
+			ecdsa_doit[R_EC_P224] = 2;
+		else if (strcmp(*argv, "ecdsap256") == 0)
+			ecdsa_doit[R_EC_P256] = 2;
+		else if (strcmp(*argv, "ecdsap384") == 0)
+			ecdsa_doit[R_EC_P384] = 2;
+		else if (strcmp(*argv, "ecdsap521") == 0)
+			ecdsa_doit[R_EC_P521] = 2;
+		else if (strcmp(*argv, "ecdsak163") == 0)
+			ecdsa_doit[R_EC_K163] = 2;
+		else if (strcmp(*argv, "ecdsak233") == 0)
+			ecdsa_doit[R_EC_K233] = 2;
+		else if (strcmp(*argv, "ecdsak283") == 0)
+			ecdsa_doit[R_EC_K283] = 2;
+		else if (strcmp(*argv, "ecdsak409") == 0)
+			ecdsa_doit[R_EC_K409] = 2;
+		else if (strcmp(*argv, "ecdsak571") == 0)
+			ecdsa_doit[R_EC_K571] = 2;
+		else if (strcmp(*argv, "ecdsab163") == 0)
+			ecdsa_doit[R_EC_B163] = 2;
+		else if (strcmp(*argv, "ecdsab233") == 0)
+			ecdsa_doit[R_EC_B233] = 2;
+		else if (strcmp(*argv, "ecdsab283") == 0)
+			ecdsa_doit[R_EC_B283] = 2;
+		else if (strcmp(*argv, "ecdsab409") == 0)
+			ecdsa_doit[R_EC_B409] = 2;
+		else if (strcmp(*argv, "ecdsab571") == 0)
+			ecdsa_doit[R_EC_B571] = 2;
+		else if (strcmp(*argv, "ecdsa") == 0) {
+			for (i = 0; i < EC_NUM; i++)
+				ecdsa_doit[i] = 1;
+		} else
+		if (strcmp(*argv, "ecdhp160") == 0)
+			ecdh_doit[R_EC_P160] = 2;
+		else if (strcmp(*argv, "ecdhp192") == 0)
+			ecdh_doit[R_EC_P192] = 2;
+		else if (strcmp(*argv, "ecdhp224") == 0)
+			ecdh_doit[R_EC_P224] = 2;
+		else if (strcmp(*argv, "ecdhp256") == 0)
+			ecdh_doit[R_EC_P256] = 2;
+		else if (strcmp(*argv, "ecdhp384") == 0)
+			ecdh_doit[R_EC_P384] = 2;
+		else if (strcmp(*argv, "ecdhp521") == 0)
+			ecdh_doit[R_EC_P521] = 2;
+		else if (strcmp(*argv, "ecdhk163") == 0)
+			ecdh_doit[R_EC_K163] = 2;
+		else if (strcmp(*argv, "ecdhk233") == 0)
+			ecdh_doit[R_EC_K233] = 2;
+		else if (strcmp(*argv, "ecdhk283") == 0)
+			ecdh_doit[R_EC_K283] = 2;
+		else if (strcmp(*argv, "ecdhk409") == 0)
+			ecdh_doit[R_EC_K409] = 2;
+		else if (strcmp(*argv, "ecdhk571") == 0)
+			ecdh_doit[R_EC_K571] = 2;
+		else if (strcmp(*argv, "ecdhb163") == 0)
+			ecdh_doit[R_EC_B163] = 2;
+		else if (strcmp(*argv, "ecdhb233") == 0)
+			ecdh_doit[R_EC_B233] = 2;
+		else if (strcmp(*argv, "ecdhb283") == 0)
+			ecdh_doit[R_EC_B283] = 2;
+		else if (strcmp(*argv, "ecdhb409") == 0)
+			ecdh_doit[R_EC_B409] = 2;
+		else if (strcmp(*argv, "ecdhb571") == 0)
+			ecdh_doit[R_EC_B571] = 2;
+		else if (strcmp(*argv, "ecdh") == 0) {
+			for (i = 0; i < EC_NUM; i++)
+				ecdh_doit[i] = 1;
+		} else
+		{
+			BIO_printf(bio_err, "Error: bad option or value\n");
+			BIO_printf(bio_err, "\n");
+			BIO_printf(bio_err, "Available values:\n");
+#ifndef OPENSSL_NO_MD4
+			BIO_printf(bio_err, "md4      ");
+#endif
+#ifndef OPENSSL_NO_MD5
+			BIO_printf(bio_err, "md5      ");
+#ifndef OPENSSL_NO_HMAC
+			BIO_printf(bio_err, "hmac     ");
+#endif
+#endif
+#ifndef OPENSSL_NO_SHA1
+			BIO_printf(bio_err, "sha1     ");
+#endif
+#ifndef OPENSSL_NO_SHA256
+			BIO_printf(bio_err, "sha256   ");
+#endif
+#ifndef OPENSSL_NO_SHA512
+			BIO_printf(bio_err, "sha512   ");
+#endif
+#ifndef OPENSSL_NO_WHIRLPOOL
+			BIO_printf(bio_err, "whirlpool");
+#endif
+#ifndef OPENSSL_NO_RIPEMD160
+			BIO_printf(bio_err, "rmd160");
+#endif
+#if !defined(OPENSSL_NO_MD2) || \
+    !defined(OPENSSL_NO_MD4) || !defined(OPENSSL_NO_MD5) || \
+    !defined(OPENSSL_NO_SHA1) || !defined(OPENSSL_NO_RIPEMD160) || \
+    !defined(OPENSSL_NO_WHIRLPOOL)
+			BIO_printf(bio_err, "\n");
+#endif
+
+#ifndef OPENSSL_NO_IDEA
+			BIO_printf(bio_err, "idea-cbc ");
+#endif
+#ifndef OPENSSL_NO_RC2
+			BIO_printf(bio_err, "rc2-cbc  ");
+#endif
+#ifndef OPENSSL_NO_BF
+			BIO_printf(bio_err, "bf-cbc   ");
+#endif
+#ifndef OPENSSL_NO_DES
+			BIO_printf(bio_err, "des-cbc  des-ede3\n");
+#endif
+#ifndef OPENSSL_NO_AES
+			BIO_printf(bio_err, "aes-128-cbc aes-192-cbc aes-256-cbc ");
+			BIO_printf(bio_err, "aes-128-ige aes-192-ige aes-256-ige\n");
+			BIO_printf(bio_err, "aes-128-gcm aes-256-gcm ");
+#endif
+#ifndef OPENSSL_NO_CAMELLIA
+			BIO_printf(bio_err, "\n");
+			BIO_printf(bio_err, "camellia-128-cbc camellia-192-cbc camellia-256-cbc ");
+#endif
+#ifndef OPENSSL_NO_RC4
+			BIO_printf(bio_err, "rc4");
+#endif
+#if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305)
+			BIO_printf(bio_err," chacha20-poly1305");
+#endif
+			BIO_printf(bio_err, "\n");
+
+			BIO_printf(bio_err, "rsa512   rsa1024  rsa2048  rsa4096\n");
+
+			BIO_printf(bio_err, "dsa512   dsa1024  dsa2048\n");
+			BIO_printf(bio_err, "ecdsap160 ecdsap192 ecdsap224 ecdsap256 ecdsap384 ecdsap521\n");
+			BIO_printf(bio_err, "ecdsak163 ecdsak233 ecdsak283 ecdsak409 ecdsak571\n");
+			BIO_printf(bio_err, "ecdsab163 ecdsab233 ecdsab283 ecdsab409 ecdsab571 ecdsa\n");
+			BIO_printf(bio_err, "ecdhp160  ecdhp192  ecdhp224  ecdhp256  ecdhp384  ecdhp521\n");
+			BIO_printf(bio_err, "ecdhk163  ecdhk233  ecdhk283  ecdhk409  ecdhk571\n");
+			BIO_printf(bio_err, "ecdhb163  ecdhb233  ecdhb283  ecdhb409  ecdhb571  ecdh\n");
+
+#ifndef OPENSSL_NO_IDEA
+			BIO_printf(bio_err, "idea     ");
+#endif
+#ifndef OPENSSL_NO_RC2
+			BIO_printf(bio_err, "rc2      ");
+#endif
+#ifndef OPENSSL_NO_DES
+			BIO_printf(bio_err, "des      ");
+#endif
+#ifndef OPENSSL_NO_AES
+			BIO_printf(bio_err, "aes      ");
+#endif
+#ifndef OPENSSL_NO_CAMELLIA
+			BIO_printf(bio_err, "camellia ");
+#endif
+			BIO_printf(bio_err, "rsa      ");
+#ifndef OPENSSL_NO_BF
+			BIO_printf(bio_err, "blowfish");
+#endif
+#if !defined(OPENSSL_NO_IDEA) || !defined(OPENSSL_NO_SEED) || \
+    !defined(OPENSSL_NO_RC2) || !defined(OPENSSL_NO_DES) || \
+    !defined(OPENSSL_NO_RSA) || !defined(OPENSSL_NO_BF) || \
+    !defined(OPENSSL_NO_AES) || !defined(OPENSSL_NO_CAMELLIA)
+			BIO_printf(bio_err, "\n");
+#endif
+
+			BIO_printf(bio_err, "\n");
+			BIO_printf(bio_err, "Available options:\n");
+			BIO_printf(bio_err, "-elapsed        measure time in real time instead of CPU user time.\n");
+			BIO_printf(bio_err, "-evp e          use EVP e.\n");
+			BIO_printf(bio_err, "-decrypt        time decryption instead of encryption (only EVP).\n");
+			BIO_printf(bio_err, "-mr             produce machine readable output.\n");
+			BIO_printf(bio_err, "-multi n        run n benchmarks in parallel.\n");
+			goto end;
+		}
+		argc--;
+		argv++;
+		j++;
+	}
+
+	if (multi && do_multi(multi))
+		goto show_res;
+
+	if (j == 0) {
+		for (i = 0; i < ALGOR_NUM; i++) {
+			if (i != D_EVP)
+				doit[i] = 1;
+		}
+		for (i = 0; i < RSA_NUM; i++)
+			rsa_doit[i] = 1;
+		for (i = 0; i < DSA_NUM; i++)
+			dsa_doit[i] = 1;
+		for (i = 0; i < EC_NUM; i++)
+			ecdsa_doit[i] = 1;
+		for (i = 0; i < EC_NUM; i++)
+			ecdh_doit[i] = 1;
+	}
+	for (i = 0; i < ALGOR_NUM; i++)
+		if (doit[i])
+			pr_header++;
+
+	if (usertime == 0 && !mr)
+		BIO_printf(bio_err, "You have chosen to measure elapsed time instead of user CPU time.\n");
+
+	for (i = 0; i < RSA_NUM; i++) {
+		const unsigned char *p;
+
+		p = rsa_data[i];
+		rsa_key[i] = d2i_RSAPrivateKey(NULL, &p, rsa_data_length[i]);
+		if (rsa_key[i] == NULL) {
+			BIO_printf(bio_err, "internal error loading RSA key number %d\n", i);
+			goto end;
+		}
+	}
+
+	dsa_key[0] = get_dsa512();
+	dsa_key[1] = get_dsa1024();
+	dsa_key[2] = get_dsa2048();
+
+#ifndef OPENSSL_NO_DES
+	DES_set_key_unchecked(&key, &sch);
+	DES_set_key_unchecked(&key2, &sch2);
+	DES_set_key_unchecked(&key3, &sch3);
+#endif
+#ifndef OPENSSL_NO_AES
+	AES_set_encrypt_key(key16, 128, &aes_ks1);
+	AES_set_encrypt_key(key24, 192, &aes_ks2);
+	AES_set_encrypt_key(key32, 256, &aes_ks3);
+#endif
+#ifndef OPENSSL_NO_CAMELLIA
+	Camellia_set_key(key16, 128, &camellia_ks1);
+	Camellia_set_key(ckey24, 192, &camellia_ks2);
+	Camellia_set_key(ckey32, 256, &camellia_ks3);
+#endif
+#ifndef OPENSSL_NO_IDEA
+	idea_set_encrypt_key(key16, &idea_ks);
+#endif
+#ifndef OPENSSL_NO_RC4
+	RC4_set_key(&rc4_ks, 16, key16);
+#endif
+#ifndef OPENSSL_NO_RC2
+	RC2_set_key(&rc2_ks, 16, key16, 128);
+#endif
+#ifndef OPENSSL_NO_BF
+	BF_set_key(&bf_ks, 16, key16);
+#endif
+#ifndef OPENSSL_NO_CAST
+	CAST_set_key(&cast_ks, 16, key16);
+#endif
+	memset(rsa_c, 0, sizeof(rsa_c));
+#define COND(c)	(run && count<0x7fffffff)
+#define COUNT(d) (count)
+	signal(SIGALRM, sig_done);
+
+#ifndef OPENSSL_NO_MD4
+	if (doit[D_MD4]) {
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_MD4], c[D_MD4][j], lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_MD4][j]); count++)
+				EVP_Digest(&(buf[0]), (unsigned long) lengths[j], &(md4[0]), NULL, EVP_md4(), NULL);
+			d = Time_F(STOP);
+			print_result(D_MD4, j, count, d);
+		}
+	}
+#endif
+
+#ifndef OPENSSL_NO_MD5
+	if (doit[D_MD5]) {
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_MD5], c[D_MD5][j], lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_MD5][j]); count++)
+				EVP_Digest(&(buf[0]), (unsigned long) lengths[j], &(md5[0]), NULL, EVP_get_digestbyname("md5"), NULL);
+			d = Time_F(STOP);
+			print_result(D_MD5, j, count, d);
+		}
+	}
+#endif
+
+#if !defined(OPENSSL_NO_MD5) && !defined(OPENSSL_NO_HMAC)
+	if (doit[D_HMAC]) {
+		HMAC_CTX hctx;
+
+		HMAC_CTX_init(&hctx);
+		HMAC_Init_ex(&hctx, (unsigned char *) "This is a key...",
+		    16, EVP_md5(), NULL);
+
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_HMAC], c[D_HMAC][j], lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_HMAC][j]); count++) {
+				HMAC_Init_ex(&hctx, NULL, 0, NULL, NULL);
+				HMAC_Update(&hctx, buf, lengths[j]);
+				HMAC_Final(&hctx, &(hmac[0]), NULL);
+			}
+			d = Time_F(STOP);
+			print_result(D_HMAC, j, count, d);
+		}
+		HMAC_CTX_cleanup(&hctx);
+	}
+#endif
+#ifndef OPENSSL_NO_SHA
+	if (doit[D_SHA1]) {
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_SHA1], c[D_SHA1][j], lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_SHA1][j]); count++)
+				EVP_Digest(buf, (unsigned long) lengths[j], &(sha[0]), NULL, EVP_sha1(), NULL);
+			d = Time_F(STOP);
+			print_result(D_SHA1, j, count, d);
+		}
+	}
+#ifndef OPENSSL_NO_SHA256
+	if (doit[D_SHA256]) {
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_SHA256], c[D_SHA256][j], lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_SHA256][j]); count++)
+				SHA256(buf, lengths[j], sha256);
+			d = Time_F(STOP);
+			print_result(D_SHA256, j, count, d);
+		}
+	}
+#endif
+
+#ifndef OPENSSL_NO_SHA512
+	if (doit[D_SHA512]) {
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_SHA512], c[D_SHA512][j], lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_SHA512][j]); count++)
+				SHA512(buf, lengths[j], sha512);
+			d = Time_F(STOP);
+			print_result(D_SHA512, j, count, d);
+		}
+	}
+#endif
+#endif
+
+#ifndef OPENSSL_NO_WHIRLPOOL
+	if (doit[D_WHIRLPOOL]) {
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_WHIRLPOOL], c[D_WHIRLPOOL][j], lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_WHIRLPOOL][j]); count++)
+				WHIRLPOOL(buf, lengths[j], whirlpool);
+			d = Time_F(STOP);
+			print_result(D_WHIRLPOOL, j, count, d);
+		}
+	}
+#endif
+
+#ifndef OPENSSL_NO_RIPEMD
+	if (doit[D_RMD160]) {
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_RMD160], c[D_RMD160][j], lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_RMD160][j]); count++)
+				EVP_Digest(buf, (unsigned long) lengths[j], &(rmd160[0]), NULL, EVP_ripemd160(), NULL);
+			d = Time_F(STOP);
+			print_result(D_RMD160, j, count, d);
+		}
+	}
+#endif
+#ifndef OPENSSL_NO_RC4
+	if (doit[D_RC4]) {
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_RC4], c[D_RC4][j], lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_RC4][j]); count++)
+				RC4(&rc4_ks, (unsigned int) lengths[j],
+				    buf, buf);
+			d = Time_F(STOP);
+			print_result(D_RC4, j, count, d);
+		}
+	}
+#endif
+#ifndef OPENSSL_NO_DES
+	if (doit[D_CBC_DES]) {
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_CBC_DES], c[D_CBC_DES][j], lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_CBC_DES][j]); count++)
+				DES_ncbc_encrypt(buf, buf, lengths[j], &sch,
+				    &DES_iv, DES_ENCRYPT);
+			d = Time_F(STOP);
+			print_result(D_CBC_DES, j, count, d);
+		}
+	}
+	if (doit[D_EDE3_DES]) {
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_EDE3_DES], c[D_EDE3_DES][j], lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_EDE3_DES][j]); count++)
+				DES_ede3_cbc_encrypt(buf, buf, lengths[j],
+				    &sch, &sch2, &sch3,
+				    &DES_iv, DES_ENCRYPT);
+			d = Time_F(STOP);
+			print_result(D_EDE3_DES, j, count, d);
+		}
+	}
+#endif
+#ifndef OPENSSL_NO_AES
+	if (doit[D_CBC_128_AES]) {
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_CBC_128_AES], c[D_CBC_128_AES][j], lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_CBC_128_AES][j]); count++)
+				AES_cbc_encrypt(buf, buf,
+				    (unsigned long) lengths[j], &aes_ks1,
+				    iv, AES_ENCRYPT);
+			d = Time_F(STOP);
+			print_result(D_CBC_128_AES, j, count, d);
+		}
+	}
+	if (doit[D_CBC_192_AES]) {
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_CBC_192_AES], c[D_CBC_192_AES][j], lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_CBC_192_AES][j]); count++)
+				AES_cbc_encrypt(buf, buf,
+				    (unsigned long) lengths[j], &aes_ks2,
+				    iv, AES_ENCRYPT);
+			d = Time_F(STOP);
+			print_result(D_CBC_192_AES, j, count, d);
+		}
+	}
+	if (doit[D_CBC_256_AES]) {
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_CBC_256_AES], c[D_CBC_256_AES][j], lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_CBC_256_AES][j]); count++)
+				AES_cbc_encrypt(buf, buf,
+				    (unsigned long) lengths[j], &aes_ks3,
+				    iv, AES_ENCRYPT);
+			d = Time_F(STOP);
+			print_result(D_CBC_256_AES, j, count, d);
+		}
+	}
+	if (doit[D_IGE_128_AES]) {
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_IGE_128_AES], c[D_IGE_128_AES][j], lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_IGE_128_AES][j]); count++)
+				AES_ige_encrypt(buf, buf2,
+				    (unsigned long) lengths[j], &aes_ks1,
+				    iv, AES_ENCRYPT);
+			d = Time_F(STOP);
+			print_result(D_IGE_128_AES, j, count, d);
+		}
+	}
+	if (doit[D_IGE_192_AES]) {
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_IGE_192_AES], c[D_IGE_192_AES][j], lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_IGE_192_AES][j]); count++)
+				AES_ige_encrypt(buf, buf2,
+				    (unsigned long) lengths[j], &aes_ks2,
+				    iv, AES_ENCRYPT);
+			d = Time_F(STOP);
+			print_result(D_IGE_192_AES, j, count, d);
+		}
+	}
+	if (doit[D_IGE_256_AES]) {
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_IGE_256_AES], c[D_IGE_256_AES][j], lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_IGE_256_AES][j]); count++)
+				AES_ige_encrypt(buf, buf2,
+				    (unsigned long) lengths[j], &aes_ks3,
+				    iv, AES_ENCRYPT);
+			d = Time_F(STOP);
+			print_result(D_IGE_256_AES, j, count, d);
+		}
+	}
+	if (doit[D_GHASH]) {
+		GCM128_CONTEXT *ctx = CRYPTO_gcm128_new(&aes_ks1, (block128_f) AES_encrypt);
+		CRYPTO_gcm128_setiv(ctx, (unsigned char *) "0123456789ab", 12);
+
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_GHASH], c[D_GHASH][j], lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_GHASH][j]); count++)
+				CRYPTO_gcm128_aad(ctx, buf, lengths[j]);
+			d = Time_F(STOP);
+			print_result(D_GHASH, j, count, d);
+		}
+		CRYPTO_gcm128_release(ctx);
+	}
+	if (doit[D_AES_128_GCM]) {
+		const EVP_AEAD *aead = EVP_aead_aes_128_gcm();
+		static const unsigned char nonce[32] = {0};
+		size_t buf_len, nonce_len;
+		EVP_AEAD_CTX ctx;
+
+		EVP_AEAD_CTX_init(&ctx, aead, key32, EVP_AEAD_key_length(aead),
+		    EVP_AEAD_DEFAULT_TAG_LENGTH, NULL);
+		nonce_len = EVP_AEAD_nonce_length(aead);
+
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_AES_128_GCM],c[D_AES_128_GCM][j],lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_AES_128_GCM][j]); count++)
+				EVP_AEAD_CTX_seal(&ctx, buf, &buf_len, BUFSIZE, nonce,
+				    nonce_len, buf, lengths[j], NULL, 0);
+			d=Time_F(STOP);
+			print_result(D_AES_128_GCM,j,count,d);
+		}
+		EVP_AEAD_CTX_cleanup(&ctx);
+	}
+
+	if (doit[D_AES_256_GCM]) {
+		const EVP_AEAD *aead = EVP_aead_aes_256_gcm();
+		static const unsigned char nonce[32] = {0};
+		size_t buf_len, nonce_len;
+		EVP_AEAD_CTX ctx;
+
+		EVP_AEAD_CTX_init(&ctx, aead, key32, EVP_AEAD_key_length(aead),
+		EVP_AEAD_DEFAULT_TAG_LENGTH, NULL);
+		nonce_len = EVP_AEAD_nonce_length(aead);
+
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_AES_256_GCM],c[D_AES_256_GCM][j],lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_AES_256_GCM][j]); count++)
+				EVP_AEAD_CTX_seal(&ctx, buf, &buf_len, BUFSIZE, nonce,
+				    nonce_len, buf, lengths[j], NULL, 0);
+			d=Time_F(STOP);
+			print_result(D_AES_256_GCM, j, count, d);
+		}
+		EVP_AEAD_CTX_cleanup(&ctx);
+	}
+#endif
+#if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305)
+	if (doit[D_CHACHA20_POLY1305]) {
+		const EVP_AEAD *aead = EVP_aead_chacha20_poly1305();
+		static const unsigned char nonce[32] = {0};
+		size_t buf_len, nonce_len;
+		EVP_AEAD_CTX ctx;
+
+		EVP_AEAD_CTX_init(&ctx, aead, key32, EVP_AEAD_key_length(aead),
+		    EVP_AEAD_DEFAULT_TAG_LENGTH, NULL);
+		nonce_len = EVP_AEAD_nonce_length(aead);
+
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_CHACHA20_POLY1305],
+			    c[D_CHACHA20_POLY1305][j], lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_CHACHA20_POLY1305][j]); count++)
+				EVP_AEAD_CTX_seal(&ctx, buf, &buf_len, BUFSIZE, nonce,
+				    nonce_len, buf, lengths[j], NULL, 0);
+			d=Time_F(STOP);
+			print_result(D_CHACHA20_POLY1305, j, count, d);
+		}
+		EVP_AEAD_CTX_cleanup(&ctx);
+	}
+#endif
+#ifndef OPENSSL_NO_CAMELLIA
+	if (doit[D_CBC_128_CML]) {
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_CBC_128_CML], c[D_CBC_128_CML][j], lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_CBC_128_CML][j]); count++)
+				Camellia_cbc_encrypt(buf, buf,
+				    (unsigned long) lengths[j], &camellia_ks1,
+				    iv, CAMELLIA_ENCRYPT);
+			d = Time_F(STOP);
+			print_result(D_CBC_128_CML, j, count, d);
+		}
+	}
+	if (doit[D_CBC_192_CML]) {
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_CBC_192_CML], c[D_CBC_192_CML][j], lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_CBC_192_CML][j]); count++)
+				Camellia_cbc_encrypt(buf, buf,
+				    (unsigned long) lengths[j], &camellia_ks2,
+				    iv, CAMELLIA_ENCRYPT);
+			d = Time_F(STOP);
+			print_result(D_CBC_192_CML, j, count, d);
+		}
+	}
+	if (doit[D_CBC_256_CML]) {
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_CBC_256_CML], c[D_CBC_256_CML][j], lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_CBC_256_CML][j]); count++)
+				Camellia_cbc_encrypt(buf, buf,
+				    (unsigned long) lengths[j], &camellia_ks3,
+				    iv, CAMELLIA_ENCRYPT);
+			d = Time_F(STOP);
+			print_result(D_CBC_256_CML, j, count, d);
+		}
+	}
+#endif
+#ifndef OPENSSL_NO_IDEA
+	if (doit[D_CBC_IDEA]) {
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_CBC_IDEA], c[D_CBC_IDEA][j], lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_CBC_IDEA][j]); count++)
+				idea_cbc_encrypt(buf, buf,
+				    (unsigned long) lengths[j], &idea_ks,
+				    iv, IDEA_ENCRYPT);
+			d = Time_F(STOP);
+			print_result(D_CBC_IDEA, j, count, d);
+		}
+	}
+#endif
+#ifndef OPENSSL_NO_RC2
+	if (doit[D_CBC_RC2]) {
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_CBC_RC2], c[D_CBC_RC2][j], lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_CBC_RC2][j]); count++)
+				RC2_cbc_encrypt(buf, buf,
+				    (unsigned long) lengths[j], &rc2_ks,
+				    iv, RC2_ENCRYPT);
+			d = Time_F(STOP);
+			print_result(D_CBC_RC2, j, count, d);
+		}
+	}
+#endif
+#ifndef OPENSSL_NO_BF
+	if (doit[D_CBC_BF]) {
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_CBC_BF], c[D_CBC_BF][j], lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_CBC_BF][j]); count++)
+				BF_cbc_encrypt(buf, buf,
+				    (unsigned long) lengths[j], &bf_ks,
+				    iv, BF_ENCRYPT);
+			d = Time_F(STOP);
+			print_result(D_CBC_BF, j, count, d);
+		}
+	}
+#endif
+#ifndef OPENSSL_NO_CAST
+	if (doit[D_CBC_CAST]) {
+		for (j = 0; j < SIZE_NUM; j++) {
+			print_message(names[D_CBC_CAST], c[D_CBC_CAST][j], lengths[j]);
+			Time_F(START);
+			for (count = 0, run = 1; COND(c[D_CBC_CAST][j]); count++)
+				CAST_cbc_encrypt(buf, buf,
+				    (unsigned long) lengths[j], &cast_ks,
+				    iv, CAST_ENCRYPT);
+			d = Time_F(STOP);
+			print_result(D_CBC_CAST, j, count, d);
+		}
+	}
+#endif
+
+	if (doit[D_EVP]) {
+		for (j = 0; j < SIZE_NUM; j++) {
+			if (evp_cipher) {
+				EVP_CIPHER_CTX ctx;
+				int outl;
+
+				names[D_EVP] = OBJ_nid2ln(evp_cipher->nid);
+				/*
+				 * -O3 -fschedule-insns messes up an
+				 * optimization here!  names[D_EVP] somehow
+				 * becomes NULL
+				 */
+				print_message(names[D_EVP], save_count,
+				    lengths[j]);
+
+				EVP_CIPHER_CTX_init(&ctx);
+				if (decrypt)
+					EVP_DecryptInit_ex(&ctx, evp_cipher, NULL, key16, iv);
+				else
+					EVP_EncryptInit_ex(&ctx, evp_cipher, NULL, key16, iv);
+				EVP_CIPHER_CTX_set_padding(&ctx, 0);
+
+				Time_F(START);
+				if (decrypt)
+					for (count = 0, run = 1; COND(save_count * 4 * lengths[0] / lengths[j]); count++)
+						EVP_DecryptUpdate(&ctx, buf, &outl, buf, lengths[j]);
+				else
+					for (count = 0, run = 1; COND(save_count * 4 * lengths[0] / lengths[j]); count++)
+						EVP_EncryptUpdate(&ctx, buf, &outl, buf, lengths[j]);
+				if (decrypt)
+					EVP_DecryptFinal_ex(&ctx, buf, &outl);
+				else
+					EVP_EncryptFinal_ex(&ctx, buf, &outl);
+				d = Time_F(STOP);
+				EVP_CIPHER_CTX_cleanup(&ctx);
+			}
+			if (evp_md) {
+				names[D_EVP] = OBJ_nid2ln(evp_md->type);
+				print_message(names[D_EVP], save_count,
+				    lengths[j]);
+
+				Time_F(START);
+				for (count = 0, run = 1; COND(save_count * 4 * lengths[0] / lengths[j]); count++)
+					EVP_Digest(buf, lengths[j], &(md[0]), NULL, evp_md, NULL);
+
+				d = Time_F(STOP);
+			}
+			print_result(D_EVP, j, count, d);
+		}
+	}
+	arc4random_buf(buf, 36);
+	for (j = 0; j < RSA_NUM; j++) {
+		int ret;
+		if (!rsa_doit[j])
+			continue;
+		ret = RSA_sign(NID_md5_sha1, buf, 36, buf2, &rsa_num, rsa_key[j]);
+		if (ret == 0) {
+			BIO_printf(bio_err, "RSA sign failure.  No RSA sign will be done.\n");
+			ERR_print_errors(bio_err);
+			rsa_count = 1;
+		} else {
+			pkey_print_message("private", "rsa",
+			    rsa_c[j][0], rsa_bits[j],
+			    RSA_SECONDS);
+/*			RSA_blinding_on(rsa_key[j],NULL); */
+			Time_F(START);
+			for (count = 0, run = 1; COND(rsa_c[j][0]); count++) {
+				ret = RSA_sign(NID_md5_sha1, buf, 36, buf2,
+				    &rsa_num, rsa_key[j]);
+				if (ret == 0) {
+					BIO_printf(bio_err,
+					    "RSA sign failure\n");
+					ERR_print_errors(bio_err);
+					count = 1;
+					break;
+				}
+			}
+			d = Time_F(STOP);
+			BIO_printf(bio_err, mr ? "+R1:%ld:%d:%.2f\n"
+			    : "%ld %d bit private RSA's in %.2fs\n",
+			    count, rsa_bits[j], d);
+			rsa_results[j][0] = d / (double) count;
+			rsa_count = count;
+		}
+
+		ret = RSA_verify(NID_md5_sha1, buf, 36, buf2, rsa_num, rsa_key[j]);
+		if (ret <= 0) {
+			BIO_printf(bio_err, "RSA verify failure.  No RSA verify will be done.\n");
+			ERR_print_errors(bio_err);
+			rsa_doit[j] = 0;
+		} else {
+			pkey_print_message("public", "rsa",
+			    rsa_c[j][1], rsa_bits[j],
+			    RSA_SECONDS);
+			Time_F(START);
+			for (count = 0, run = 1; COND(rsa_c[j][1]); count++) {
+				ret = RSA_verify(NID_md5_sha1, buf, 36, buf2,
+				    rsa_num, rsa_key[j]);
+				if (ret <= 0) {
+					BIO_printf(bio_err,
+					    "RSA verify failure\n");
+					ERR_print_errors(bio_err);
+					count = 1;
+					break;
+				}
+			}
+			d = Time_F(STOP);
+			BIO_printf(bio_err, mr ? "+R2:%ld:%d:%.2f\n"
+			    : "%ld %d bit public RSA's in %.2fs\n",
+			    count, rsa_bits[j], d);
+			rsa_results[j][1] = d / (double) count;
+		}
+
+		if (rsa_count <= 1) {
+			/* if longer than 10s, don't do any more */
+			for (j++; j < RSA_NUM; j++)
+				rsa_doit[j] = 0;
+		}
+	}
+
+	arc4random_buf(buf, 20);
+	for (j = 0; j < DSA_NUM; j++) {
+		unsigned int kk;
+		int ret;
+
+		if (!dsa_doit[j])
+			continue;
+/*		DSA_generate_key(dsa_key[j]); */
+/*		DSA_sign_setup(dsa_key[j],NULL); */
+		ret = DSA_sign(EVP_PKEY_DSA, buf, 20, buf2,
+		    &kk, dsa_key[j]);
+		if (ret == 0) {
+			BIO_printf(bio_err, "DSA sign failure.  No DSA sign will be done.\n");
+			ERR_print_errors(bio_err);
+			rsa_count = 1;
+		} else {
+			pkey_print_message("sign", "dsa",
+			    dsa_c[j][0], dsa_bits[j],
+			    DSA_SECONDS);
+			Time_F(START);
+			for (count = 0, run = 1; COND(dsa_c[j][0]); count++) {
+				ret = DSA_sign(EVP_PKEY_DSA, buf, 20, buf2,
+				    &kk, dsa_key[j]);
+				if (ret == 0) {
+					BIO_printf(bio_err,
+					    "DSA sign failure\n");
+					ERR_print_errors(bio_err);
+					count = 1;
+					break;
+				}
+			}
+			d = Time_F(STOP);
+			BIO_printf(bio_err, mr ? "+R3:%ld:%d:%.2f\n"
+			    : "%ld %d bit DSA signs in %.2fs\n",
+			    count, dsa_bits[j], d);
+			dsa_results[j][0] = d / (double) count;
+			rsa_count = count;
+		}
+
+		ret = DSA_verify(EVP_PKEY_DSA, buf, 20, buf2,
+		    kk, dsa_key[j]);
+		if (ret <= 0) {
+			BIO_printf(bio_err, "DSA verify failure.  No DSA verify will be done.\n");
+			ERR_print_errors(bio_err);
+			dsa_doit[j] = 0;
+		} else {
+			pkey_print_message("verify", "dsa",
+			    dsa_c[j][1], dsa_bits[j],
+			    DSA_SECONDS);
+			Time_F(START);
+			for (count = 0, run = 1; COND(dsa_c[j][1]); count++) {
+				ret = DSA_verify(EVP_PKEY_DSA, buf, 20, buf2,
+				    kk, dsa_key[j]);
+				if (ret <= 0) {
+					BIO_printf(bio_err,
+					    "DSA verify failure\n");
+					ERR_print_errors(bio_err);
+					count = 1;
+					break;
+				}
+			}
+			d = Time_F(STOP);
+			BIO_printf(bio_err, mr ? "+R4:%ld:%d:%.2f\n"
+			    : "%ld %d bit DSA verify in %.2fs\n",
+			    count, dsa_bits[j], d);
+			dsa_results[j][1] = d / (double) count;
+		}
+
+		if (rsa_count <= 1) {
+			/* if longer than 10s, don't do any more */
+			for (j++; j < DSA_NUM; j++)
+				dsa_doit[j] = 0;
+		}
+	}
+
+	for (j = 0; j < EC_NUM; j++) {
+		int ret;
+
+		if (!ecdsa_doit[j])
+			continue;	/* Ignore Curve */
+		ecdsa[j] = EC_KEY_new_by_curve_name(test_curves[j]);
+		if (ecdsa[j] == NULL) {
+			BIO_printf(bio_err, "ECDSA failure.\n");
+			ERR_print_errors(bio_err);
+			rsa_count = 1;
+		} else {
+			EC_KEY_precompute_mult(ecdsa[j], NULL);
+
+			/* Perform ECDSA signature test */
+			EC_KEY_generate_key(ecdsa[j]);
+			ret = ECDSA_sign(0, buf, 20, ecdsasig,
+			    &ecdsasiglen, ecdsa[j]);
+			if (ret == 0) {
+				BIO_printf(bio_err, "ECDSA sign failure.  No ECDSA sign will be done.\n");
+				ERR_print_errors(bio_err);
+				rsa_count = 1;
+			} else {
+				pkey_print_message("sign", "ecdsa",
+				    ecdsa_c[j][0],
+				    test_curves_bits[j],
+				    ECDSA_SECONDS);
+
+				Time_F(START);
+				for (count = 0, run = 1; COND(ecdsa_c[j][0]);
+				    count++) {
+					ret = ECDSA_sign(0, buf, 20,
+					    ecdsasig, &ecdsasiglen,
+					    ecdsa[j]);
+					if (ret == 0) {
+						BIO_printf(bio_err, "ECDSA sign failure\n");
+						ERR_print_errors(bio_err);
+						count = 1;
+						break;
+					}
+				}
+				d = Time_F(STOP);
+
+				BIO_printf(bio_err, mr ? "+R5:%ld:%d:%.2f\n" :
+				    "%ld %d bit ECDSA signs in %.2fs \n",
+				    count, test_curves_bits[j], d);
+				ecdsa_results[j][0] = d / (double) count;
+				rsa_count = count;
+			}
+
+			/* Perform ECDSA verification test */
+			ret = ECDSA_verify(0, buf, 20, ecdsasig,
+			    ecdsasiglen, ecdsa[j]);
+			if (ret != 1) {
+				BIO_printf(bio_err, "ECDSA verify failure.  No ECDSA verify will be done.\n");
+				ERR_print_errors(bio_err);
+				ecdsa_doit[j] = 0;
+			} else {
+				pkey_print_message("verify", "ecdsa",
+				    ecdsa_c[j][1],
+				    test_curves_bits[j],
+				    ECDSA_SECONDS);
+				Time_F(START);
+				for (count = 0, run = 1; COND(ecdsa_c[j][1]); count++) {
+					ret = ECDSA_verify(0, buf, 20, ecdsasig, ecdsasiglen, ecdsa[j]);
+					if (ret != 1) {
+						BIO_printf(bio_err, "ECDSA verify failure\n");
+						ERR_print_errors(bio_err);
+						count = 1;
+						break;
+					}
+				}
+				d = Time_F(STOP);
+				BIO_printf(bio_err, mr ? "+R6:%ld:%d:%.2f\n"
+				    : "%ld %d bit ECDSA verify in %.2fs\n",
+				    count, test_curves_bits[j], d);
+				ecdsa_results[j][1] = d / (double) count;
+			}
+
+			if (rsa_count <= 1) {
+				/* if longer than 10s, don't do any more */
+				for (j++; j < EC_NUM; j++)
+					ecdsa_doit[j] = 0;
+			}
+		}
+	}
+
+	for (j = 0; j < EC_NUM; j++) {
+		if (!ecdh_doit[j])
+			continue;
+		ecdh_a[j] = EC_KEY_new_by_curve_name(test_curves[j]);
+		ecdh_b[j] = EC_KEY_new_by_curve_name(test_curves[j]);
+		if ((ecdh_a[j] == NULL) || (ecdh_b[j] == NULL)) {
+			BIO_printf(bio_err, "ECDH failure.\n");
+			ERR_print_errors(bio_err);
+			rsa_count = 1;
+		} else {
+			/* generate two ECDH key pairs */
+			if (!EC_KEY_generate_key(ecdh_a[j]) ||
+			    !EC_KEY_generate_key(ecdh_b[j])) {
+				BIO_printf(bio_err, "ECDH key generation failure.\n");
+				ERR_print_errors(bio_err);
+				rsa_count = 1;
+			} else {
+				/*
+				 * If field size is not more than 24 octets,
+				 * then use SHA-1 hash of result; otherwise,
+				 * use result (see section 4.8 of
+				 * draft-ietf-tls-ecc-03.txt).
+				 */
+				int field_size, outlen;
+				void *(*kdf) (const void *in, size_t inlen, void *out, size_t * xoutlen);
+				field_size = EC_GROUP_get_degree(EC_KEY_get0_group(ecdh_a[j]));
+				if (field_size <= 24 * 8) {
+					outlen = KDF1_SHA1_len;
+					kdf = KDF1_SHA1;
+				} else {
+					outlen = (field_size + 7) / 8;
+					kdf = NULL;
+				}
+				secret_size_a = ECDH_compute_key(secret_a, outlen,
+				    EC_KEY_get0_public_key(ecdh_b[j]),
+				    ecdh_a[j], kdf);
+				secret_size_b = ECDH_compute_key(secret_b, outlen,
+				    EC_KEY_get0_public_key(ecdh_a[j]),
+				    ecdh_b[j], kdf);
+				if (secret_size_a != secret_size_b)
+					ecdh_checks = 0;
+				else
+					ecdh_checks = 1;
+
+				for (secret_idx = 0;
+				    (secret_idx < secret_size_a)
+				    && (ecdh_checks == 1);
+				    secret_idx++) {
+					if (secret_a[secret_idx] != secret_b[secret_idx])
+						ecdh_checks = 0;
+				}
+
+				if (ecdh_checks == 0) {
+					BIO_printf(bio_err,
+					    "ECDH computations don't match.\n");
+					ERR_print_errors(bio_err);
+					rsa_count = 1;
+				} else {
+					pkey_print_message("", "ecdh",
+					    ecdh_c[j][0],
+					    test_curves_bits[j],
+					    ECDH_SECONDS);
+					Time_F(START);
+					for (count = 0, run = 1;
+					     COND(ecdh_c[j][0]); count++) {
+						ECDH_compute_key(secret_a,
+						    outlen,
+						    EC_KEY_get0_public_key(ecdh_b[j]),
+						    ecdh_a[j], kdf);
+					}
+					d = Time_F(STOP);
+					BIO_printf(bio_err, mr
+					    ? "+R7:%ld:%d:%.2f\n"
+					    : "%ld %d-bit ECDH ops in %.2fs\n",
+					    count, test_curves_bits[j], d);
+					ecdh_results[j][0] = d / (double) count;
+					rsa_count = count;
+				}
+			}
+		}
+
+
+		if (rsa_count <= 1) {
+			/* if longer than 10s, don't do any more */
+			for (j++; j < EC_NUM; j++)
+				ecdh_doit[j] = 0;
+		}
+	}
+show_res:
+	if (!mr) {
+		fprintf(stdout, "%s\n", SSLeay_version(SSLEAY_VERSION));
+		fprintf(stdout, "%s\n", SSLeay_version(SSLEAY_BUILT_ON));
+		printf("options:");
+		printf("%s ", BN_options());
+#ifndef OPENSSL_NO_RC4
+		printf("%s ", RC4_options());
+#endif
+#ifndef OPENSSL_NO_DES
+		printf("%s ", DES_options());
+#endif
+#ifndef OPENSSL_NO_AES
+		printf("%s ", AES_options());
+#endif
+#ifndef OPENSSL_NO_IDEA
+		printf("%s ", idea_options());
+#endif
+#ifndef OPENSSL_NO_BF
+		printf("%s ", BF_options());
+#endif
+		fprintf(stdout, "\n%s\n", SSLeay_version(SSLEAY_CFLAGS));
+	}
+	if (pr_header) {
+		if (mr)
+			fprintf(stdout, "+H");
+		else {
+			fprintf(stdout, "The 'numbers' are in 1000s of bytes per second processed.\n");
+			fprintf(stdout, "type        ");
+		}
+		for (j = 0; j < SIZE_NUM; j++)
+			fprintf(stdout, mr ? ":%d" : "%7d bytes", lengths[j]);
+		fprintf(stdout, "\n");
+	}
+	for (k = 0; k < ALGOR_NUM; k++) {
+		if (!doit[k])
+			continue;
+		if (mr)
+			fprintf(stdout, "+F:%d:%s", k, names[k]);
+		else
+			fprintf(stdout, "%-13s", names[k]);
+		for (j = 0; j < SIZE_NUM; j++) {
+			if (results[k][j] > 10000 && !mr)
+				fprintf(stdout, " %11.2fk", results[k][j] / 1e3);
+			else
+				fprintf(stdout, mr ? ":%.2f" : " %11.2f ", results[k][j]);
+		}
+		fprintf(stdout, "\n");
+	}
+	j = 1;
+	for (k = 0; k < RSA_NUM; k++) {
+		if (!rsa_doit[k])
+			continue;
+		if (j && !mr) {
+			printf("%18ssign    verify    sign/s verify/s\n", " ");
+			j = 0;
+		}
+		if (mr)
+			fprintf(stdout, "+F2:%u:%u:%f:%f\n",
+			    k, rsa_bits[k], rsa_results[k][0],
+			    rsa_results[k][1]);
+		else
+			fprintf(stdout, "rsa %4u bits %8.6fs %8.6fs %8.1f %8.1f\n",
+			    rsa_bits[k], rsa_results[k][0], rsa_results[k][1],
+			    1.0 / rsa_results[k][0], 1.0 / rsa_results[k][1]);
+	}
+	j = 1;
+	for (k = 0; k < DSA_NUM; k++) {
+		if (!dsa_doit[k])
+			continue;
+		if (j && !mr) {
+			printf("%18ssign    verify    sign/s verify/s\n", " ");
+			j = 0;
+		}
+		if (mr)
+			fprintf(stdout, "+F3:%u:%u:%f:%f\n",
+			    k, dsa_bits[k], dsa_results[k][0], dsa_results[k][1]);
+		else
+			fprintf(stdout, "dsa %4u bits %8.6fs %8.6fs %8.1f %8.1f\n",
+			    dsa_bits[k], dsa_results[k][0], dsa_results[k][1],
+			    1.0 / dsa_results[k][0], 1.0 / dsa_results[k][1]);
+	}
+	j = 1;
+	for (k = 0; k < EC_NUM; k++) {
+		if (!ecdsa_doit[k])
+			continue;
+		if (j && !mr) {
+			printf("%30ssign    verify    sign/s verify/s\n", " ");
+			j = 0;
+		}
+		if (mr)
+			fprintf(stdout, "+F4:%u:%u:%f:%f\n",
+			    k, test_curves_bits[k],
+			    ecdsa_results[k][0], ecdsa_results[k][1]);
+		else
+			fprintf(stdout,
+			    "%4u bit ecdsa (%s) %8.4fs %8.4fs %8.1f %8.1f\n",
+			    test_curves_bits[k],
+			    test_curves_names[k],
+			    ecdsa_results[k][0], ecdsa_results[k][1],
+			    1.0 / ecdsa_results[k][0], 1.0 / ecdsa_results[k][1]);
+	}
+
+
+	j = 1;
+	for (k = 0; k < EC_NUM; k++) {
+		if (!ecdh_doit[k])
+			continue;
+		if (j && !mr) {
+			printf("%30sop      op/s\n", " ");
+			j = 0;
+		}
+		if (mr)
+			fprintf(stdout, "+F5:%u:%u:%f:%f\n",
+			    k, test_curves_bits[k],
+			    ecdh_results[k][0], 1.0 / ecdh_results[k][0]);
+
+		else
+			fprintf(stdout, "%4u bit ecdh (%s) %8.4fs %8.1f\n",
+			    test_curves_bits[k],
+			    test_curves_names[k],
+			    ecdh_results[k][0], 1.0 / ecdh_results[k][0]);
+	}
+
+	mret = 0;
+
+end:
+	ERR_print_errors(bio_err);
+	free(buf);
+	free(buf2);
+	for (i = 0; i < RSA_NUM; i++)
+		if (rsa_key[i] != NULL)
+			RSA_free(rsa_key[i]);
+	for (i = 0; i < DSA_NUM; i++)
+		if (dsa_key[i] != NULL)
+			DSA_free(dsa_key[i]);
+
+	for (i = 0; i < EC_NUM; i++)
+		if (ecdsa[i] != NULL)
+			EC_KEY_free(ecdsa[i]);
+	for (i = 0; i < EC_NUM; i++) {
+		if (ecdh_a[i] != NULL)
+			EC_KEY_free(ecdh_a[i]);
+		if (ecdh_b[i] != NULL)
+			EC_KEY_free(ecdh_b[i]);
+	}
+
+
+	return (mret);
+}
+
+static void
+print_message(const char *s, long num, int length)
+{
+	BIO_printf(bio_err, mr ? "+DT:%s:%d:%d\n"
+	    : "Doing %s for %ds on %d size blocks: ", s, SECONDS, length);
+	(void) BIO_flush(bio_err);
+	alarm(SECONDS);
+}
+
+static void
+pkey_print_message(const char *str, const char *str2, long num,
+    int bits, int tm)
+{
+	BIO_printf(bio_err, mr ? "+DTP:%d:%s:%s:%d\n"
+	    : "Doing %d bit %s %s's for %ds: ", bits, str, str2, tm);
+	(void) BIO_flush(bio_err);
+	alarm(tm);
+}
+
+static void
+print_result(int alg, int run_no, int count, double time_used)
+{
+	BIO_printf(bio_err, mr ? "+R:%d:%s:%f\n"
+	    : "%d %s's in %.2fs\n", count, names[alg], time_used);
+	results[alg][run_no] = ((double) count) / time_used * lengths[run_no];
+}
+
+static char *
+sstrsep(char **string, const char *delim)
+{
+	char isdelim[256];
+	char *token = *string;
+
+	if (**string == 0)
+		return NULL;
+
+	memset(isdelim, 0, sizeof isdelim);
+	isdelim[0] = 1;
+
+	while (*delim) {
+		isdelim[(unsigned char) (*delim)] = 1;
+		delim++;
+	}
+
+	while (!isdelim[(unsigned char) (**string)]) {
+		(*string)++;
+	}
+
+	if (**string) {
+		**string = 0;
+		(*string)++;
+	}
+	return token;
+}
+
+static int
+do_multi(int multi)
+{
+	int n;
+	int fd[2];
+	int *fds;
+	static char sep[] = ":";
+	const char *errstr = NULL;
+
+	fds = reallocarray(NULL, multi, sizeof *fds);
+	if (fds == NULL) {
+		fprintf(stderr, "reallocarray failure\n");
+		exit(1);
+	}
+	for (n = 0; n < multi; ++n) {
+		if (pipe(fd) == -1) {
+			fprintf(stderr, "pipe failure\n");
+			exit(1);
+		}
+		fflush(stdout);
+		fflush(stderr);
+		if (fork()) {
+			close(fd[1]);
+			fds[n] = fd[0];
+		} else {
+			close(fd[0]);
+			close(1);
+			if (dup(fd[1]) == -1) {
+				fprintf(stderr, "dup failed\n");
+				exit(1);
+			}
+			close(fd[1]);
+			mr = 1;
+			usertime = 0;
+			free(fds);
+			return 0;
+		}
+		printf("Forked child %d\n", n);
+	}
+
+	/* for now, assume the pipe is long enough to take all the output */
+	for (n = 0; n < multi; ++n) {
+		FILE *f;
+		char buf[1024];
+		char *p;
+
+		f = fdopen(fds[n], "r");
+		while (fgets(buf, sizeof buf, f)) {
+			p = strchr(buf, '\n');
+			if (p)
+				*p = '\0';
+			if (buf[0] != '+') {
+				fprintf(stderr, "Don't understand line '%s' from child %d\n",
+				    buf, n);
+				continue;
+			}
+			printf("Got: %s from %d\n", buf, n);
+			if (!strncmp(buf, "+F:", 3)) {
+				int alg;
+				int j;
+
+				p = buf + 3;
+				alg = strtonum(sstrsep(&p, sep),
+				    0, ALGOR_NUM - 1, &errstr);
+				sstrsep(&p, sep);
+				for (j = 0; j < SIZE_NUM; ++j)
+					results[alg][j] += atof(sstrsep(&p, sep));
+			} else if (!strncmp(buf, "+F2:", 4)) {
+				int k;
+				double d;
+
+				p = buf + 4;
+				k = strtonum(sstrsep(&p, sep),
+				    0, ALGOR_NUM - 1, &errstr);
+				sstrsep(&p, sep);
+
+				d = atof(sstrsep(&p, sep));
+				if (n)
+					rsa_results[k][0] = 1 / (1 / rsa_results[k][0] + 1 / d);
+				else
+					rsa_results[k][0] = d;
+
+				d = atof(sstrsep(&p, sep));
+				if (n)
+					rsa_results[k][1] = 1 / (1 / rsa_results[k][1] + 1 / d);
+				else
+					rsa_results[k][1] = d;
+			} else if (!strncmp(buf, "+F2:", 4)) {
+				int k;
+				double d;
+
+				p = buf + 4;
+				k = strtonum(sstrsep(&p, sep),
+				    0, ALGOR_NUM - 1, &errstr);
+				sstrsep(&p, sep);
+
+				d = atof(sstrsep(&p, sep));
+				if (n)
+					rsa_results[k][0] = 1 / (1 / rsa_results[k][0] + 1 / d);
+				else
+					rsa_results[k][0] = d;
+
+				d = atof(sstrsep(&p, sep));
+				if (n)
+					rsa_results[k][1] = 1 / (1 / rsa_results[k][1] + 1 / d);
+				else
+					rsa_results[k][1] = d;
+			}
+			else if (!strncmp(buf, "+F3:", 4)) {
+				int k;
+				double d;
+
+				p = buf + 4;
+				k = strtonum(sstrsep(&p, sep),
+				    0, ALGOR_NUM - 1, &errstr);
+				sstrsep(&p, sep);
+
+				d = atof(sstrsep(&p, sep));
+				if (n)
+					dsa_results[k][0] = 1 / (1 / dsa_results[k][0] + 1 / d);
+				else
+					dsa_results[k][0] = d;
+
+				d = atof(sstrsep(&p, sep));
+				if (n)
+					dsa_results[k][1] = 1 / (1 / dsa_results[k][1] + 1 / d);
+				else
+					dsa_results[k][1] = d;
+			}
+			else if (!strncmp(buf, "+F4:", 4)) {
+				int k;
+				double d;
+
+				p = buf + 4;
+				k = strtonum(sstrsep(&p, sep),
+				    0, ALGOR_NUM - 1, &errstr);
+				sstrsep(&p, sep);
+
+				d = atof(sstrsep(&p, sep));
+				if (n)
+					ecdsa_results[k][0] = 1 / (1 / ecdsa_results[k][0] + 1 / d);
+				else
+					ecdsa_results[k][0] = d;
+
+				d = atof(sstrsep(&p, sep));
+				if (n)
+					ecdsa_results[k][1] = 1 / (1 / ecdsa_results[k][1] + 1 / d);
+				else
+					ecdsa_results[k][1] = d;
+			}
+
+			else if (!strncmp(buf, "+F5:", 4)) {
+				int k;
+				double d;
+
+				p = buf + 4;
+				k = strtonum(sstrsep(&p, sep),
+				    0, ALGOR_NUM - 1, &errstr);
+				sstrsep(&p, sep);
+
+				d = atof(sstrsep(&p, sep));
+				if (n)
+					ecdh_results[k][0] = 1 / (1 / ecdh_results[k][0] + 1 / d);
+				else
+					ecdh_results[k][0] = d;
+
+			}
+
+			else if (!strncmp(buf, "+H:", 3)) {
+			} else
+				fprintf(stderr, "Unknown type '%s' from child %d\n", buf, n);
+		}
+
+		fclose(f);
+	}
+	free(fds);
+	return 1;
+}
+#endif
diff --git a/bin/openssl/spkac.c b/bin/openssl/spkac.c
new file mode 100644
index 0000000000..77f3e3479c
--- /dev/null
+++ b/bin/openssl/spkac.c
@@ -0,0 +1,313 @@
+/* $OpenBSD: spkac.c,v 1.9 2017/01/20 08:57:12 deraadt Exp $ */
+/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
+ * project 1999. Based on an original idea by Massimiliano Pala
+ * (madwolf@openca.org).
+ */
+/* ====================================================================
+ * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include 
+#include 
+#include 
+#include 
+
+#include "apps.h"
+#include "progs.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+static struct {
+	char *challenge;
+	char *infile;
+	char *keyfile;
+	int noout;
+	char *outfile;
+	char *passargin;
+	int pubkey;
+	char *spkac;
+	char *spksect;
+	int verify;
+} spkac_config;
+
+static struct option spkac_options[] = {
+	{
+		.name = "challenge",
+		.argname = "string",
+		.desc = "Specify challenge string if SPKAC is generated",
+		.type = OPTION_ARG,
+		.opt.arg = &spkac_config.challenge,
+	},
+	{
+		.name = "in",
+		.argname = "file",
+		.desc = "Input file (default stdin)",
+		.type = OPTION_ARG,
+		.opt.arg = &spkac_config.infile,
+	},
+	{
+		.name = "key",
+		.argname = "file",
+		.desc = "Create SPKAC using private key file",
+		.type = OPTION_ARG,
+		.opt.arg = &spkac_config.keyfile,
+	},
+	{
+		.name = "noout",
+		.desc = "Do not print text version of SPKAC",
+		.type = OPTION_FLAG,
+		.opt.flag = &spkac_config.noout,
+	},
+	{
+		.name = "out",
+		.argname = "file",
+		.desc = "Output file (default stdout)",
+		.type = OPTION_ARG,
+		.opt.arg = &spkac_config.outfile,
+	},
+	{
+		.name = "passin",
+		.argname = "src",
+		.desc = "Input file passphrase source",
+		.type = OPTION_ARG,
+		.opt.arg = &spkac_config.passargin,
+	},
+	{
+		.name = "pubkey",
+		.desc = "Output public key of an SPKAC (not used if creating)",
+		.type = OPTION_FLAG,
+		.opt.flag = &spkac_config.pubkey,
+	},
+	{
+		.name = "spkac",
+		.argname = "name",
+		.desc = "SPKAC name (default \"SPKAC\")",
+		.type = OPTION_ARG,
+		.opt.arg = &spkac_config.spkac,
+	},
+	{
+		.name = "spksect",
+		.argname = "name",
+		.desc = "Name of the section containing SPKAC (default"
+		" \"default\")",
+		.type = OPTION_ARG,
+		.opt.arg = &spkac_config.spksect,
+	},
+	{
+		.name = "verify",
+		.desc = "Verify digital signature on supplied SPKAC",
+		.type = OPTION_FLAG,
+		.opt.flag = &spkac_config.verify,
+	},
+	{ NULL }
+};
+
+static void
+spkac_usage(void)
+{
+	fprintf(stderr,
+	    "usage: spkac [-challenge string] [-in file] "
+	    "[-key file] [-noout]\n"
+	    "    [-out file] [-passin src] [-pubkey] [-spkac name] "
+	    "[-spksect section]\n"
+	    "    [-verify]\n\n");
+	options_usage(spkac_options);
+}
+
+int
+spkac_main(int argc, char **argv)
+{
+	int i, ret = 1;
+	BIO *in = NULL, *out = NULL;
+	char *passin = NULL;
+	char *spkstr = NULL;
+	CONF *conf = NULL;
+	NETSCAPE_SPKI *spki = NULL;
+	EVP_PKEY *pkey = NULL;
+
+	if (single_execution) {
+		if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
+			perror("pledge");
+			exit(1);
+		}
+	}
+
+	memset(&spkac_config, 0, sizeof(spkac_config));
+	spkac_config.spkac = "SPKAC";
+	spkac_config.spksect = "default";
+
+	if (options_parse(argc, argv, spkac_options, NULL, NULL) != 0) {
+		spkac_usage();
+		return (1);
+	}
+
+	if (!app_passwd(bio_err, spkac_config.passargin, NULL, &passin, NULL)) {
+		BIO_printf(bio_err, "Error getting password\n");
+		goto end;
+	}
+
+	if (spkac_config.keyfile) {
+		pkey = load_key(bio_err,
+		    strcmp(spkac_config.keyfile, "-") ? spkac_config.keyfile
+		    : NULL, FORMAT_PEM, 1, passin, "private key");
+		if (!pkey) {
+			goto end;
+		}
+		spki = NETSCAPE_SPKI_new();
+		if (spkac_config.challenge)
+			ASN1_STRING_set(spki->spkac->challenge,
+			    spkac_config.challenge,
+			    (int) strlen(spkac_config.challenge));
+		NETSCAPE_SPKI_set_pubkey(spki, pkey);
+		NETSCAPE_SPKI_sign(spki, pkey, EVP_md5());
+		spkstr = NETSCAPE_SPKI_b64_encode(spki);
+		if (spkstr == NULL) {
+			BIO_printf(bio_err, "Error encoding SPKAC\n");
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+
+		if (spkac_config.outfile)
+			out = BIO_new_file(spkac_config.outfile, "w");
+		else
+			out = BIO_new_fp(stdout, BIO_NOCLOSE);
+
+		if (!out) {
+			BIO_printf(bio_err, "Error opening output file\n");
+			ERR_print_errors(bio_err);
+		} else {
+			BIO_printf(out, "SPKAC=%s\n", spkstr);
+			ret = 0;
+		}
+		free(spkstr);
+		goto end;
+	}
+	if (spkac_config.infile)
+		in = BIO_new_file(spkac_config.infile, "r");
+	else
+		in = BIO_new_fp(stdin, BIO_NOCLOSE);
+
+	if (!in) {
+		BIO_printf(bio_err, "Error opening input file\n");
+		ERR_print_errors(bio_err);
+		goto end;
+	}
+	conf = NCONF_new(NULL);
+	i = NCONF_load_bio(conf, in, NULL);
+
+	if (!i) {
+		BIO_printf(bio_err, "Error parsing config file\n");
+		ERR_print_errors(bio_err);
+		goto end;
+	}
+	spkstr = NCONF_get_string(conf, spkac_config.spksect,
+	    spkac_config.spkac);
+
+	if (!spkstr) {
+		BIO_printf(bio_err, "Can't find SPKAC called \"%s\"\n",
+		    spkac_config.spkac);
+		ERR_print_errors(bio_err);
+		goto end;
+	}
+	spki = NETSCAPE_SPKI_b64_decode(spkstr, -1);
+
+	if (!spki) {
+		BIO_printf(bio_err, "Error loading SPKAC\n");
+		ERR_print_errors(bio_err);
+		goto end;
+	}
+	if (spkac_config.outfile)
+		out = BIO_new_file(spkac_config.outfile, "w");
+	else {
+		out = BIO_new_fp(stdout, BIO_NOCLOSE);
+	}
+
+	if (!out) {
+		BIO_printf(bio_err, "Error opening output file\n");
+		ERR_print_errors(bio_err);
+		goto end;
+	}
+	if (!spkac_config.noout)
+		NETSCAPE_SPKI_print(out, spki);
+	pkey = NETSCAPE_SPKI_get_pubkey(spki);
+	if (spkac_config.verify) {
+		i = NETSCAPE_SPKI_verify(spki, pkey);
+		if (i > 0)
+			BIO_printf(bio_err, "Signature OK\n");
+		else {
+			BIO_printf(bio_err, "Signature Failure\n");
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+	}
+	if (spkac_config.pubkey)
+		PEM_write_bio_PUBKEY(out, pkey);
+
+	ret = 0;
+
+end:
+	NCONF_free(conf);
+	NETSCAPE_SPKI_free(spki);
+	BIO_free(in);
+	BIO_free_all(out);
+	EVP_PKEY_free(pkey);
+	free(passin);
+
+	return (ret);
+}
diff --git a/bin/openssl/testdsa.h b/bin/openssl/testdsa.h
new file mode 100644
index 0000000000..1bbb09ca70
--- /dev/null
+++ b/bin/openssl/testdsa.h
@@ -0,0 +1,221 @@
+/* $OpenBSD: testdsa.h,v 1.1 2014/08/26 17:47:25 jsing Exp $ */
+
+DSA *get_dsa512(void);
+DSA *get_dsa1024(void);
+DSA *get_dsa2048(void);
+
+static unsigned char dsa512_priv[] = {
+	0x65, 0xe5, 0xc7, 0x38, 0x60, 0x24, 0xb5, 0x89, 0xd4, 0x9c, 0xeb, 0x4c,
+	0x9c, 0x1d, 0x7a, 0x22, 0xbd, 0xd1, 0xc2, 0xd2,
+};
+static unsigned char dsa512_pub[] = {
+	0x00, 0x95, 0xa7, 0x0d, 0xec, 0x93, 0x68, 0xba, 0x5f, 0xf7, 0x5f, 0x07,
+	0xf2, 0x3b, 0xad, 0x6b, 0x01, 0xdc, 0xbe, 0xec, 0xde, 0x04, 0x7a, 0x3a,
+	0x27, 0xb3, 0xec, 0x49, 0xfd, 0x08, 0x43, 0x3d, 0x7e, 0xa8, 0x2c, 0x5e,
+	0x7b, 0xbb, 0xfc, 0xf4, 0x6e, 0xeb, 0x6c, 0xb0, 0x6e, 0xf8, 0x02, 0x12,
+	0x8c, 0x38, 0x5d, 0x83, 0x56, 0x7d, 0xee, 0x53, 0x05, 0x3e, 0x24, 0x84,
+	0xbe, 0xba, 0x0a, 0x6b, 0xc8,
+};
+static unsigned char dsa512_p[] = {
+	0x9D, 0x1B, 0x69, 0x8E, 0x26, 0xDB, 0xF2, 0x2B, 0x11, 0x70, 0x19, 0x86,
+	0xF6, 0x19, 0xC8, 0xF8, 0x19, 0xF2, 0x18, 0x53, 0x94, 0x46, 0x06, 0xD0,
+	0x62, 0x50, 0x33, 0x4B, 0x02, 0x3C, 0x52, 0x30, 0x03, 0x8B, 0x3B, 0xF9,
+	0x5F, 0xD1, 0x24, 0x06, 0x4F, 0x7B, 0x4C, 0xBA, 0xAA, 0x40, 0x9B, 0xFD,
+	0x96, 0xE4, 0x37, 0x33, 0xBB, 0x2D, 0x5A, 0xD7, 0x5A, 0x11, 0x40, 0x66,
+	0xA2, 0x76, 0x7D, 0x31,
+};
+static unsigned char dsa512_q[] = {
+	0xFB, 0x53, 0xEF, 0x50, 0xB4, 0x40, 0x92, 0x31, 0x56, 0x86, 0x53, 0x7A,
+	0xE8, 0x8B, 0x22, 0x9A, 0x49, 0xFB, 0x71, 0x8F,
+};
+static unsigned char dsa512_g[] = {
+	0x83, 0x3E, 0x88, 0xE5, 0xC5, 0x89, 0x73, 0xCE, 0x3B, 0x6C, 0x01, 0x49,
+	0xBF, 0xB3, 0xC7, 0x9F, 0x0A, 0xEA, 0x44, 0x91, 0xE5, 0x30, 0xAA, 0xD9,
+	0xBE, 0x5B, 0x5F, 0xB7, 0x10, 0xD7, 0x89, 0xB7, 0x8E, 0x74, 0xFB, 0xCF,
+	0x29, 0x1E, 0xEB, 0xA8, 0x2C, 0x54, 0x51, 0xB8, 0x10, 0xDE, 0xA0, 0xCE,
+	0x2F, 0xCC, 0x24, 0x6B, 0x90, 0x77, 0xDE, 0xA2, 0x68, 0xA6, 0x52, 0x12,
+	0xA2, 0x03, 0x9D, 0x20,
+};
+
+DSA *
+get_dsa512()
+{
+	DSA *dsa;
+
+	if ((dsa = DSA_new()) == NULL)
+		return (NULL);
+	dsa->priv_key = BN_bin2bn(dsa512_priv, sizeof(dsa512_priv), NULL);
+	dsa->pub_key = BN_bin2bn(dsa512_pub, sizeof(dsa512_pub), NULL);
+	dsa->p = BN_bin2bn(dsa512_p, sizeof(dsa512_p), NULL);
+	dsa->q = BN_bin2bn(dsa512_q, sizeof(dsa512_q), NULL);
+	dsa->g = BN_bin2bn(dsa512_g, sizeof(dsa512_g), NULL);
+	if ((dsa->priv_key == NULL) || (dsa->pub_key == NULL) ||
+	    (dsa->p == NULL) || (dsa->q == NULL) || (dsa->g == NULL))
+		return (NULL);
+	return (dsa);
+}
+
+static unsigned char dsa1024_priv[] = {
+	0x7d, 0x21, 0xda, 0xbb, 0x62, 0x15, 0x47, 0x36, 0x07, 0x67, 0x12, 0xe8,
+	0x8c, 0xaa, 0x1c, 0xcd, 0x38, 0x12, 0x61, 0x18,
+};
+static unsigned char dsa1024_pub[] = {
+	0x3c, 0x4e, 0x9c, 0x2a, 0x7f, 0x16, 0xc1, 0x25, 0xeb, 0xac, 0x78, 0x63,
+	0x90, 0x14, 0x8c, 0x8b, 0xf4, 0x68, 0x43, 0x3c, 0x2d, 0xee, 0x65, 0x50,
+	0x7d, 0x9c, 0x8f, 0x8c, 0x8a, 0x51, 0xd6, 0x11, 0x2b, 0x99, 0xaf, 0x1e,
+	0x90, 0x97, 0xb5, 0xd3, 0xa6, 0x20, 0x25, 0xd6, 0xfe, 0x43, 0x02, 0xd5,
+	0x91, 0x7d, 0xa7, 0x8c, 0xdb, 0xc9, 0x85, 0xa3, 0x36, 0x48, 0xf7, 0x68,
+	0xaa, 0x60, 0xb1, 0xf7, 0x05, 0x68, 0x3a, 0xa3, 0x3f, 0xd3, 0x19, 0x82,
+	0xd8, 0x82, 0x7a, 0x77, 0xfb, 0xef, 0xf4, 0x15, 0x0a, 0xeb, 0x06, 0x04,
+	0x7f, 0x53, 0x07, 0x0c, 0xbc, 0xcb, 0x2d, 0x83, 0xdb, 0x3e, 0xd1, 0x28,
+	0xa5, 0xa1, 0x31, 0xe0, 0x67, 0xfa, 0x50, 0xde, 0x9b, 0x07, 0x83, 0x7e,
+	0x2c, 0x0b, 0xc3, 0x13, 0x50, 0x61, 0xe5, 0xad, 0xbd, 0x36, 0xb8, 0x97,
+	0x4e, 0x40, 0x7d, 0xe8, 0x83, 0x0d, 0xbc, 0x4b
+};
+static unsigned char dsa1024_p[] = {
+	0xA7, 0x3F, 0x6E, 0x85, 0xBF, 0x41, 0x6A, 0x29, 0x7D, 0xF0, 0x9F, 0x47,
+	0x19, 0x30, 0x90, 0x9A, 0x09, 0x1D, 0xDA, 0x6A, 0x33, 0x1E, 0xC5, 0x3D,
+	0x86, 0x96, 0xB3, 0x15, 0xE0, 0x53, 0x2E, 0x8F, 0xE0, 0x59, 0x82, 0x73,
+	0x90, 0x3E, 0x75, 0x31, 0x99, 0x47, 0x7A, 0x52, 0xFB, 0x85, 0xE4, 0xD9,
+	0xA6, 0x7B, 0x38, 0x9B, 0x68, 0x8A, 0x84, 0x9B, 0x87, 0xC6, 0x1E, 0xB5,
+	0x7E, 0x86, 0x4B, 0x53, 0x5B, 0x59, 0xCF, 0x71, 0x65, 0x19, 0x88, 0x6E,
+	0xCE, 0x66, 0xAE, 0x6B, 0x88, 0x36, 0xFB, 0xEC, 0x28, 0xDC, 0xC2, 0xD7,
+	0xA5, 0xBB, 0xE5, 0x2C, 0x39, 0x26, 0x4B, 0xDA, 0x9A, 0x70, 0x18, 0x95,
+	0x37, 0x95, 0x10, 0x56, 0x23, 0xF6, 0x15, 0xED, 0xBA, 0x04, 0x5E, 0xDE,
+	0x39, 0x4F, 0xFD, 0xB7, 0x43, 0x1F, 0xB5, 0xA4, 0x65, 0x6F, 0xCD, 0x80,
+	0x11, 0xE4, 0x70, 0x95, 0x5B, 0x50, 0xCD, 0x49,
+};
+static unsigned char dsa1024_q[] = {
+	0xF7, 0x07, 0x31, 0xED, 0xFA, 0x6C, 0x06, 0x03, 0xD5, 0x85, 0x8A, 0x1C,
+	0xAC, 0x9C, 0x65, 0xE7, 0x50, 0x66, 0x65, 0x6F,
+};
+static unsigned char dsa1024_g[] = {
+	0x4D, 0xDF, 0x4C, 0x03, 0xA6, 0x91, 0x8A, 0xF5, 0x19, 0x6F, 0x50, 0x46,
+	0x25, 0x99, 0xE5, 0x68, 0x6F, 0x30, 0xE3, 0x69, 0xE1, 0xE5, 0xB3, 0x5D,
+	0x98, 0xBB, 0x28, 0x86, 0x48, 0xFC, 0xDE, 0x99, 0x04, 0x3F, 0x5F, 0x88,
+	0x0C, 0x9C, 0x73, 0x24, 0x0D, 0x20, 0x5D, 0xB9, 0x2A, 0x9A, 0x3F, 0x18,
+	0x96, 0x27, 0xE4, 0x62, 0x87, 0xC1, 0x7B, 0x74, 0x62, 0x53, 0xFC, 0x61,
+	0x27, 0xA8, 0x7A, 0x91, 0x09, 0x9D, 0xB6, 0xF1, 0x4D, 0x9C, 0x54, 0x0F,
+	0x58, 0x06, 0xEE, 0x49, 0x74, 0x07, 0xCE, 0x55, 0x7E, 0x23, 0xCE, 0x16,
+	0xF6, 0xCA, 0xDC, 0x5A, 0x61, 0x01, 0x7E, 0xC9, 0x71, 0xB5, 0x4D, 0xF6,
+	0xDC, 0x34, 0x29, 0x87, 0x68, 0xF6, 0x5E, 0x20, 0x93, 0xB3, 0xDB, 0xF5,
+	0xE4, 0x09, 0x6C, 0x41, 0x17, 0x95, 0x92, 0xEB, 0x01, 0xB5, 0x73, 0xA5,
+	0x6A, 0x7E, 0xD8, 0x32, 0xED, 0x0E, 0x02, 0xB8,
+};
+
+DSA *
+get_dsa1024()
+{
+	DSA *dsa;
+
+	if ((dsa = DSA_new()) == NULL)
+		return (NULL);
+	dsa->priv_key = BN_bin2bn(dsa1024_priv, sizeof(dsa1024_priv), NULL);
+	dsa->pub_key = BN_bin2bn(dsa1024_pub, sizeof(dsa1024_pub), NULL);
+	dsa->p = BN_bin2bn(dsa1024_p, sizeof(dsa1024_p), NULL);
+	dsa->q = BN_bin2bn(dsa1024_q, sizeof(dsa1024_q), NULL);
+	dsa->g = BN_bin2bn(dsa1024_g, sizeof(dsa1024_g), NULL);
+	if ((dsa->priv_key == NULL) || (dsa->pub_key == NULL) ||
+	    (dsa->p == NULL) || (dsa->q == NULL) || (dsa->g == NULL))
+		return (NULL);
+	return (dsa);
+}
+
+static unsigned char dsa2048_priv[] = {
+	0x32, 0x67, 0x92, 0xf6, 0xc4, 0xe2, 0xe2, 0xe8, 0xa0, 0x8b, 0x6b, 0x45,
+	0x0c, 0x8a, 0x76, 0xb0, 0xee, 0xcf, 0x91, 0xa7,
+};
+static unsigned char dsa2048_pub[] = {
+	0x17, 0x8f, 0xa8, 0x11, 0x84, 0x92, 0xec, 0x83, 0x47, 0xc7, 0x6a, 0xb0,
+	0x92, 0xaf, 0x5a, 0x20, 0x37, 0xa3, 0x64, 0x79, 0xd2, 0xd0, 0x3d, 0xcd,
+	0xe0, 0x61, 0x88, 0x88, 0x21, 0xcc, 0x74, 0x5d, 0xce, 0x4c, 0x51, 0x47,
+	0xf0, 0xc5, 0x5c, 0x4c, 0x82, 0x7a, 0xaf, 0x72, 0xad, 0xb9, 0xe0, 0x53,
+	0xf2, 0x78, 0xb7, 0xf0, 0xb5, 0x48, 0x7f, 0x8a, 0x3a, 0x18, 0xd1, 0x9f,
+	0x8b, 0x7d, 0xa5, 0x47, 0xb7, 0x95, 0xab, 0x98, 0xf8, 0x7b, 0x74, 0x50,
+	0x56, 0x8e, 0x57, 0xf0, 0xee, 0xf5, 0xb7, 0xba, 0xab, 0x85, 0x86, 0xf9,
+	0x2b, 0xef, 0x41, 0x56, 0xa0, 0xa4, 0x9f, 0xb7, 0x38, 0x00, 0x46, 0x0a,
+	0xa6, 0xf1, 0xfc, 0x1f, 0xd8, 0x4e, 0x85, 0x44, 0x92, 0x43, 0x21, 0x5d,
+	0x6e, 0xcc, 0xc2, 0xcb, 0x26, 0x31, 0x0d, 0x21, 0xc4, 0xbd, 0x8d, 0x24,
+	0xbc, 0xd9, 0x18, 0x19, 0xd7, 0xdc, 0xf1, 0xe7, 0x93, 0x50, 0x48, 0x03,
+	0x2c, 0xae, 0x2e, 0xe7, 0x49, 0x88, 0x5f, 0x93, 0x57, 0x27, 0x99, 0x36,
+	0xb4, 0x20, 0xab, 0xfc, 0xa7, 0x2b, 0xf2, 0xd9, 0x98, 0xd7, 0xd4, 0x34,
+	0x9d, 0x96, 0x50, 0x58, 0x9a, 0xea, 0x54, 0xf3, 0xee, 0xf5, 0x63, 0x14,
+	0xee, 0x85, 0x83, 0x74, 0x76, 0xe1, 0x52, 0x95, 0xc3, 0xf7, 0xeb, 0x04,
+	0x04, 0x7b, 0xa7, 0x28, 0x1b, 0xcc, 0xea, 0x4a, 0x4e, 0x84, 0xda, 0xd8,
+	0x9c, 0x79, 0xd8, 0x9b, 0x66, 0x89, 0x2f, 0xcf, 0xac, 0xd7, 0x79, 0xf9,
+	0xa9, 0xd8, 0x45, 0x13, 0x78, 0xb9, 0x00, 0x14, 0xc9, 0x7e, 0x22, 0x51,
+	0x86, 0x67, 0xb0, 0x9f, 0x26, 0x11, 0x23, 0xc8, 0x38, 0xd7, 0x70, 0x1d,
+	0x15, 0x8e, 0x4d, 0x4f, 0x95, 0x97, 0x40, 0xa1, 0xc2, 0x7e, 0x01, 0x18,
+	0x72, 0xf4, 0x10, 0xe6, 0x8d, 0x52, 0x16, 0x7f, 0xf2, 0xc9, 0xf8, 0x33,
+	0x8b, 0x33, 0xb7, 0xce,
+};
+static unsigned char dsa2048_p[] = {
+	0xA0, 0x25, 0xFA, 0xAD, 0xF4, 0x8E, 0xB9, 0xE5, 0x99, 0xF3, 0x5D, 0x6F,
+	0x4F, 0x83, 0x34, 0xE2, 0x7E, 0xCF, 0x6F, 0xBF, 0x30, 0xAF, 0x6F, 0x81,
+	0xEB, 0xF8, 0xC4, 0x13, 0xD9, 0xA0, 0x5D, 0x8B, 0x5C, 0x8E, 0xDC, 0xC2,
+	0x1D, 0x0B, 0x41, 0x32, 0xB0, 0x1F, 0xFE, 0xEF, 0x0C, 0xC2, 0xA2, 0x7E,
+	0x68, 0x5C, 0x28, 0x21, 0xE9, 0xF5, 0xB1, 0x58, 0x12, 0x63, 0x4C, 0x19,
+	0x4E, 0xFF, 0x02, 0x4B, 0x92, 0xED, 0xD2, 0x07, 0x11, 0x4D, 0x8C, 0x58,
+	0x16, 0x5C, 0x55, 0x8E, 0xAD, 0xA3, 0x67, 0x7D, 0xB9, 0x86, 0x6E, 0x0B,
+	0xE6, 0x54, 0x6F, 0x40, 0xAE, 0x0E, 0x67, 0x4C, 0xF9, 0x12, 0x5B, 0x3C,
+	0x08, 0x7A, 0xF7, 0xFC, 0x67, 0x86, 0x69, 0xE7, 0x0A, 0x94, 0x40, 0xBF,
+	0x8B, 0x76, 0xFE, 0x26, 0xD1, 0xF2, 0xA1, 0x1A, 0x84, 0xA1, 0x43, 0x56,
+	0x28, 0xBC, 0x9A, 0x5F, 0xD7, 0x3B, 0x69, 0x89, 0x8A, 0x36, 0x2C, 0x51,
+	0xDF, 0x12, 0x77, 0x2F, 0x57, 0x7B, 0xA0, 0xAA, 0xDD, 0x7F, 0xA1, 0x62,
+	0x3B, 0x40, 0x7B, 0x68, 0x1A, 0x8F, 0x0D, 0x38, 0xBB, 0x21, 0x5D, 0x18,
+	0xFC, 0x0F, 0x46, 0xF7, 0xA3, 0xB0, 0x1D, 0x23, 0xC3, 0xD2, 0xC7, 0x72,
+	0x51, 0x18, 0xDF, 0x46, 0x95, 0x79, 0xD9, 0xBD, 0xB5, 0x19, 0x02, 0x2C,
+	0x87, 0xDC, 0xE7, 0x57, 0x82, 0x7E, 0xF1, 0x8B, 0x06, 0x3D, 0x00, 0xA5,
+	0x7B, 0x6B, 0x26, 0x27, 0x91, 0x0F, 0x6A, 0x77, 0xE4, 0xD5, 0x04, 0xE4,
+	0x12, 0x2C, 0x42, 0xFF, 0xD2, 0x88, 0xBB, 0xD3, 0x92, 0xA0, 0xF9, 0xC8,
+	0x51, 0x64, 0x14, 0x5C, 0xD8, 0xF9, 0x6C, 0x47, 0x82, 0xB4, 0x1C, 0x7F,
+	0x09, 0xB8, 0xF0, 0x25, 0x83, 0x1D, 0x3F, 0x3F, 0x05, 0xB3, 0x21, 0x0A,
+	0x5D, 0xA7, 0xD8, 0x54, 0xC3, 0x65, 0x7D, 0xC3, 0xB0, 0x1D, 0xBF, 0xAE,
+	0xF8, 0x68, 0xCF, 0x9B,
+};
+static unsigned char dsa2048_q[] = {
+	0x97, 0xE7, 0x33, 0x4D, 0xD3, 0x94, 0x3E, 0x0B, 0xDB, 0x62, 0x74, 0xC6,
+	0xA1, 0x08, 0xDD, 0x19, 0xA3, 0x75, 0x17, 0x1B,
+};
+static unsigned char dsa2048_g[] = {
+	0x2C, 0x78, 0x16, 0x59, 0x34, 0x63, 0xF4, 0xF3, 0x92, 0xFC, 0xB5, 0xA5,
+	0x4F, 0x13, 0xDE, 0x2F, 0x1C, 0xA4, 0x3C, 0xAE, 0xAD, 0x38, 0x3F, 0x7E,
+	0x90, 0xBF, 0x96, 0xA6, 0xAE, 0x25, 0x90, 0x72, 0xF5, 0x8E, 0x80, 0x0C,
+	0x39, 0x1C, 0xD9, 0xEC, 0xBA, 0x90, 0x5B, 0x3A, 0xE8, 0x58, 0x6C, 0x9E,
+	0x30, 0x42, 0x37, 0x02, 0x31, 0x82, 0xBC, 0x6A, 0xDF, 0x6A, 0x09, 0x29,
+	0xE3, 0xC0, 0x46, 0xD1, 0xCB, 0x85, 0xEC, 0x0C, 0x30, 0x5E, 0xEA, 0xC8,
+	0x39, 0x8E, 0x22, 0x9F, 0x22, 0x10, 0xD2, 0x34, 0x61, 0x68, 0x37, 0x3D,
+	0x2E, 0x4A, 0x5B, 0x9A, 0xF5, 0xC1, 0x48, 0xC6, 0xF6, 0xDC, 0x63, 0x1A,
+	0xD3, 0x96, 0x64, 0xBA, 0x34, 0xC9, 0xD1, 0xA0, 0xD1, 0xAE, 0x6C, 0x2F,
+	0x48, 0x17, 0x93, 0x14, 0x43, 0xED, 0xF0, 0x21, 0x30, 0x19, 0xC3, 0x1B,
+	0x5F, 0xDE, 0xA3, 0xF0, 0x70, 0x78, 0x18, 0xE1, 0xA8, 0xE4, 0xEE, 0x2E,
+	0x00, 0xA5, 0xE4, 0xB3, 0x17, 0xC8, 0x0C, 0x7D, 0x6E, 0x42, 0xDC, 0xB7,
+	0x46, 0x00, 0x36, 0x4D, 0xD4, 0x46, 0xAA, 0x3D, 0x3C, 0x46, 0x89, 0x40,
+	0xBF, 0x1D, 0x84, 0x77, 0x0A, 0x75, 0xF3, 0x87, 0x1D, 0x08, 0x4C, 0xA6,
+	0xD1, 0xA9, 0x1C, 0x1E, 0x12, 0x1E, 0xE1, 0xC7, 0x30, 0x28, 0x76, 0xA5,
+	0x7F, 0x6C, 0x85, 0x96, 0x2B, 0x6F, 0xDB, 0x80, 0x66, 0x26, 0xAE, 0xF5,
+	0x93, 0xC7, 0x8E, 0xAE, 0x9A, 0xED, 0xE4, 0xCA, 0x04, 0xEA, 0x3B, 0x72,
+	0xEF, 0xDC, 0x87, 0xED, 0x0D, 0xA5, 0x4C, 0x4A, 0xDD, 0x71, 0x22, 0x64,
+	0x59, 0x69, 0x4E, 0x8E, 0xBF, 0x43, 0xDC, 0xAB, 0x8E, 0x66, 0xBB, 0x01,
+	0xB6, 0xF4, 0xE7, 0xFD, 0xD2, 0xAD, 0x9F, 0x36, 0xC1, 0xA0, 0x29, 0x99,
+	0xD1, 0x96, 0x70, 0x59, 0x06, 0x78, 0x35, 0xBD, 0x65, 0x55, 0x52, 0x9E,
+	0xF8, 0xB2, 0xE5, 0x38,
+};
+
+DSA *
+get_dsa2048()
+{
+	DSA *dsa;
+
+	if ((dsa = DSA_new()) == NULL)
+		return (NULL);
+	dsa->priv_key = BN_bin2bn(dsa2048_priv, sizeof(dsa2048_priv), NULL);
+	dsa->pub_key = BN_bin2bn(dsa2048_pub, sizeof(dsa2048_pub), NULL);
+	dsa->p = BN_bin2bn(dsa2048_p, sizeof(dsa2048_p), NULL);
+	dsa->q = BN_bin2bn(dsa2048_q, sizeof(dsa2048_q), NULL);
+	dsa->g = BN_bin2bn(dsa2048_g, sizeof(dsa2048_g), NULL);
+	if ((dsa->priv_key == NULL) || (dsa->pub_key == NULL) ||
+	    (dsa->p == NULL) || (dsa->q == NULL) || (dsa->g == NULL))
+		return (NULL);
+	return (dsa);
+}
diff --git a/bin/openssl/testrsa.h b/bin/openssl/testrsa.h
new file mode 100644
index 0000000000..789afa9621
--- /dev/null
+++ b/bin/openssl/testrsa.h
@@ -0,0 +1,517 @@
+/* $OpenBSD: testrsa.h,v 1.1 2014/08/26 17:47:25 jsing Exp $ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+static unsigned char test512[] = {
+	0x30, 0x82, 0x01, 0x3a, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00,
+	0xd6, 0x33, 0xb9, 0xc8, 0xfb, 0x4f, 0x3c, 0x7d, 0xc0, 0x01,
+	0x86, 0xd0, 0xe7, 0xa0, 0x55, 0xf2, 0x95, 0x93, 0xcc, 0x4f,
+	0xb7, 0x5b, 0x67, 0x5b, 0x94, 0x68, 0xc9, 0x34, 0x15, 0xde,
+	0xa5, 0x2e, 0x1c, 0x33, 0xc2, 0x6e, 0xfc, 0x34, 0x5e, 0x71,
+	0x13, 0xb7, 0xd6, 0xee, 0xd8, 0xa5, 0x65, 0x05, 0x72, 0x87,
+	0xa8, 0xb0, 0x77, 0xfe, 0x57, 0xf5, 0xfc, 0x5f, 0x55, 0x83,
+	0x87, 0xdd, 0x57, 0x49, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02,
+	0x41, 0x00, 0xa7, 0xf7, 0x91, 0xc5, 0x0f, 0x84, 0x57, 0xdc,
+	0x07, 0xf7, 0x6a, 0x7f, 0x60, 0x52, 0xb3, 0x72, 0xf1, 0x66,
+	0x1f, 0x7d, 0x97, 0x3b, 0x9e, 0xb6, 0x0a, 0x8f, 0x8c, 0xcf,
+	0x42, 0x23, 0x00, 0x04, 0xd4, 0x28, 0x0e, 0x1c, 0x90, 0xc4,
+	0x11, 0x25, 0x25, 0xa5, 0x93, 0xa5, 0x2f, 0x70, 0x02, 0xdf,
+	0x81, 0x9c, 0x49, 0x03, 0xa0, 0xf8, 0x6d, 0x54, 0x2e, 0x26,
+	0xde, 0xaa, 0x85, 0x59, 0xa8, 0x31, 0x02, 0x21, 0x00, 0xeb,
+	0x47, 0xd7, 0x3b, 0xf6, 0xc3, 0xdd, 0x5a, 0x46, 0xc5, 0xb9,
+	0x2b, 0x9a, 0xa0, 0x09, 0x8f, 0xa6, 0xfb, 0xf3, 0x78, 0x7a,
+	0x33, 0x70, 0x9d, 0x0f, 0x42, 0x6b, 0x13, 0x68, 0x24, 0xd3,
+	0x15, 0x02, 0x21, 0x00, 0xe9, 0x10, 0xb0, 0xb3, 0x0d, 0xe2,
+	0x82, 0x68, 0x77, 0x8a, 0x6e, 0x7c, 0xda, 0xbc, 0x3e, 0x53,
+	0x83, 0xfb, 0xd6, 0x22, 0xe7, 0xb5, 0xae, 0x6e, 0x80, 0xda,
+	0x00, 0x55, 0x97, 0xc1, 0xd0, 0x65, 0x02, 0x20, 0x4c, 0xf8,
+	0x73, 0xb1, 0x6a, 0x49, 0x29, 0x61, 0x1f, 0x46, 0x10, 0x0d,
+	0xf3, 0xc7, 0xe7, 0x58, 0xd7, 0x88, 0x15, 0x5e, 0x94, 0x9b,
+	0xbf, 0x7b, 0xa2, 0x42, 0x58, 0x45, 0x41, 0x0c, 0xcb, 0x01,
+	0x02, 0x20, 0x12, 0x11, 0xba, 0x31, 0x57, 0x9d, 0x3d, 0x11,
+	0x0e, 0x5b, 0x8c, 0x2f, 0x5f, 0xe2, 0x02, 0x4f, 0x05, 0x47,
+	0x8c, 0x15, 0x8e, 0xb3, 0x56, 0x3f, 0xb8, 0xfb, 0xad, 0xd4,
+	0xf4, 0xfc, 0x10, 0xc5, 0x02, 0x20, 0x18, 0xa1, 0x29, 0x99,
+	0x5b, 0xd9, 0xc8, 0xd4, 0xfc, 0x49, 0x7a, 0x2a, 0x21, 0x2c,
+	0x49, 0xe4, 0x4f, 0xeb, 0xef, 0x51, 0xf1, 0xab, 0x6d, 0xfb,
+	0x4b, 0x14, 0xe9, 0x4b, 0x52, 0xb5, 0x82, 0x2c,
+};
+
+static unsigned char test1024[] = {
+	0x30, 0x82, 0x02, 0x5c, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81,
+	0x00, 0xdc, 0x98, 0x43, 0xe8, 0x3d, 0x43, 0x5b, 0xe4, 0x05,
+	0xcd, 0xd0, 0xa9, 0x3e, 0xcb, 0x83, 0x75, 0xf6, 0xb5, 0xa5,
+	0x9f, 0x6b, 0xe9, 0x34, 0x41, 0x29, 0x18, 0xfa, 0x6a, 0x55,
+	0x4d, 0x70, 0xfc, 0xec, 0xae, 0x87, 0x38, 0x0a, 0x20, 0xa9,
+	0xc0, 0x45, 0x77, 0x6e, 0x57, 0x60, 0x57, 0xf4, 0xed, 0x96,
+	0x22, 0xcb, 0x8f, 0xe1, 0x33, 0x3a, 0x17, 0x1f, 0xed, 0x37,
+	0xa5, 0x6f, 0xeb, 0xa6, 0xbc, 0x12, 0x80, 0x1d, 0x53, 0xbd,
+	0x70, 0xeb, 0x21, 0x76, 0x3e, 0xc9, 0x2f, 0x1a, 0x45, 0x24,
+	0x82, 0xff, 0xcd, 0x59, 0x32, 0x06, 0x2e, 0x12, 0x3b, 0x23,
+	0x78, 0xed, 0x12, 0x3d, 0xe0, 0x8d, 0xf9, 0x67, 0x4f, 0x37,
+	0x4e, 0x47, 0x02, 0x4c, 0x2d, 0xc0, 0x4f, 0x1f, 0xb3, 0x94,
+	0xe1, 0x41, 0x2e, 0x2d, 0x90, 0x10, 0xfc, 0x82, 0x91, 0x8b,
+	0x0f, 0x22, 0xd4, 0xf2, 0xfc, 0x2c, 0xab, 0x53, 0x55, 0x02,
+	0x03, 0x01, 0x00, 0x01, 0x02, 0x81, 0x80, 0x2b, 0xcc, 0x3f,
+	0x8f, 0x58, 0xba, 0x8b, 0x00, 0x16, 0xf6, 0xea, 0x3a, 0xf0,
+	0x30, 0xd0, 0x05, 0x17, 0xda, 0xb0, 0xeb, 0x9a, 0x2d, 0x4f,
+	0x26, 0xb0, 0xd6, 0x38, 0xc1, 0xeb, 0xf5, 0xd8, 0x3d, 0x1f,
+	0x70, 0xf7, 0x7f, 0xf4, 0xe2, 0xcf, 0x51, 0x51, 0x79, 0x88,
+	0xfa, 0xe8, 0x32, 0x0e, 0x7b, 0x2d, 0x97, 0xf2, 0xfa, 0xba,
+	0x27, 0xc5, 0x9c, 0xd9, 0xc5, 0xeb, 0x8a, 0x79, 0x52, 0x3c,
+	0x64, 0x34, 0x7d, 0xc2, 0xcf, 0x28, 0xc7, 0x4e, 0xd5, 0x43,
+	0x0b, 0xd1, 0xa6, 0xca, 0x6d, 0x03, 0x2d, 0x72, 0x23, 0xbc,
+	0x6d, 0x05, 0xfa, 0x16, 0x09, 0x2f, 0x2e, 0x5c, 0xb6, 0xee,
+	0x74, 0xdd, 0xd2, 0x48, 0x8e, 0x36, 0x0c, 0x06, 0x3d, 0x4d,
+	0xe5, 0x10, 0x82, 0xeb, 0x6a, 0xf3, 0x4b, 0x9f, 0xd6, 0xed,
+	0x11, 0xb1, 0x6e, 0xec, 0xf4, 0xfe, 0x8e, 0x75, 0x94, 0x20,
+	0x2f, 0xcb, 0xac, 0x46, 0xf1, 0x02, 0x41, 0x00, 0xf9, 0x8c,
+	0xa3, 0x85, 0xb1, 0xdd, 0x29, 0xaf, 0x65, 0xc1, 0x33, 0xf3,
+	0x95, 0xc5, 0x52, 0x68, 0x0b, 0xd4, 0xf1, 0xe5, 0x0e, 0x02,
+	0x9f, 0x4f, 0xfa, 0x77, 0xdc, 0x46, 0x9e, 0xc7, 0xa6, 0xe4,
+	0x16, 0x29, 0xda, 0xb0, 0x07, 0xcf, 0x5b, 0xa9, 0x12, 0x8a,
+	0xdd, 0x63, 0x0a, 0xde, 0x2e, 0x8c, 0x66, 0x8b, 0x8c, 0xdc,
+	0x19, 0xa3, 0x7e, 0xf4, 0x3b, 0xd0, 0x1a, 0x8c, 0xa4, 0xc2,
+	0xe1, 0xd3, 0x02, 0x41, 0x00, 0xe2, 0x4c, 0x05, 0xf2, 0x04,
+	0x86, 0x4e, 0x61, 0x43, 0xdb, 0xb0, 0xb9, 0x96, 0x86, 0x52,
+	0x2c, 0xca, 0x8d, 0x7b, 0xab, 0x0b, 0x13, 0x0d, 0x7e, 0x38,
+	0x5b, 0xe2, 0x2e, 0x7b, 0x0e, 0xe7, 0x19, 0x99, 0x38, 0xe7,
+	0xf2, 0x21, 0xbd, 0x85, 0x85, 0xe3, 0xfd, 0x28, 0x77, 0x20,
+	0x31, 0x71, 0x2c, 0xd0, 0xff, 0xfb, 0x2e, 0xaf, 0x85, 0xb4,
+	0x86, 0xca, 0xf3, 0xbb, 0xca, 0xaa, 0x0f, 0x95, 0x37, 0x02,
+	0x40, 0x0e, 0x41, 0x9a, 0x95, 0xe8, 0xb3, 0x59, 0xce, 0x4b,
+	0x61, 0xde, 0x35, 0xec, 0x38, 0x79, 0x9c, 0xb8, 0x10, 0x52,
+	0x41, 0x63, 0xab, 0x82, 0xae, 0x6f, 0x00, 0xa9, 0xf4, 0xde,
+	0xdd, 0x49, 0x0b, 0x7e, 0xb8, 0xa5, 0x65, 0xa9, 0x0c, 0x8f,
+	0x8f, 0xf9, 0x1f, 0x35, 0xc6, 0x92, 0xb8, 0x5e, 0xb0, 0x66,
+	0xab, 0x52, 0x40, 0xc0, 0xb6, 0x36, 0x6a, 0x7d, 0x80, 0x46,
+	0x04, 0x02, 0xe5, 0x9f, 0x41, 0x02, 0x41, 0x00, 0xc0, 0xad,
+	0xcc, 0x4e, 0x21, 0xee, 0x1d, 0x24, 0x91, 0xfb, 0xa7, 0x80,
+	0x8d, 0x9a, 0xb6, 0xb3, 0x2e, 0x8f, 0xc2, 0xe1, 0x82, 0xdf,
+	0x69, 0x18, 0xb4, 0x71, 0xff, 0xa6, 0x65, 0xde, 0xed, 0x84,
+	0x8d, 0x42, 0xb7, 0xb3, 0x21, 0x69, 0x56, 0x1c, 0x07, 0x60,
+	0x51, 0x29, 0x04, 0xff, 0x34, 0x06, 0xdd, 0xb9, 0x67, 0x2c,
+	0x7c, 0x04, 0x93, 0x0e, 0x46, 0x15, 0xbb, 0x2a, 0xb7, 0x1b,
+	0xe7, 0x87, 0x02, 0x40, 0x78, 0xda, 0x5d, 0x07, 0x51, 0x0c,
+	0x16, 0x7a, 0x9f, 0x29, 0x20, 0x84, 0x0d, 0x42, 0xfa, 0xd7,
+	0x00, 0xd8, 0x77, 0x7e, 0xb0, 0xb0, 0x6b, 0xd6, 0x5b, 0x53,
+	0xb8, 0x9b, 0x7a, 0xcd, 0xc7, 0x2b, 0xb8, 0x6a, 0x63, 0xa9,
+	0xfb, 0x6f, 0xa4, 0x72, 0xbf, 0x4c, 0x5d, 0x00, 0x14, 0xba,
+	0xfa, 0x59, 0x88, 0xed, 0xe4, 0xe0, 0x8c, 0xa2, 0xec, 0x14,
+	0x7e, 0x2d, 0xe2, 0xf0, 0x46, 0x49, 0x95, 0x45,
+};
+
+static unsigned char test2048[] = {
+	0x30, 0x82, 0x04, 0xa3, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01,
+	0x01, 0x00, 0xc0, 0xc0, 0xce, 0x3e, 0x3c, 0x53, 0x67, 0x3f,
+	0x4f, 0xc5, 0x2f, 0xa4, 0xc2, 0x5a, 0x2f, 0x58, 0xfd, 0x27,
+	0x52, 0x6a, 0xe8, 0xcf, 0x4a, 0x73, 0x47, 0x8d, 0x25, 0x0f,
+	0x5f, 0x03, 0x26, 0x78, 0xef, 0xf0, 0x22, 0x12, 0xd3, 0xde,
+	0x47, 0xb2, 0x1c, 0x0b, 0x38, 0x63, 0x1a, 0x6c, 0x85, 0x7a,
+	0x80, 0xc6, 0x8f, 0xa0, 0x41, 0xaf, 0x62, 0xc4, 0x67, 0x32,
+	0x88, 0xf8, 0xa6, 0x9c, 0xf5, 0x23, 0x1d, 0xe4, 0xac, 0x3f,
+	0x29, 0xf9, 0xec, 0xe1, 0x8b, 0x26, 0x03, 0x2c, 0xb2, 0xab,
+	0xf3, 0x7d, 0xb5, 0xca, 0x49, 0xc0, 0x8f, 0x1c, 0xdf, 0x33,
+	0x3a, 0x60, 0xda, 0x3c, 0xb0, 0x16, 0xf8, 0xa9, 0x12, 0x8f,
+	0x64, 0xac, 0x23, 0x0c, 0x69, 0x64, 0x97, 0x5d, 0x99, 0xd4,
+	0x09, 0x83, 0x9b, 0x61, 0xd3, 0xac, 0xf0, 0xde, 0xdd, 0x5e,
+	0x9f, 0x44, 0x94, 0xdb, 0x3a, 0x4d, 0x97, 0xe8, 0x52, 0x29,
+	0xf7, 0xdb, 0x94, 0x07, 0x45, 0x90, 0x78, 0x1e, 0x31, 0x0b,
+	0x80, 0xf7, 0x57, 0xad, 0x1c, 0x79, 0xc5, 0xcb, 0x32, 0xb0,
+	0xce, 0xcd, 0x74, 0xb3, 0xe2, 0x94, 0xc5, 0x78, 0x2f, 0x34,
+	0x1a, 0x45, 0xf7, 0x8c, 0x52, 0xa5, 0xbc, 0x8d, 0xec, 0xd1,
+	0x2f, 0x31, 0x3b, 0xf0, 0x49, 0x59, 0x5e, 0x88, 0x9d, 0x15,
+	0x92, 0x35, 0x32, 0xc1, 0xe7, 0x61, 0xec, 0x50, 0x48, 0x7c,
+	0xba, 0x05, 0xf9, 0xf8, 0xf8, 0xa7, 0x8c, 0x83, 0xe8, 0x66,
+	0x5b, 0xeb, 0xfe, 0xd8, 0x4f, 0xdd, 0x6d, 0x36, 0xc0, 0xb2,
+	0x90, 0x0f, 0xb8, 0x52, 0xf9, 0x04, 0x9b, 0x40, 0x2c, 0x27,
+	0xd6, 0x36, 0x8e, 0xc2, 0x1b, 0x44, 0xf3, 0x92, 0xd5, 0x15,
+	0x9e, 0x9a, 0xbc, 0xf3, 0x7d, 0x03, 0xd7, 0x02, 0x14, 0x20,
+	0xe9, 0x10, 0x92, 0xfd, 0xf9, 0xfc, 0x8f, 0xe5, 0x18, 0xe1,
+	0x95, 0xcc, 0x9e, 0x60, 0xa6, 0xfa, 0x38, 0x4d, 0x02, 0x03,
+	0x01, 0x00, 0x01, 0x02, 0x82, 0x01, 0x00, 0x00, 0xc3, 0xc3,
+	0x0d, 0xb4, 0x27, 0x90, 0x8d, 0x4b, 0xbf, 0xb8, 0x84, 0xaa,
+	0xd0, 0xb8, 0xc7, 0x5d, 0x99, 0xbe, 0x55, 0xf6, 0x3e, 0x7c,
+	0x49, 0x20, 0xcb, 0x8a, 0x8e, 0x19, 0x0e, 0x66, 0x24, 0xac,
+	0xaf, 0x03, 0x33, 0x97, 0xeb, 0x95, 0xd5, 0x3b, 0x0f, 0x40,
+	0x56, 0x04, 0x50, 0xd1, 0xe6, 0xbe, 0x84, 0x0b, 0x25, 0xd3,
+	0x9c, 0xe2, 0x83, 0x6c, 0xf5, 0x62, 0x5d, 0xba, 0x2b, 0x7d,
+	0x3d, 0x7a, 0x6c, 0xe1, 0xd2, 0x0e, 0x54, 0x93, 0x80, 0x01,
+	0x91, 0x51, 0x09, 0xe8, 0x5b, 0x8e, 0x47, 0xbd, 0x64, 0xe4,
+	0x0e, 0x03, 0x83, 0x55, 0xcf, 0x5a, 0x37, 0xf0, 0x25, 0xb5,
+	0x7d, 0x21, 0xd7, 0x69, 0xdf, 0x6f, 0xc2, 0xcf, 0x10, 0xc9,
+	0x8a, 0x40, 0x9f, 0x7a, 0x70, 0xc0, 0xe8, 0xe8, 0xc0, 0xe6,
+	0x9a, 0x15, 0x0a, 0x8d, 0x4e, 0x46, 0xcb, 0x7a, 0xdb, 0xb3,
+	0xcb, 0x83, 0x02, 0xc4, 0xf0, 0xab, 0xeb, 0x02, 0x01, 0x0e,
+	0x23, 0xfc, 0x1d, 0xc4, 0xbd, 0xd4, 0xaa, 0x5d, 0x31, 0x46,
+	0x99, 0xce, 0x9e, 0xf8, 0x04, 0x75, 0x10, 0x67, 0xc4, 0x53,
+	0x47, 0x44, 0xfa, 0xc2, 0x25, 0x73, 0x7e, 0xd0, 0x8e, 0x59,
+	0xd1, 0xb2, 0x5a, 0xf4, 0xc7, 0x18, 0x92, 0x2f, 0x39, 0xab,
+	0xcd, 0xa3, 0xb5, 0xc2, 0xb9, 0xc7, 0xb9, 0x1b, 0x9f, 0x48,
+	0xfa, 0x13, 0xc6, 0x98, 0x4d, 0xca, 0x84, 0x9c, 0x06, 0xca,
+	0xe7, 0x89, 0x01, 0x04, 0xc4, 0x6c, 0xfd, 0x29, 0x59, 0x35,
+	0xe7, 0xf3, 0xdd, 0xce, 0x64, 0x59, 0xbf, 0x21, 0x13, 0xa9,
+	0x9f, 0x0e, 0xc5, 0xff, 0xbd, 0x33, 0x00, 0xec, 0xac, 0x6b,
+	0x11, 0xef, 0x51, 0x5e, 0xad, 0x07, 0x15, 0xde, 0xb8, 0x5f,
+	0xc6, 0xb9, 0xa3, 0x22, 0x65, 0x46, 0x83, 0x14, 0xdf, 0xd0,
+	0xf1, 0x44, 0x8a, 0xe1, 0x9c, 0x23, 0x33, 0xb4, 0x97, 0x33,
+	0xe6, 0x6b, 0x81, 0x02, 0x81, 0x81, 0x00, 0xec, 0x12, 0xa7,
+	0x59, 0x74, 0x6a, 0xde, 0x3e, 0xad, 0xd8, 0x36, 0x80, 0x50,
+	0xa2, 0xd5, 0x21, 0x81, 0x07, 0xf1, 0xd0, 0x91, 0xf2, 0x6c,
+	0x12, 0x2f, 0x9d, 0x1a, 0x26, 0xf8, 0x30, 0x65, 0xdf, 0xe8,
+	0xc0, 0x9b, 0x6a, 0x30, 0x98, 0x82, 0x87, 0xec, 0xa2, 0x56,
+	0x87, 0x62, 0x6f, 0xe7, 0x9f, 0xf6, 0x56, 0xe6, 0x71, 0x8f,
+	0x49, 0x86, 0x93, 0x5a, 0x4d, 0x34, 0x58, 0xfe, 0xd9, 0x04,
+	0x13, 0xaf, 0x79, 0xb7, 0xad, 0x11, 0xd1, 0x30, 0x9a, 0x14,
+	0x06, 0xa0, 0xfa, 0xb7, 0x55, 0xdc, 0x6c, 0x5a, 0x4c, 0x2c,
+	0x59, 0x56, 0xf6, 0xe8, 0x9d, 0xaf, 0x0a, 0x78, 0x99, 0x06,
+	0x06, 0x9e, 0xe7, 0x9c, 0x51, 0x55, 0x43, 0xfc, 0x3b, 0x6c,
+	0x0b, 0xbf, 0x2d, 0x41, 0xa7, 0xaf, 0xb7, 0xe0, 0xe8, 0x28,
+	0x18, 0xb4, 0x13, 0xd1, 0xe6, 0x97, 0xd0, 0x9f, 0x6a, 0x80,
+	0xca, 0xdd, 0x1a, 0x7e, 0x15, 0x02, 0x81, 0x81, 0x00, 0xd1,
+	0x06, 0x0c, 0x1f, 0xe3, 0xd0, 0xab, 0xd6, 0xca, 0x7c, 0xbc,
+	0x7d, 0x13, 0x35, 0xce, 0x27, 0xcd, 0xd8, 0x49, 0x51, 0x63,
+	0x64, 0x0f, 0xca, 0x06, 0x12, 0xfc, 0x07, 0x3e, 0xaf, 0x61,
+	0x6d, 0xe2, 0x53, 0x39, 0x27, 0xae, 0xc3, 0x11, 0x9e, 0x94,
+	0x01, 0x4f, 0xe3, 0xf3, 0x67, 0xf9, 0x77, 0xf9, 0xe7, 0x95,
+	0x3a, 0x6f, 0xe2, 0x20, 0x73, 0x3e, 0xa4, 0x7a, 0x28, 0xd4,
+	0x61, 0x97, 0xf6, 0x17, 0xa0, 0x23, 0x10, 0x2b, 0xce, 0x84,
+	0x57, 0x7e, 0x25, 0x1f, 0xf4, 0xa8, 0x54, 0xd2, 0x65, 0x94,
+	0xcc, 0x95, 0x0a, 0xab, 0x30, 0xc1, 0x59, 0x1f, 0x61, 0x8e,
+	0xb9, 0x6b, 0xd7, 0x4e, 0xb9, 0x83, 0x43, 0x79, 0x85, 0x11,
+	0xbc, 0x0f, 0xae, 0x25, 0x20, 0x05, 0xbc, 0xd2, 0x48, 0xa1,
+	0x68, 0x09, 0x84, 0xf6, 0x12, 0x9a, 0x66, 0xb9, 0x2b, 0xbb,
+	0x76, 0x03, 0x17, 0x46, 0x4e, 0x97, 0x59, 0x02, 0x81, 0x80,
+	0x09, 0x4c, 0xfa, 0xd6, 0xe5, 0x65, 0x48, 0x78, 0x43, 0xb5,
+	0x1f, 0x00, 0x93, 0x2c, 0xb7, 0x24, 0xe8, 0xc6, 0x7d, 0x5a,
+	0x70, 0x45, 0x92, 0xc8, 0x6c, 0xa3, 0xcd, 0xe1, 0xf7, 0x29,
+	0x40, 0xfa, 0x3f, 0x5b, 0x47, 0x44, 0x39, 0xc1, 0xe8, 0x72,
+	0x9e, 0x7a, 0x0e, 0xda, 0xaa, 0xa0, 0x2a, 0x09, 0xfd, 0x54,
+	0x93, 0x23, 0xaa, 0x37, 0x85, 0x5b, 0xcc, 0xd4, 0xf9, 0xd8,
+	0xff, 0xc1, 0x61, 0x0d, 0xbd, 0x7e, 0x18, 0x24, 0x73, 0x6d,
+	0x40, 0x72, 0xf1, 0x93, 0x09, 0x48, 0x97, 0x6c, 0x84, 0x90,
+	0xa8, 0x46, 0x14, 0x01, 0x39, 0x11, 0xe5, 0x3c, 0x41, 0x27,
+	0x32, 0x75, 0x24, 0xed, 0xa1, 0xd9, 0x12, 0x29, 0x8a, 0x28,
+	0x71, 0x89, 0x8d, 0xca, 0x30, 0xb0, 0x01, 0xc4, 0x2f, 0x82,
+	0x19, 0x14, 0x4c, 0x70, 0x1c, 0xb8, 0x23, 0x2e, 0xe8, 0x90,
+	0x49, 0x97, 0x92, 0x97, 0x6b, 0x7a, 0x9d, 0xb9, 0x02, 0x81,
+	0x80, 0x0f, 0x0e, 0xa1, 0x76, 0xf6, 0xa1, 0x44, 0x8f, 0xaf,
+	0x7c, 0x76, 0xd3, 0x87, 0xbb, 0xbb, 0x83, 0x10, 0x88, 0x01,
+	0x18, 0x14, 0xd1, 0xd3, 0x75, 0x59, 0x24, 0xaa, 0xf5, 0x16,
+	0xa5, 0xe9, 0x9d, 0xd1, 0xcc, 0xee, 0xf4, 0x15, 0xd9, 0xc5,
+	0x7e, 0x27, 0xe9, 0x44, 0x49, 0x06, 0x72, 0xb9, 0xfc, 0xd3,
+	0x8a, 0xc4, 0x2c, 0x36, 0x7d, 0x12, 0x9b, 0x5a, 0xaa, 0xdc,
+	0x85, 0xee, 0x6e, 0xad, 0x54, 0xb3, 0xf4, 0xfc, 0x31, 0xa1,
+	0x06, 0x3a, 0x70, 0x57, 0x0c, 0xf3, 0x95, 0x5b, 0x3e, 0xe8,
+	0xfd, 0x1a, 0x4f, 0xf6, 0x78, 0x93, 0x46, 0x6a, 0xd7, 0x31,
+	0xb4, 0x84, 0x64, 0x85, 0x09, 0x38, 0x89, 0x92, 0x94, 0x1c,
+	0xbf, 0xe2, 0x3c, 0x2a, 0xe0, 0xff, 0x99, 0xa3, 0xf0, 0x2b,
+	0x31, 0xc2, 0x36, 0xcd, 0x60, 0xbf, 0x9d, 0x2d, 0x74, 0x32,
+	0xe8, 0x9c, 0x93, 0x6e, 0xbb, 0x91, 0x7b, 0xfd, 0xd9, 0x02,
+	0x81, 0x81, 0x00, 0xa2, 0x71, 0x25, 0x38, 0xeb, 0x2a, 0xe9,
+	0x37, 0xcd, 0xfe, 0x44, 0xce, 0x90, 0x3f, 0x52, 0x87, 0x84,
+	0x52, 0x1b, 0xae, 0x8d, 0x22, 0x94, 0xce, 0x38, 0xe6, 0x04,
+	0x88, 0x76, 0x85, 0x9a, 0xd3, 0x14, 0x09, 0xe5, 0x69, 0x9a,
+	0xff, 0x58, 0x92, 0x02, 0x6a, 0x7d, 0x7c, 0x1e, 0x2c, 0xfd,
+	0xa8, 0xca, 0x32, 0x14, 0x4f, 0x0d, 0x84, 0x0d, 0x37, 0x43,
+	0xbf, 0xe4, 0x5d, 0x12, 0xc8, 0x24, 0x91, 0x27, 0x8d, 0x46,
+	0xd9, 0x54, 0x53, 0xe7, 0x62, 0x71, 0xa8, 0x2b, 0x71, 0x41,
+	0x8d, 0x75, 0xf8, 0x3a, 0xa0, 0x61, 0x29, 0x46, 0xa6, 0xe5,
+	0x82, 0xfa, 0x3a, 0xd9, 0x08, 0xfa, 0xfc, 0x63, 0xfd, 0x6b,
+	0x30, 0xbc, 0xf4, 0x4e, 0x9e, 0x8c, 0x25, 0x0c, 0xb6, 0x55,
+	0xe7, 0x3c, 0xd4, 0x4e, 0x0b, 0xfd, 0x8b, 0xc3, 0x0e, 0x1d,
+	0x9c, 0x44, 0x57, 0x8f, 0x1f, 0x86, 0xf7, 0xd5, 0x1b, 0xe4,
+	0x95,
+};
+
+static unsigned char test4096[] = {
+	0x30, 0x82, 0x09, 0x29, 0x02, 0x01, 0x00, 0x02, 0x82, 0x02,
+	0x01, 0x00, 0xc0, 0x71, 0xac, 0x1a, 0x13, 0x88, 0x82, 0x43,
+	0x3b, 0x51, 0x57, 0x71, 0x8d, 0xb6, 0x2b, 0x82, 0x65, 0x21,
+	0x53, 0x5f, 0x28, 0x29, 0x4f, 0x8d, 0x7c, 0x8a, 0xb9, 0x44,
+	0xb3, 0x28, 0x41, 0x4f, 0xd3, 0xfa, 0x6a, 0xf8, 0xb9, 0x28,
+	0x50, 0x39, 0x67, 0x53, 0x2c, 0x3c, 0xd7, 0xcb, 0x96, 0x41,
+	0x40, 0x32, 0xbb, 0xeb, 0x70, 0xae, 0x1f, 0xb0, 0x65, 0xf7,
+	0x3a, 0xd9, 0x22, 0xfd, 0x10, 0xae, 0xbd, 0x02, 0xe2, 0xdd,
+	0xf3, 0xc2, 0x79, 0x3c, 0xc6, 0xfc, 0x75, 0xbb, 0xaf, 0x4e,
+	0x3a, 0x36, 0xc2, 0x4f, 0xea, 0x25, 0xdf, 0x13, 0x16, 0x4b,
+	0x20, 0xfe, 0x4b, 0x69, 0x16, 0xc4, 0x7f, 0x1a, 0x43, 0xa6,
+	0x17, 0x1b, 0xb9, 0x0a, 0xf3, 0x09, 0x86, 0x28, 0x89, 0xcf,
+	0x2c, 0xd0, 0xd4, 0x81, 0xaf, 0xc6, 0x6d, 0xe6, 0x21, 0x8d,
+	0xee, 0xef, 0xea, 0xdc, 0xb7, 0xc6, 0x3b, 0x63, 0x9f, 0x0e,
+	0xad, 0x89, 0x78, 0x23, 0x18, 0xbf, 0x70, 0x7e, 0x84, 0xe0,
+	0x37, 0xec, 0xdb, 0x8e, 0x9c, 0x3e, 0x6a, 0x19, 0xcc, 0x99,
+	0x72, 0xe6, 0xb5, 0x7d, 0x6d, 0xfa, 0xe5, 0xd3, 0xe4, 0x90,
+	0xb5, 0xb2, 0xb2, 0x12, 0x70, 0x4e, 0xca, 0xf8, 0x10, 0xf8,
+	0xa3, 0x14, 0xc2, 0x48, 0x19, 0xeb, 0x60, 0x99, 0xbb, 0x2a,
+	0x1f, 0xb1, 0x7a, 0xb1, 0x3d, 0x24, 0xfb, 0xa0, 0x29, 0xda,
+	0xbd, 0x1b, 0xd7, 0xa4, 0xbf, 0xef, 0x60, 0x2d, 0x22, 0xca,
+	0x65, 0x98, 0xf1, 0xc4, 0xe1, 0xc9, 0x02, 0x6b, 0x16, 0x28,
+	0x2f, 0xa1, 0xaa, 0x79, 0x00, 0xda, 0xdc, 0x7c, 0x43, 0xf7,
+	0x42, 0x3c, 0xa0, 0xef, 0x68, 0xf7, 0xdf, 0xb9, 0x69, 0xfb,
+	0x8e, 0x01, 0xed, 0x01, 0x42, 0xb5, 0x4e, 0x57, 0xa6, 0x26,
+	0xb8, 0xd0, 0x7b, 0x56, 0x6d, 0x03, 0xc6, 0x40, 0x8c, 0x8c,
+	0x2a, 0x55, 0xd7, 0x9c, 0x35, 0x00, 0x94, 0x93, 0xec, 0x03,
+	0xeb, 0x22, 0xef, 0x77, 0xbb, 0x79, 0x13, 0x3f, 0x15, 0xa1,
+	0x8f, 0xca, 0xdf, 0xfd, 0xd3, 0xb8, 0xe1, 0xd4, 0xcc, 0x09,
+	0x3f, 0x3c, 0x2c, 0xdb, 0xd1, 0x49, 0x7f, 0x38, 0x07, 0x83,
+	0x6d, 0xeb, 0x08, 0x66, 0xe9, 0x06, 0x44, 0x12, 0xac, 0x95,
+	0x22, 0x90, 0x23, 0x67, 0xd4, 0x08, 0xcc, 0xf4, 0xb7, 0xdc,
+	0xcc, 0x87, 0xd4, 0xac, 0x69, 0x35, 0x4c, 0xb5, 0x39, 0x36,
+	0xcd, 0xa4, 0xd2, 0x95, 0xca, 0x0d, 0xc5, 0xda, 0xc2, 0xc5,
+	0x22, 0x32, 0x28, 0x08, 0xe3, 0xd2, 0x8b, 0x38, 0x30, 0xdc,
+	0x8c, 0x75, 0x4f, 0x6a, 0xec, 0x7a, 0xac, 0x16, 0x3e, 0xa8,
+	0xd4, 0x6a, 0x45, 0xe1, 0xa8, 0x4f, 0x2e, 0x80, 0x34, 0xaa,
+	0x54, 0x1b, 0x02, 0x95, 0x7d, 0x8a, 0x6d, 0xcc, 0x79, 0xca,
+	0xf2, 0xa4, 0x2e, 0x8d, 0xfb, 0xfe, 0x15, 0x51, 0x10, 0x0e,
+	0x4d, 0x88, 0xb1, 0xc7, 0xf4, 0x79, 0xdb, 0xf0, 0xb4, 0x56,
+	0x44, 0x37, 0xca, 0x5a, 0xc1, 0x8c, 0x48, 0xac, 0xae, 0x48,
+	0x80, 0x83, 0x01, 0x3f, 0xde, 0xd9, 0xd3, 0x2c, 0x51, 0x46,
+	0xb1, 0x41, 0xb6, 0xc6, 0x91, 0x72, 0xf9, 0x83, 0x55, 0x1b,
+	0x8c, 0xba, 0xf3, 0x73, 0xe5, 0x2c, 0x74, 0x50, 0x3a, 0xbe,
+	0xc5, 0x2f, 0xa7, 0xb2, 0x6d, 0x8c, 0x9e, 0x13, 0x77, 0xa3,
+	0x13, 0xcd, 0x6d, 0x8c, 0x45, 0xe1, 0xfc, 0x0b, 0xb7, 0x69,
+	0xe9, 0x27, 0xbc, 0x65, 0xc3, 0xfa, 0x9b, 0xd0, 0xef, 0xfe,
+	0xe8, 0x1f, 0xb3, 0x5e, 0x34, 0xf4, 0x8c, 0xea, 0xfc, 0xd3,
+	0x81, 0xbf, 0x3d, 0x30, 0xb2, 0xb4, 0x01, 0xe8, 0x43, 0x0f,
+	0xba, 0x02, 0x23, 0x42, 0x76, 0x82, 0x31, 0x73, 0x91, 0xed,
+	0x07, 0x46, 0x61, 0x0d, 0x39, 0x83, 0x40, 0xce, 0x7a, 0xd4,
+	0xdb, 0x80, 0x2c, 0x1f, 0x0d, 0xd1, 0x34, 0xd4, 0x92, 0xe3,
+	0xd4, 0xf1, 0xc2, 0x01, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02,
+	0x82, 0x02, 0x01, 0x00, 0x97, 0x6c, 0xda, 0x6e, 0xea, 0x4f,
+	0xcf, 0xaf, 0xf7, 0x4c, 0xd9, 0xf1, 0x90, 0x00, 0x77, 0xdb,
+	0xf2, 0x97, 0x76, 0x72, 0xb9, 0xb7, 0x47, 0xd1, 0x9c, 0xdd,
+	0xcb, 0x4a, 0x33, 0x6e, 0xc9, 0x75, 0x76, 0xe6, 0xe4, 0xa5,
+	0x31, 0x8c, 0x77, 0x13, 0xb4, 0x29, 0xcd, 0xf5, 0x52, 0x17,
+	0xef, 0xf3, 0x08, 0x00, 0xe3, 0xbd, 0x2e, 0xbc, 0xd4, 0x52,
+	0x88, 0xe9, 0x30, 0x75, 0x0b, 0x02, 0xf5, 0xcd, 0x89, 0x0c,
+	0x6c, 0x57, 0x19, 0x27, 0x3d, 0x1e, 0x85, 0xb4, 0xc1, 0x2f,
+	0x1d, 0x92, 0x00, 0x5c, 0x76, 0x29, 0x4b, 0xa4, 0xe1, 0x12,
+	0xb3, 0xc8, 0x09, 0xfe, 0x0e, 0x78, 0x72, 0x61, 0xcb, 0x61,
+	0x6f, 0x39, 0x91, 0x95, 0x4e, 0xd5, 0x3e, 0xc7, 0x8f, 0xb8,
+	0xf6, 0x36, 0xfe, 0x9c, 0x93, 0x9a, 0x38, 0x25, 0x7a, 0xf4,
+	0x4a, 0x12, 0xd4, 0xa0, 0x13, 0xbd, 0xf9, 0x1d, 0x12, 0x3e,
+	0x21, 0x39, 0xfb, 0x72, 0xe0, 0x05, 0x3d, 0xc3, 0xe5, 0x50,
+	0xa8, 0x5d, 0x85, 0xa3, 0xea, 0x5f, 0x1c, 0xb2, 0x3f, 0xea,
+	0x6d, 0x03, 0x91, 0x55, 0xd8, 0x19, 0x0a, 0x21, 0x12, 0x16,
+	0xd9, 0x12, 0xc4, 0xe6, 0x07, 0x18, 0x5b, 0x26, 0xa4, 0xae,
+	0xed, 0x2b, 0xb7, 0xa6, 0xed, 0xf8, 0xad, 0xec, 0x77, 0xe6,
+	0x7f, 0x4f, 0x76, 0x00, 0xc0, 0xfa, 0x15, 0x92, 0xb4, 0x2c,
+	0x22, 0xc2, 0xeb, 0x6a, 0xad, 0x14, 0x05, 0xb2, 0xe5, 0x8a,
+	0x9e, 0x85, 0x83, 0xcc, 0x04, 0xf1, 0x56, 0x78, 0x44, 0x5e,
+	0xde, 0xe0, 0x60, 0x1a, 0x65, 0x79, 0x31, 0x23, 0x05, 0xbb,
+	0x01, 0xff, 0xdd, 0x2e, 0xb7, 0xb3, 0xaa, 0x74, 0xe0, 0xa5,
+	0x94, 0xaf, 0x4b, 0xde, 0x58, 0x0f, 0x55, 0xde, 0x33, 0xf6,
+	0xe3, 0xd6, 0x34, 0x36, 0x57, 0xd6, 0x79, 0x91, 0x2e, 0xbe,
+	0x3b, 0xd9, 0x4e, 0xb6, 0x9d, 0x21, 0x5c, 0xd3, 0x48, 0x14,
+	0x7f, 0x4a, 0xc4, 0x60, 0xa9, 0x29, 0xf8, 0x53, 0x7f, 0x88,
+	0x11, 0x2d, 0xb5, 0xc5, 0x2d, 0x6f, 0xee, 0x85, 0x0b, 0xf7,
+	0x8d, 0x9a, 0xbe, 0xb0, 0x42, 0xf2, 0x2e, 0x71, 0xaf, 0x19,
+	0x31, 0x6d, 0xec, 0xcd, 0x6f, 0x2b, 0x23, 0xdf, 0xb4, 0x40,
+	0xaf, 0x2c, 0x0a, 0xc3, 0x1b, 0x7d, 0x7d, 0x03, 0x1d, 0x4b,
+	0xf3, 0xb5, 0xe0, 0x85, 0xd8, 0xdf, 0x91, 0x6b, 0x0a, 0x69,
+	0xf7, 0xf2, 0x69, 0x66, 0x5b, 0xf1, 0xcf, 0x46, 0x7d, 0xe9,
+	0x70, 0xfa, 0x6d, 0x7e, 0x75, 0x4e, 0xa9, 0x77, 0xe6, 0x8c,
+	0x02, 0xf7, 0x14, 0x4d, 0xa5, 0x41, 0x8f, 0x3f, 0xc1, 0x62,
+	0x1e, 0x71, 0x5e, 0x38, 0xb4, 0xd6, 0xe6, 0xe1, 0x4b, 0xc2,
+	0x2c, 0x30, 0x83, 0x81, 0x6f, 0x49, 0x2e, 0x96, 0xe6, 0xc9,
+	0x9a, 0xf7, 0x5d, 0x09, 0xa0, 0x55, 0x02, 0xa5, 0x3a, 0x25,
+	0x23, 0xd0, 0x92, 0xc3, 0xa3, 0xe3, 0x0e, 0x12, 0x2f, 0x4d,
+	0xef, 0xf3, 0x55, 0x5a, 0xbe, 0xe6, 0x19, 0x86, 0x31, 0xab,
+	0x75, 0x9a, 0xd3, 0xf0, 0x2c, 0xc5, 0x41, 0x92, 0xd9, 0x1f,
+	0x5f, 0x11, 0x8c, 0x75, 0x1c, 0x63, 0xd0, 0x02, 0x80, 0x2c,
+	0x68, 0xcb, 0x93, 0xfb, 0x51, 0x73, 0x49, 0xb4, 0x60, 0xda,
+	0xe2, 0x26, 0xaf, 0xa9, 0x46, 0x12, 0xb8, 0xec, 0x50, 0xdd,
+	0x12, 0x06, 0x5f, 0xce, 0x59, 0xe6, 0xf6, 0x1c, 0xe0, 0x54,
+	0x10, 0xad, 0xf6, 0xcd, 0x98, 0xcc, 0x0f, 0xfb, 0xcb, 0x41,
+	0x14, 0x9d, 0xed, 0xe4, 0xb4, 0x74, 0x5f, 0x09, 0x60, 0xc7,
+	0x12, 0xf6, 0x7b, 0x3c, 0x8f, 0xa7, 0x20, 0xbc, 0xe4, 0xb1,
+	0xef, 0xeb, 0xa4, 0x93, 0xc5, 0x06, 0xca, 0x9a, 0x27, 0x9d,
+	0x87, 0xf3, 0xde, 0xca, 0xe5, 0xe7, 0xf6, 0x1c, 0x01, 0x65,
+	0x5b, 0xfb, 0x19, 0x79, 0x6e, 0x08, 0x26, 0xc5, 0xc8, 0x28,
+	0x0e, 0xb6, 0x3b, 0x07, 0x08, 0xc1, 0x02, 0x82, 0x01, 0x01,
+	0x00, 0xe8, 0x1c, 0x73, 0xa6, 0xb8, 0xe0, 0x0e, 0x6d, 0x8d,
+	0x1b, 0xb9, 0x53, 0xed, 0x58, 0x94, 0xe6, 0x1d, 0x60, 0x14,
+	0x5c, 0x76, 0x43, 0xc4, 0x58, 0x19, 0xc4, 0x24, 0xe8, 0xbc,
+	0x1b, 0x3b, 0x0b, 0x13, 0x24, 0x45, 0x54, 0x0e, 0xcc, 0x37,
+	0xf0, 0xe0, 0x63, 0x7d, 0xc3, 0xf7, 0xfb, 0x81, 0x74, 0x81,
+	0xc4, 0x0f, 0x1a, 0x21, 0x48, 0xaf, 0xce, 0xc1, 0xc4, 0x94,
+	0x18, 0x06, 0x44, 0x8d, 0xd3, 0xd2, 0x22, 0x2d, 0x2d, 0x3e,
+	0x5a, 0x31, 0xdc, 0x95, 0x8e, 0xf4, 0x41, 0xfc, 0x58, 0xc9,
+	0x40, 0x92, 0x17, 0x5f, 0xe3, 0xda, 0xac, 0x9e, 0x3f, 0x1c,
+	0x2a, 0x6b, 0x58, 0x5f, 0x48, 0x78, 0x20, 0xb1, 0xaf, 0x24,
+	0x9b, 0x3c, 0x20, 0x8b, 0x93, 0x25, 0x9e, 0xe6, 0x6b, 0xbc,
+	0x13, 0x42, 0x14, 0x6c, 0x36, 0x31, 0xff, 0x7a, 0xd1, 0xc1,
+	0x1a, 0x26, 0x14, 0x7f, 0xa9, 0x76, 0xa7, 0x0c, 0xf8, 0xcc,
+	0xed, 0x07, 0x6a, 0xd2, 0xdf, 0x62, 0xee, 0x0a, 0x7c, 0x84,
+	0xcb, 0x49, 0x90, 0xb2, 0x03, 0x0d, 0xa2, 0x82, 0x06, 0x77,
+	0xf1, 0xcd, 0x67, 0xf2, 0x47, 0x21, 0x02, 0x3f, 0x43, 0x21,
+	0xf0, 0x46, 0x30, 0x62, 0x51, 0x72, 0xb1, 0xe7, 0x48, 0xc6,
+	0x67, 0x12, 0xcd, 0x9e, 0xd6, 0x15, 0xe5, 0x21, 0xed, 0xfa,
+	0x8f, 0x30, 0xa6, 0x41, 0xfe, 0xb6, 0xfa, 0x8f, 0x34, 0x14,
+	0x19, 0xe8, 0x11, 0xf7, 0xa5, 0x77, 0x3e, 0xb7, 0xf9, 0x39,
+	0x07, 0x8c, 0x67, 0x2a, 0xab, 0x7b, 0x08, 0xf8, 0xb0, 0x06,
+	0xa8, 0xea, 0x2f, 0x8f, 0xfa, 0xcc, 0xcc, 0x40, 0xce, 0xf3,
+	0x70, 0x4f, 0x3f, 0x7f, 0xe2, 0x0c, 0xea, 0x76, 0x4a, 0x35,
+	0x4e, 0x47, 0xad, 0x2b, 0xa7, 0x97, 0x5d, 0x74, 0x43, 0x97,
+	0x90, 0xd2, 0xfb, 0xd9, 0xf9, 0x96, 0x01, 0x33, 0x05, 0xed,
+	0x7b, 0x03, 0x05, 0xad, 0xf8, 0x49, 0x03, 0x02, 0x82, 0x01,
+	0x01, 0x00, 0xd4, 0x40, 0x17, 0x66, 0x10, 0x92, 0x95, 0xc8,
+	0xec, 0x62, 0xa9, 0x7a, 0xcb, 0x93, 0x8e, 0xe6, 0x53, 0xd4,
+	0x80, 0x48, 0x27, 0x4b, 0x41, 0xce, 0x61, 0xdf, 0xbf, 0x94,
+	0xa4, 0x3d, 0x71, 0x03, 0x0b, 0xed, 0x25, 0x71, 0x98, 0xa4,
+	0xd6, 0xd5, 0x4a, 0x57, 0xf5, 0x6c, 0x1b, 0xda, 0x21, 0x7d,
+	0x35, 0x45, 0xb3, 0xf3, 0x6a, 0xd9, 0xd3, 0x43, 0xe8, 0x5c,
+	0x54, 0x1c, 0x83, 0x1b, 0xb4, 0x5f, 0xf2, 0x97, 0x24, 0x2e,
+	0xdc, 0x40, 0xde, 0x92, 0x23, 0x59, 0x8e, 0xbc, 0xd2, 0xa1,
+	0xf2, 0xe0, 0x4c, 0xdd, 0x0b, 0xd1, 0xe7, 0xae, 0x65, 0xbc,
+	0xb5, 0xf5, 0x5b, 0x98, 0xe9, 0xd7, 0xc2, 0xb7, 0x0e, 0x55,
+	0x71, 0x0e, 0x3c, 0x0a, 0x24, 0x6b, 0xa6, 0xe6, 0x14, 0x61,
+	0x11, 0xfd, 0x33, 0x42, 0x99, 0x2b, 0x84, 0x77, 0x74, 0x92,
+	0x91, 0xf5, 0x79, 0x79, 0xcf, 0xad, 0x8e, 0x04, 0xef, 0x80,
+	0x1e, 0x57, 0xf4, 0x14, 0xf5, 0x35, 0x09, 0x74, 0xb2, 0x13,
+	0x71, 0x58, 0x6b, 0xea, 0x32, 0x5d, 0xf3, 0xd3, 0x76, 0x48,
+	0x39, 0x10, 0x23, 0x84, 0x9d, 0xbe, 0x92, 0x77, 0x4a, 0xed,
+	0x70, 0x3e, 0x1a, 0xa2, 0x6c, 0xb3, 0x81, 0x00, 0xc3, 0xc9,
+	0xe4, 0x52, 0xc8, 0x24, 0x88, 0x0c, 0x41, 0xad, 0x87, 0x5a,
+	0xea, 0xa3, 0x7a, 0x85, 0x1c, 0x5e, 0x31, 0x7f, 0xc3, 0x35,
+	0xc6, 0xfa, 0x10, 0xc8, 0x75, 0x10, 0xc4, 0x96, 0x99, 0xe7,
+	0xfe, 0x01, 0xb4, 0x74, 0xdb, 0xb4, 0x11, 0xc3, 0xc8, 0x8c,
+	0xf6, 0xf7, 0x3b, 0x66, 0x50, 0xfc, 0xdb, 0xeb, 0xca, 0x47,
+	0x85, 0x89, 0xe1, 0x65, 0xd9, 0x62, 0x34, 0x3c, 0x70, 0xd8,
+	0x2e, 0xb4, 0x2f, 0x65, 0x3c, 0x4a, 0xa6, 0x2a, 0xe7, 0xc7,
+	0xd8, 0x41, 0x8f, 0x8a, 0x43, 0xbf, 0x42, 0xf2, 0x4d, 0xbc,
+	0xfc, 0x9e, 0x27, 0x95, 0xfb, 0x75, 0xff, 0xab, 0x02, 0x82,
+	0x01, 0x00, 0x41, 0x2f, 0x44, 0x57, 0x6d, 0x12, 0x17, 0x5b,
+	0x32, 0xc6, 0xb7, 0x6c, 0x57, 0x7a, 0x8a, 0x0e, 0x79, 0xef,
+	0x72, 0xa8, 0x68, 0xda, 0x2d, 0x38, 0xe4, 0xbb, 0x8d, 0xf6,
+	0x02, 0x65, 0xcf, 0x56, 0x13, 0xe1, 0x1a, 0xcb, 0x39, 0x80,
+	0xa6, 0xb1, 0x32, 0x03, 0x1e, 0xdd, 0xbb, 0x35, 0xd9, 0xac,
+	0x43, 0x89, 0x31, 0x08, 0x90, 0x92, 0x5e, 0x35, 0x3d, 0x7b,
+	0x9c, 0x6f, 0x86, 0xcb, 0x17, 0xdd, 0x85, 0xe4, 0xed, 0x35,
+	0x08, 0x8e, 0xc1, 0xf4, 0x05, 0xd8, 0x68, 0xc6, 0x63, 0x3c,
+	0xf7, 0xff, 0xf7, 0x47, 0x33, 0x39, 0xc5, 0x3e, 0xb7, 0x0e,
+	0x58, 0x35, 0x9d, 0x81, 0xea, 0xf8, 0x6a, 0x2c, 0x1c, 0x5a,
+	0x68, 0x78, 0x64, 0x11, 0x6b, 0xc1, 0x3e, 0x4e, 0x7a, 0xbd,
+	0x84, 0xcb, 0x0f, 0xc2, 0xb6, 0x85, 0x1d, 0xd3, 0x76, 0xc5,
+	0x93, 0x6a, 0x69, 0x89, 0x56, 0x34, 0xdc, 0x4a, 0x9b, 0xbc,
+	0xff, 0xa8, 0x0d, 0x6e, 0x35, 0x9c, 0x60, 0xa7, 0x23, 0x30,
+	0xc7, 0x06, 0x64, 0x39, 0x8b, 0x94, 0x89, 0xee, 0xba, 0x7f,
+	0x60, 0x8d, 0xfa, 0xb6, 0x97, 0x76, 0xdc, 0x51, 0x4a, 0x3c,
+	0xeb, 0x3a, 0x14, 0x2c, 0x20, 0x60, 0x69, 0x4a, 0x86, 0xfe,
+	0x8c, 0x21, 0x84, 0x49, 0x54, 0xb3, 0x20, 0xe1, 0x01, 0x7f,
+	0x58, 0xdf, 0x7f, 0xb5, 0x21, 0x51, 0x8c, 0x47, 0x9f, 0x91,
+	0xeb, 0x97, 0x3e, 0xf2, 0x54, 0xcf, 0x16, 0x46, 0xf9, 0xd9,
+	0xb6, 0xe7, 0x64, 0xc9, 0xd0, 0x54, 0xea, 0x2f, 0xa1, 0xcf,
+	0xa5, 0x7f, 0x28, 0x8d, 0x84, 0xec, 0xd5, 0x39, 0x03, 0x76,
+	0x5b, 0x2d, 0x8e, 0x43, 0xf2, 0x01, 0x24, 0xc9, 0x6f, 0xc0,
+	0xf5, 0x69, 0x6f, 0x7d, 0xb5, 0x85, 0xd2, 0x5f, 0x7f, 0x78,
+	0x40, 0x07, 0x7f, 0x09, 0x15, 0xb5, 0x1f, 0x28, 0x65, 0x10,
+	0xe4, 0x19, 0xa8, 0xc6, 0x9e, 0x8d, 0xdc, 0xcb, 0x02, 0x82,
+	0x01, 0x00, 0x13, 0x01, 0xee, 0x56, 0x80, 0x93, 0x70, 0x00,
+	0x7f, 0x52, 0xd2, 0x94, 0xa1, 0x98, 0x84, 0x4a, 0x92, 0x25,
+	0x4c, 0x9b, 0xa9, 0x91, 0x2e, 0xc2, 0x79, 0xb7, 0x5c, 0xe3,
+	0xc5, 0xd5, 0x8e, 0xc2, 0x54, 0x16, 0x17, 0xad, 0x55, 0x9b,
+	0x25, 0x76, 0x12, 0x63, 0x50, 0x22, 0x2f, 0x58, 0x58, 0x79,
+	0x6b, 0x04, 0xe3, 0xf9, 0x9f, 0x8f, 0x04, 0x41, 0x67, 0x94,
+	0xa5, 0x1f, 0xac, 0x8a, 0x15, 0x9c, 0x26, 0x10, 0x6c, 0xf8,
+	0x19, 0x57, 0x61, 0xd7, 0x3a, 0x7d, 0x31, 0xb0, 0x2d, 0x38,
+	0xbd, 0x94, 0x62, 0xad, 0xc4, 0xfa, 0x36, 0x42, 0x42, 0xf0,
+	0x24, 0x67, 0x65, 0x9d, 0x8b, 0x0b, 0x7c, 0x6f, 0x82, 0x44,
+	0x1a, 0x8c, 0xc8, 0xc9, 0xab, 0xbb, 0x4c, 0x45, 0xfc, 0x7b,
+	0x38, 0xee, 0x30, 0xe1, 0xfc, 0xef, 0x8d, 0xbc, 0x58, 0xdf,
+	0x2b, 0x5d, 0x0d, 0x54, 0xe0, 0x49, 0x4d, 0x97, 0x99, 0x8f,
+	0x22, 0xa8, 0x83, 0xbe, 0x40, 0xbb, 0x50, 0x2e, 0x78, 0x28,
+	0x0f, 0x95, 0x78, 0x8c, 0x8f, 0x98, 0x24, 0x56, 0xc2, 0x97,
+	0xf3, 0x2c, 0x43, 0xd2, 0x03, 0x82, 0x66, 0x81, 0x72, 0x5f,
+	0x53, 0x16, 0xec, 0xb1, 0xb1, 0x04, 0x5e, 0x40, 0x20, 0x48,
+	0x7b, 0x3f, 0x02, 0x97, 0x6a, 0xeb, 0x96, 0x12, 0x21, 0x35,
+	0xfe, 0x1f, 0x47, 0xc0, 0x95, 0xea, 0xc5, 0x8a, 0x08, 0x84,
+	0x4f, 0x5e, 0x63, 0x94, 0x60, 0x0f, 0x71, 0x5b, 0x7f, 0x4a,
+	0xec, 0x4f, 0x60, 0xc6, 0xba, 0x4a, 0x24, 0xf1, 0x20, 0x8b,
+	0xa7, 0x2e, 0x3a, 0xce, 0x8d, 0xe0, 0x27, 0x1d, 0xb5, 0x8e,
+	0xb4, 0x21, 0xc5, 0xe2, 0xa6, 0x16, 0x0a, 0x51, 0x83, 0x55,
+	0x88, 0xd1, 0x30, 0x11, 0x63, 0xd5, 0xd7, 0x8d, 0xae, 0x16,
+	0x12, 0x82, 0xc4, 0x85, 0x00, 0x4e, 0x27, 0x83, 0xa5, 0x7c,
+	0x90, 0x2e, 0xe5, 0xa2, 0xa3, 0xd3, 0x4c, 0x63, 0x02, 0x82,
+	0x01, 0x01, 0x00, 0x86, 0x08, 0x98, 0x98, 0xa5, 0x00, 0x05,
+	0x39, 0x77, 0xd9, 0x66, 0xb3, 0xcf, 0xca, 0xa0, 0x71, 0xb3,
+	0x50, 0xce, 0x3d, 0xb1, 0x93, 0x95, 0x35, 0xc4, 0xd4, 0x2e,
+	0x90, 0xdf, 0x0f, 0xfc, 0x60, 0xc1, 0x94, 0x68, 0x61, 0x43,
+	0xca, 0x9a, 0x23, 0x4a, 0x1e, 0x45, 0x72, 0x99, 0xb5, 0x1e,
+	0x61, 0x8d, 0x77, 0x0f, 0xa0, 0xbb, 0xd7, 0x77, 0xb4, 0x2a,
+	0x15, 0x11, 0x88, 0x2d, 0xb3, 0x56, 0x61, 0x5e, 0x6a, 0xed,
+	0xa4, 0x46, 0x4a, 0x3f, 0x50, 0x11, 0xd6, 0xba, 0xb6, 0xd7,
+	0x95, 0x65, 0x53, 0xc3, 0xa1, 0x8f, 0xe0, 0xa3, 0xf5, 0x1c,
+	0xfd, 0xaf, 0x6e, 0x43, 0xd7, 0x17, 0xa7, 0xd3, 0x81, 0x1b,
+	0xa4, 0xdf, 0xe0, 0x97, 0x8a, 0x46, 0x03, 0xd3, 0x46, 0x0e,
+	0x83, 0x48, 0x4e, 0xd2, 0x02, 0xcb, 0xc0, 0xad, 0x79, 0x95,
+	0x8c, 0x96, 0xba, 0x40, 0x34, 0x11, 0x71, 0x5e, 0xe9, 0x11,
+	0xf9, 0xc5, 0x4a, 0x5e, 0x91, 0x9d, 0xf5, 0x92, 0x4f, 0xeb,
+	0xc6, 0x70, 0x02, 0x2d, 0x3d, 0x04, 0xaa, 0xe9, 0x3a, 0x8e,
+	0xd5, 0xa8, 0xad, 0xf7, 0xce, 0x0d, 0x16, 0xb2, 0xec, 0x0a,
+	0x9c, 0xf5, 0x94, 0x39, 0xb9, 0x8a, 0xfc, 0x1e, 0xf9, 0xcc,
+	0xf2, 0x5f, 0x21, 0x31, 0x74, 0x72, 0x6b, 0x64, 0xae, 0x35,
+	0x61, 0x8d, 0x0d, 0xcb, 0xe7, 0xda, 0x39, 0xca, 0xf3, 0x21,
+	0x66, 0x0b, 0x95, 0xd7, 0x0a, 0x7c, 0xca, 0xa1, 0xa9, 0x5a,
+	0xe8, 0xac, 0xe0, 0x71, 0x54, 0xaf, 0x28, 0xcf, 0xd5, 0x70,
+	0x89, 0xe0, 0xf3, 0x9e, 0x43, 0x6c, 0x8d, 0x7b, 0x99, 0x01,
+	0x68, 0x4d, 0xa1, 0x45, 0x46, 0x0c, 0x43, 0xbc, 0xcc, 0x2c,
+	0xdd, 0xc5, 0x46, 0xc8, 0x4e, 0x0e, 0xbe, 0xed, 0xb9, 0x26,
+	0xab, 0x2e, 0xdb, 0xeb, 0x8f, 0xff, 0xdb, 0xb0, 0xc6, 0x55,
+	0xaf, 0xf8, 0x2a, 0x91, 0x9d, 0x50, 0x44, 0x21, 0x17,
+};
diff --git a/bin/openssl/timeouts.h b/bin/openssl/timeouts.h
new file mode 100644
index 0000000000..dd2f85028d
--- /dev/null
+++ b/bin/openssl/timeouts.h
@@ -0,0 +1,67 @@
+/* $OpenBSD: timeouts.h,v 1.1 2014/08/26 17:47:25 jsing Exp $ */
+/*
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2005 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef INCLUDED_TIMEOUTS_H
+#define INCLUDED_TIMEOUTS_H
+
+/* numbers in us */
+#define DGRAM_RCV_TIMEOUT         250000
+#define DGRAM_SND_TIMEOUT         250000
+
+#endif /* ! INCLUDED_TIMEOUTS_H */
diff --git a/bin/openssl/ts.c b/bin/openssl/ts.c
new file mode 100644
index 0000000000..28462430a2
--- /dev/null
+++ b/bin/openssl/ts.c
@@ -0,0 +1,1090 @@
+/* $OpenBSD: ts.c,v 1.14 2017/01/20 08:57:12 deraadt Exp $ */
+/* Written by Zoltan Glozik (zglozik@stones.com) for the OpenSSL
+ * project 2002.
+ */
+/* ====================================================================
+ * Copyright (c) 2001 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include 
+#include 
+#include 
+
+#include "apps.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/* Length of the nonce of the request in bits (must be a multiple of 8). */
+#define	NONCE_LENGTH		64
+
+/* Macro definitions for the configuration file. */
+#define	ENV_OID_FILE		"oid_file"
+
+/* Local function declarations. */
+
+static ASN1_OBJECT *txt2obj(const char *oid);
+static CONF *load_config_file(const char *configfile);
+
+/* Query related functions. */
+static int query_command(const char *data, char *digest,
+    const EVP_MD * md, const char *policy, int no_nonce,
+    int cert, const char *in, const char *out, int text);
+static BIO *BIO_open_with_default(const char *file, const char *mode,
+    FILE * default_fp);
+static TS_REQ *create_query(BIO * data_bio, char *digest, const EVP_MD * md,
+    const char *policy, int no_nonce, int cert);
+static int create_digest(BIO * input, char *digest,
+    const EVP_MD * md, unsigned char **md_value);
+static ASN1_INTEGER *create_nonce(int bits);
+
+/* Reply related functions. */
+static int reply_command(CONF * conf, char *section,
+    char *queryfile, char *passin, char *inkey,
+    char *signer, char *chain, const char *policy,
+    char *in, int token_in, char *out, int token_out,
+    int text);
+static TS_RESP *read_PKCS7(BIO * in_bio);
+static TS_RESP *create_response(CONF * conf, const char *section,
+    char *queryfile, char *passin, char *inkey,
+    char *signer, char *chain, const char *policy);
+static ASN1_INTEGER *serial_cb(TS_RESP_CTX * ctx, void *data);
+static ASN1_INTEGER *next_serial(const char *serialfile);
+static int save_ts_serial(const char *serialfile, ASN1_INTEGER * serial);
+
+/* Verify related functions. */
+static int verify_command(char *data, char *digest, char *queryfile,
+    char *in, int token_in,
+    char *ca_path, char *ca_file, char *untrusted);
+static TS_VERIFY_CTX *create_verify_ctx(char *data, char *digest,
+    char *queryfile,
+    char *ca_path, char *ca_file,
+    char *untrusted);
+static X509_STORE *create_cert_store(char *ca_path, char *ca_file);
+static int verify_cb(int ok, X509_STORE_CTX * ctx);
+
+int
+ts_main(int argc, char **argv)
+{
+	int ret = 1;
+	char *configfile = NULL;
+	char *section = NULL;
+	CONF *conf = NULL;
+	enum mode {
+		CMD_NONE, CMD_QUERY, CMD_REPLY, CMD_VERIFY
+	} mode = CMD_NONE;
+	char *data = NULL;
+	char *digest = NULL;
+	const EVP_MD *md = NULL;
+	char *policy = NULL;
+	int no_nonce = 0;
+	int cert = 0;
+	char *in = NULL;
+	char *out = NULL;
+	int text = 0;
+	char *queryfile = NULL;
+	char *passin = NULL;	/* Password source. */
+	char *password = NULL;	/* Password itself. */
+	char *inkey = NULL;
+	char *signer = NULL;
+	char *chain = NULL;
+	char *ca_path = NULL;
+	char *ca_file = NULL;
+	char *untrusted = NULL;
+	/* Input is ContentInfo instead of TimeStampResp. */
+	int token_in = 0;
+	/* Output is ContentInfo instead of TimeStampResp. */
+	int token_out = 0;
+
+	if (single_execution) {
+		if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
+			perror("pledge");
+			exit(1);
+		}
+	}
+
+	for (argc--, argv++; argc > 0; argc--, argv++) {
+		if (strcmp(*argv, "-config") == 0) {
+			if (argc-- < 1)
+				goto usage;
+			configfile = *++argv;
+		} else if (strcmp(*argv, "-section") == 0) {
+			if (argc-- < 1)
+				goto usage;
+			section = *++argv;
+		} else if (strcmp(*argv, "-query") == 0) {
+			if (mode != CMD_NONE)
+				goto usage;
+			mode = CMD_QUERY;
+		} else if (strcmp(*argv, "-data") == 0) {
+			if (argc-- < 1)
+				goto usage;
+			data = *++argv;
+		} else if (strcmp(*argv, "-digest") == 0) {
+			if (argc-- < 1)
+				goto usage;
+			digest = *++argv;
+		} else if (strcmp(*argv, "-policy") == 0) {
+			if (argc-- < 1)
+				goto usage;
+			policy = *++argv;
+		} else if (strcmp(*argv, "-no_nonce") == 0) {
+			no_nonce = 1;
+		} else if (strcmp(*argv, "-cert") == 0) {
+			cert = 1;
+		} else if (strcmp(*argv, "-in") == 0) {
+			if (argc-- < 1)
+				goto usage;
+			in = *++argv;
+		} else if (strcmp(*argv, "-token_in") == 0) {
+			token_in = 1;
+		} else if (strcmp(*argv, "-out") == 0) {
+			if (argc-- < 1)
+				goto usage;
+			out = *++argv;
+		} else if (strcmp(*argv, "-token_out") == 0) {
+			token_out = 1;
+		} else if (strcmp(*argv, "-text") == 0) {
+			text = 1;
+		} else if (strcmp(*argv, "-reply") == 0) {
+			if (mode != CMD_NONE)
+				goto usage;
+			mode = CMD_REPLY;
+		} else if (strcmp(*argv, "-queryfile") == 0) {
+			if (argc-- < 1)
+				goto usage;
+			queryfile = *++argv;
+		} else if (strcmp(*argv, "-passin") == 0) {
+			if (argc-- < 1)
+				goto usage;
+			passin = *++argv;
+		} else if (strcmp(*argv, "-inkey") == 0) {
+			if (argc-- < 1)
+				goto usage;
+			inkey = *++argv;
+		} else if (strcmp(*argv, "-signer") == 0) {
+			if (argc-- < 1)
+				goto usage;
+			signer = *++argv;
+		} else if (strcmp(*argv, "-chain") == 0) {
+			if (argc-- < 1)
+				goto usage;
+			chain = *++argv;
+		} else if (strcmp(*argv, "-verify") == 0) {
+			if (mode != CMD_NONE)
+				goto usage;
+			mode = CMD_VERIFY;
+		} else if (strcmp(*argv, "-CApath") == 0) {
+			if (argc-- < 1)
+				goto usage;
+			ca_path = *++argv;
+		} else if (strcmp(*argv, "-CAfile") == 0) {
+			if (argc-- < 1)
+				goto usage;
+			ca_file = *++argv;
+		} else if (strcmp(*argv, "-untrusted") == 0) {
+			if (argc-- < 1)
+				goto usage;
+			untrusted = *++argv;
+		} else if ((md = EVP_get_digestbyname(*argv + 1)) != NULL) {
+			/* empty. */
+		} else
+			goto usage;
+	}
+
+	/* Get the password if required. */
+	if (mode == CMD_REPLY && passin &&
+	    !app_passwd(bio_err, passin, NULL, &password, NULL)) {
+		BIO_printf(bio_err, "Error getting password.\n");
+		goto cleanup;
+	}
+	/*
+	 * Check consistency of parameters and execute the appropriate
+	 * function.
+	 */
+	switch (mode) {
+	case CMD_NONE:
+		goto usage;
+	case CMD_QUERY:
+		/*
+		 * Data file and message imprint cannot be specified at the
+		 * same time.
+		 */
+		ret = data != NULL && digest != NULL;
+		if (ret)
+			goto usage;
+		/* Load the config file for possible policy OIDs. */
+		conf = load_config_file(configfile);
+		ret = !query_command(data, digest, md, policy, no_nonce, cert,
+		    in, out, text);
+		break;
+	case CMD_REPLY:
+		conf = load_config_file(configfile);
+		if (in == NULL) {
+			ret = !(queryfile != NULL && conf != NULL && !token_in);
+			if (ret)
+				goto usage;
+		} else {
+			/* 'in' and 'queryfile' are exclusive. */
+			ret = !(queryfile == NULL);
+			if (ret)
+				goto usage;
+		}
+
+		ret = !reply_command(conf, section, queryfile,
+		    password, inkey, signer, chain, policy,
+		    in, token_in, out, token_out, text);
+		break;
+	case CMD_VERIFY:
+		ret = !(((queryfile && !data && !digest) ||
+		    (!queryfile && data && !digest) ||
+		    (!queryfile && !data && digest)) && in != NULL);
+		if (ret)
+			goto usage;
+
+		ret = !verify_command(data, digest, queryfile, in, token_in,
+		    ca_path, ca_file, untrusted);
+	}
+
+	goto cleanup;
+
+usage:
+	BIO_printf(bio_err, "usage:\n"
+	    "ts -query [-config configfile] "
+	    "[-data file_to_hash] [-digest digest_bytes]"
+	    "[-md4|-md5|-sha1|-ripemd160] "
+	    "[-policy object_id] [-no_nonce] [-cert] "
+	    "[-in request.tsq] [-out request.tsq] [-text]\n");
+	BIO_printf(bio_err, "or\n"
+	    "ts -reply [-config configfile] [-section tsa_section] "
+	    "[-queryfile request.tsq] [-passin password] "
+	    "[-signer tsa_cert.pem] [-inkey private_key.pem] "
+	    "[-chain certs_file.pem] [-policy object_id] "
+	    "[-in response.tsr] [-token_in] "
+	    "[-out response.tsr] [-token_out] [-text]\n");
+	BIO_printf(bio_err, "or\n"
+	    "ts -verify [-data file_to_hash] [-digest digest_bytes] "
+	    "[-queryfile request.tsq] "
+	    "-in response.tsr [-token_in] "
+	    "-CApath ca_path -CAfile ca_file.pem "
+	    "-untrusted cert_file.pem\n");
+
+cleanup:
+	/* Clean up. */
+	NCONF_free(conf);
+	free(password);
+	OBJ_cleanup();
+
+	return (ret);
+}
+
+/*
+ * Configuration file-related function definitions.
+ */
+
+static ASN1_OBJECT *
+txt2obj(const char *oid)
+{
+	ASN1_OBJECT *oid_obj = NULL;
+
+	if (!(oid_obj = OBJ_txt2obj(oid, 0)))
+		BIO_printf(bio_err, "cannot convert %s to OID\n", oid);
+
+	return oid_obj;
+}
+
+static CONF *
+load_config_file(const char *configfile)
+{
+	CONF *conf = NULL;
+	long errorline = -1;
+
+	if (!configfile)
+		configfile = getenv("OPENSSL_CONF");
+
+	if (configfile &&
+	    (!(conf = NCONF_new(NULL)) ||
+	    NCONF_load(conf, configfile, &errorline) <= 0)) {
+		if (errorline <= 0)
+			BIO_printf(bio_err, "error loading the config file "
+			    "'%s'\n", configfile);
+		else
+			BIO_printf(bio_err, "error on line %ld of config file "
+			    "'%s'\n", errorline, configfile);
+	}
+	if (conf != NULL) {
+		const char *p;
+
+		BIO_printf(bio_err, "Using configuration from %s\n",
+		    configfile);
+		p = NCONF_get_string(conf, NULL, ENV_OID_FILE);
+		if (p != NULL) {
+			BIO *oid_bio = BIO_new_file(p, "r");
+			if (!oid_bio)
+				ERR_print_errors(bio_err);
+			else {
+				OBJ_create_objects(oid_bio);
+				BIO_free_all(oid_bio);
+			}
+		} else
+			ERR_clear_error();
+		if (!add_oid_section(bio_err, conf))
+			ERR_print_errors(bio_err);
+	}
+	return conf;
+}
+
+/*
+ * Query-related method definitions.
+ */
+
+static int
+query_command(const char *data, char *digest, const EVP_MD * md,
+    const char *policy, int no_nonce, int cert, const char *in,
+    const char *out, int text)
+{
+	int ret = 0;
+	TS_REQ *query = NULL;
+	BIO *in_bio = NULL;
+	BIO *data_bio = NULL;
+	BIO *out_bio = NULL;
+
+	/* Build query object either from file or from scratch. */
+	if (in != NULL) {
+		if ((in_bio = BIO_new_file(in, "rb")) == NULL)
+			goto end;
+		query = d2i_TS_REQ_bio(in_bio, NULL);
+	} else {
+		/* Open the file if no explicit digest bytes were specified. */
+		if (!digest &&
+		    !(data_bio = BIO_open_with_default(data, "rb", stdin)))
+			goto end;
+		/* Creating the query object. */
+		query = create_query(data_bio, digest, md,
+		    policy, no_nonce, cert);
+		/* Saving the random number generator state. */
+	}
+	if (query == NULL)
+		goto end;
+
+	/* Write query either in ASN.1 or in text format. */
+	if ((out_bio = BIO_open_with_default(out, "wb", stdout)) == NULL)
+		goto end;
+	if (text) {
+		/* Text output. */
+		if (!TS_REQ_print_bio(out_bio, query))
+			goto end;
+	} else {
+		/* ASN.1 output. */
+		if (!i2d_TS_REQ_bio(out_bio, query))
+			goto end;
+	}
+
+	ret = 1;
+
+end:
+	ERR_print_errors(bio_err);
+
+	/* Clean up. */
+	BIO_free_all(in_bio);
+	BIO_free_all(data_bio);
+	BIO_free_all(out_bio);
+	TS_REQ_free(query);
+
+	return ret;
+}
+
+static BIO *
+BIO_open_with_default(const char *file, const char *mode, FILE * default_fp)
+{
+	return file == NULL ? BIO_new_fp(default_fp, BIO_NOCLOSE) :
+	    BIO_new_file(file, mode);
+}
+
+static TS_REQ *
+create_query(BIO * data_bio, char *digest, const EVP_MD * md,
+    const char *policy, int no_nonce, int cert)
+{
+	int ret = 0;
+	TS_REQ *ts_req = NULL;
+	int len;
+	TS_MSG_IMPRINT *msg_imprint = NULL;
+	X509_ALGOR *algo = NULL;
+	unsigned char *data = NULL;
+	ASN1_OBJECT *policy_obj = NULL;
+	ASN1_INTEGER *nonce_asn1 = NULL;
+
+	/* Setting default message digest. */
+	if (!md && !(md = EVP_get_digestbyname("sha1")))
+		goto err;
+
+	/* Creating request object. */
+	if (!(ts_req = TS_REQ_new()))
+		goto err;
+
+	/* Setting version. */
+	if (!TS_REQ_set_version(ts_req, 1))
+		goto err;
+
+	/* Creating and adding MSG_IMPRINT object. */
+	if (!(msg_imprint = TS_MSG_IMPRINT_new()))
+		goto err;
+
+	/* Adding algorithm. */
+	if (!(algo = X509_ALGOR_new()))
+		goto err;
+	if (!(algo->algorithm = OBJ_nid2obj(EVP_MD_type(md))))
+		goto err;
+	if (!(algo->parameter = ASN1_TYPE_new()))
+		goto err;
+	algo->parameter->type = V_ASN1_NULL;
+	if (!TS_MSG_IMPRINT_set_algo(msg_imprint, algo))
+		goto err;
+
+	/* Adding message digest. */
+	if ((len = create_digest(data_bio, digest, md, &data)) == 0)
+		goto err;
+	if (!TS_MSG_IMPRINT_set_msg(msg_imprint, data, len))
+		goto err;
+
+	if (!TS_REQ_set_msg_imprint(ts_req, msg_imprint))
+		goto err;
+
+	/* Setting policy if requested. */
+	if (policy && !(policy_obj = txt2obj(policy)))
+		goto err;
+	if (policy_obj && !TS_REQ_set_policy_id(ts_req, policy_obj))
+		goto err;
+
+	/* Setting nonce if requested. */
+	if (!no_nonce && !(nonce_asn1 = create_nonce(NONCE_LENGTH)))
+		goto err;
+	if (nonce_asn1 && !TS_REQ_set_nonce(ts_req, nonce_asn1))
+		goto err;
+
+	/* Setting certificate request flag if requested. */
+	if (!TS_REQ_set_cert_req(ts_req, cert))
+		goto err;
+
+	ret = 1;
+
+err:
+	if (!ret) {
+		TS_REQ_free(ts_req);
+		ts_req = NULL;
+		BIO_printf(bio_err, "could not create query\n");
+	}
+	TS_MSG_IMPRINT_free(msg_imprint);
+	X509_ALGOR_free(algo);
+	free(data);
+	ASN1_OBJECT_free(policy_obj);
+	ASN1_INTEGER_free(nonce_asn1);
+
+	return ts_req;
+}
+
+static int
+create_digest(BIO * input, char *digest, const EVP_MD * md,
+    unsigned char **md_value)
+{
+	int md_value_len;
+
+	md_value_len = EVP_MD_size(md);
+	if (md_value_len < 0)
+		goto err;
+	if (input) {
+		/* Digest must be computed from an input file. */
+		EVP_MD_CTX md_ctx;
+		unsigned char buffer[4096];
+		int length;
+
+		*md_value = malloc(md_value_len);
+		if (*md_value == 0)
+			goto err;
+
+		EVP_DigestInit(&md_ctx, md);
+		while ((length = BIO_read(input, buffer, sizeof(buffer))) > 0) {
+			EVP_DigestUpdate(&md_ctx, buffer, length);
+		}
+		EVP_DigestFinal(&md_ctx, *md_value, NULL);
+	} else {
+		/* Digest bytes are specified with digest. */
+		long digest_len;
+		*md_value = string_to_hex(digest, &digest_len);
+		if (!*md_value || md_value_len != digest_len) {
+			free(*md_value);
+			*md_value = NULL;
+			BIO_printf(bio_err, "bad digest, %d bytes "
+			    "must be specified\n", md_value_len);
+			goto err;
+		}
+	}
+
+	return md_value_len;
+err:
+	return 0;
+}
+
+static ASN1_INTEGER *
+create_nonce(int bits)
+{
+	unsigned char buf[20];
+	ASN1_INTEGER *nonce = NULL;
+	int len = (bits - 1) / 8 + 1;
+	int i;
+
+	/* Generating random byte sequence. */
+	if (len > (int) sizeof(buf))
+		goto err;
+	arc4random_buf(buf, len);
+
+	/* Find the first non-zero byte and creating ASN1_INTEGER object. */
+	for (i = 0; i < len && !buf[i]; ++i)
+		;
+	if (!(nonce = ASN1_INTEGER_new()))
+		goto err;
+	free(nonce->data);
+	/* Allocate at least one byte. */
+	nonce->length = len - i;
+	if (!(nonce->data = malloc(nonce->length + 1)))
+		goto err;
+	memcpy(nonce->data, buf + i, nonce->length);
+
+	return nonce;
+
+err:
+	BIO_printf(bio_err, "could not create nonce\n");
+	ASN1_INTEGER_free(nonce);
+	return NULL;
+}
+/*
+ * Reply-related method definitions.
+ */
+
+static int
+reply_command(CONF * conf, char *section, char *queryfile,
+    char *passin, char *inkey, char *signer, char *chain, const char *policy,
+    char *in, int token_in, char *out, int token_out, int text)
+{
+	int ret = 0;
+	TS_RESP *response = NULL;
+	BIO *in_bio = NULL;
+	BIO *query_bio = NULL;
+	BIO *inkey_bio = NULL;
+	BIO *signer_bio = NULL;
+	BIO *out_bio = NULL;
+
+	/* Build response object either from response or query. */
+	if (in != NULL) {
+		if ((in_bio = BIO_new_file(in, "rb")) == NULL)
+			goto end;
+		if (token_in) {
+			/*
+			 * We have a ContentInfo (PKCS7) object, add
+			 * 'granted' status info around it.
+			 */
+			response = read_PKCS7(in_bio);
+		} else {
+			/* We have a ready-made TS_RESP object. */
+			response = d2i_TS_RESP_bio(in_bio, NULL);
+		}
+	} else {
+		response = create_response(conf, section, queryfile,
+		    passin, inkey, signer, chain,
+		    policy);
+		if (response)
+			BIO_printf(bio_err, "Response has been generated.\n");
+		else
+			BIO_printf(bio_err, "Response is not generated.\n");
+	}
+	if (response == NULL)
+		goto end;
+
+	/* Write response either in ASN.1 or text format. */
+	if ((out_bio = BIO_open_with_default(out, "wb", stdout)) == NULL)
+		goto end;
+	if (text) {
+		/* Text output. */
+		if (token_out) {
+			TS_TST_INFO *tst_info = TS_RESP_get_tst_info(response);
+			if (!TS_TST_INFO_print_bio(out_bio, tst_info))
+				goto end;
+		} else {
+			if (!TS_RESP_print_bio(out_bio, response))
+				goto end;
+		}
+	} else {
+		/* ASN.1 DER output. */
+		if (token_out) {
+			PKCS7 *token = TS_RESP_get_token(response);
+			if (!i2d_PKCS7_bio(out_bio, token))
+				goto end;
+		} else {
+			if (!i2d_TS_RESP_bio(out_bio, response))
+				goto end;
+		}
+	}
+
+	ret = 1;
+
+end:
+	ERR_print_errors(bio_err);
+
+	/* Clean up. */
+	BIO_free_all(in_bio);
+	BIO_free_all(query_bio);
+	BIO_free_all(inkey_bio);
+	BIO_free_all(signer_bio);
+	BIO_free_all(out_bio);
+	TS_RESP_free(response);
+
+	return ret;
+}
+
+/* Reads a PKCS7 token and adds default 'granted' status info to it. */
+static TS_RESP *
+read_PKCS7(BIO * in_bio)
+{
+	int ret = 0;
+	PKCS7 *token = NULL;
+	TS_TST_INFO *tst_info = NULL;
+	TS_RESP *resp = NULL;
+	TS_STATUS_INFO *si = NULL;
+
+	/* Read PKCS7 object and extract the signed time stamp info. */
+	if (!(token = d2i_PKCS7_bio(in_bio, NULL)))
+		goto end;
+	if (!(tst_info = PKCS7_to_TS_TST_INFO(token)))
+		goto end;
+
+	/* Creating response object. */
+	if (!(resp = TS_RESP_new()))
+		goto end;
+
+	/* Create granted status info. */
+	if (!(si = TS_STATUS_INFO_new()))
+		goto end;
+	if (!(ASN1_INTEGER_set(si->status, TS_STATUS_GRANTED)))
+		goto end;
+	if (!TS_RESP_set_status_info(resp, si))
+		goto end;
+
+	/* Setting encapsulated token. */
+	TS_RESP_set_tst_info(resp, token, tst_info);
+	token = NULL;		/* Ownership is lost. */
+	tst_info = NULL;	/* Ownership is lost. */
+
+	ret = 1;
+end:
+	PKCS7_free(token);
+	TS_TST_INFO_free(tst_info);
+	if (!ret) {
+		TS_RESP_free(resp);
+		resp = NULL;
+	}
+	TS_STATUS_INFO_free(si);
+	return resp;
+}
+
+static TS_RESP *
+create_response(CONF * conf, const char *section,
+    char *queryfile, char *passin, char *inkey,
+    char *signer, char *chain, const char *policy)
+{
+	int ret = 0;
+	TS_RESP *response = NULL;
+	BIO *query_bio = NULL;
+	TS_RESP_CTX *resp_ctx = NULL;
+
+	if (!(query_bio = BIO_new_file(queryfile, "rb")))
+		goto end;
+
+	/* Getting TSA configuration section. */
+	if (!(section = TS_CONF_get_tsa_section(conf, section)))
+		goto end;
+
+	/* Setting up response generation context. */
+	if (!(resp_ctx = TS_RESP_CTX_new()))
+		goto end;
+
+	/* Setting serial number provider callback. */
+	if (!TS_CONF_set_serial(conf, section, serial_cb, resp_ctx))
+		goto end;
+
+	/* Setting TSA signer certificate. */
+	if (!TS_CONF_set_signer_cert(conf, section, signer, resp_ctx))
+		goto end;
+
+	/* Setting TSA signer certificate chain. */
+	if (!TS_CONF_set_certs(conf, section, chain, resp_ctx))
+		goto end;
+
+	/* Setting TSA signer private key. */
+	if (!TS_CONF_set_signer_key(conf, section, inkey, passin, resp_ctx))
+		goto end;
+
+	/* Setting default policy OID. */
+	if (!TS_CONF_set_def_policy(conf, section, policy, resp_ctx))
+		goto end;
+
+	/* Setting acceptable policy OIDs. */
+	if (!TS_CONF_set_policies(conf, section, resp_ctx))
+		goto end;
+
+	/* Setting the acceptable one-way hash algorithms. */
+	if (!TS_CONF_set_digests(conf, section, resp_ctx))
+		goto end;
+
+	/* Setting guaranteed time stamp accuracy. */
+	if (!TS_CONF_set_accuracy(conf, section, resp_ctx))
+		goto end;
+
+	/* Setting the precision of the time. */
+	if (!TS_CONF_set_clock_precision_digits(conf, section, resp_ctx))
+		goto end;
+
+	/* Setting the ordering flaf if requested. */
+	if (!TS_CONF_set_ordering(conf, section, resp_ctx))
+		goto end;
+
+	/* Setting the TSA name required flag if requested. */
+	if (!TS_CONF_set_tsa_name(conf, section, resp_ctx))
+		goto end;
+
+	/* Setting the ESS cert id chain flag if requested. */
+	if (!TS_CONF_set_ess_cert_id_chain(conf, section, resp_ctx))
+		goto end;
+
+	/* Creating the response. */
+	if (!(response = TS_RESP_create_response(resp_ctx, query_bio)))
+		goto end;
+
+	ret = 1;
+end:
+	if (!ret) {
+		TS_RESP_free(response);
+		response = NULL;
+	}
+	TS_RESP_CTX_free(resp_ctx);
+	BIO_free_all(query_bio);
+
+	return response;
+}
+
+static ASN1_INTEGER *
+serial_cb(TS_RESP_CTX * ctx, void *data)
+{
+	const char *serial_file = (const char *) data;
+	ASN1_INTEGER *serial = next_serial(serial_file);
+
+	if (!serial) {
+		TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
+		    "Error during serial number "
+		    "generation.");
+		TS_RESP_CTX_add_failure_info(ctx,
+		    TS_INFO_ADD_INFO_NOT_AVAILABLE);
+	} else
+		save_ts_serial(serial_file, serial);
+
+	return serial;
+}
+
+static ASN1_INTEGER *
+next_serial(const char *serialfile)
+{
+	int ret = 0;
+	BIO *in = NULL;
+	ASN1_INTEGER *serial = NULL;
+	BIGNUM *bn = NULL;
+
+	if (!(serial = ASN1_INTEGER_new()))
+		goto err;
+
+	if (!(in = BIO_new_file(serialfile, "r"))) {
+		ERR_clear_error();
+		BIO_printf(bio_err, "Warning: could not open file %s for "
+		    "reading, using serial number: 1\n", serialfile);
+		if (!ASN1_INTEGER_set(serial, 1))
+			goto err;
+	} else {
+		char buf[1024];
+		if (!a2i_ASN1_INTEGER(in, serial, buf, sizeof(buf))) {
+			BIO_printf(bio_err, "unable to load number from %s\n",
+			    serialfile);
+			goto err;
+		}
+		if (!(bn = ASN1_INTEGER_to_BN(serial, NULL)))
+			goto err;
+		ASN1_INTEGER_free(serial);
+		serial = NULL;
+		if (!BN_add_word(bn, 1))
+			goto err;
+		if (!(serial = BN_to_ASN1_INTEGER(bn, NULL)))
+			goto err;
+	}
+	ret = 1;
+err:
+	if (!ret) {
+		ASN1_INTEGER_free(serial);
+		serial = NULL;
+	}
+	BIO_free_all(in);
+	BN_free(bn);
+	return serial;
+}
+
+static int
+save_ts_serial(const char *serialfile, ASN1_INTEGER * serial)
+{
+	int ret = 0;
+	BIO *out = NULL;
+
+	if (!(out = BIO_new_file(serialfile, "w")))
+		goto err;
+	if (i2a_ASN1_INTEGER(out, serial) <= 0)
+		goto err;
+	if (BIO_puts(out, "\n") <= 0)
+		goto err;
+	ret = 1;
+err:
+	if (!ret)
+		BIO_printf(bio_err, "could not save serial number to %s\n",
+		    serialfile);
+	BIO_free_all(out);
+	return ret;
+}
+
+/*
+ * Verify-related method definitions.
+ */
+
+static int
+verify_command(char *data, char *digest, char *queryfile, char *in,
+    int token_in, char *ca_path, char *ca_file, char *untrusted)
+{
+	BIO *in_bio = NULL;
+	PKCS7 *token = NULL;
+	TS_RESP *response = NULL;
+	TS_VERIFY_CTX *verify_ctx = NULL;
+	int ret = 0;
+
+	/* Decode the token (PKCS7) or response (TS_RESP) files. */
+	if (!(in_bio = BIO_new_file(in, "rb")))
+		goto end;
+	if (token_in) {
+		if (!(token = d2i_PKCS7_bio(in_bio, NULL)))
+			goto end;
+	} else {
+		if (!(response = d2i_TS_RESP_bio(in_bio, NULL)))
+			goto end;
+	}
+
+	if (!(verify_ctx = create_verify_ctx(data, digest, queryfile,
+	    ca_path, ca_file, untrusted)))
+		goto end;
+
+	/* Checking the token or response against the request. */
+	ret = token_in ?
+	    TS_RESP_verify_token(verify_ctx, token) :
+	    TS_RESP_verify_response(verify_ctx, response);
+
+end:
+	printf("Verification: ");
+	if (ret)
+		printf("OK\n");
+	else {
+		printf("FAILED\n");
+		/* Print errors, if there are any. */
+		ERR_print_errors(bio_err);
+	}
+
+	/* Clean up. */
+	BIO_free_all(in_bio);
+	PKCS7_free(token);
+	TS_RESP_free(response);
+	TS_VERIFY_CTX_free(verify_ctx);
+	return ret;
+}
+
+static TS_VERIFY_CTX *
+create_verify_ctx(char *data, char *digest, char *queryfile, char *ca_path,
+    char *ca_file, char *untrusted)
+{
+	TS_VERIFY_CTX *ctx = NULL;
+	BIO *input = NULL;
+	TS_REQ *request = NULL;
+	int ret = 0;
+
+	if (data != NULL || digest != NULL) {
+		if (!(ctx = TS_VERIFY_CTX_new()))
+			goto err;
+		ctx->flags = TS_VFY_VERSION | TS_VFY_SIGNER;
+		if (data != NULL) {
+			ctx->flags |= TS_VFY_DATA;
+			if (!(ctx->data = BIO_new_file(data, "rb")))
+				goto err;
+		} else if (digest != NULL) {
+			long imprint_len;
+			ctx->flags |= TS_VFY_IMPRINT;
+			if (!(ctx->imprint = string_to_hex(digest,
+				    &imprint_len))) {
+				BIO_printf(bio_err, "invalid digest string\n");
+				goto err;
+			}
+			ctx->imprint_len = imprint_len;
+		}
+	} else if (queryfile != NULL) {
+		/*
+		 * The request has just to be read, decoded and converted to
+		 * a verify context object.
+		 */
+		if (!(input = BIO_new_file(queryfile, "rb")))
+			goto err;
+		if (!(request = d2i_TS_REQ_bio(input, NULL)))
+			goto err;
+		if (!(ctx = TS_REQ_to_TS_VERIFY_CTX(request, NULL)))
+			goto err;
+	} else
+		return NULL;
+
+	/* Add the signature verification flag and arguments. */
+	ctx->flags |= TS_VFY_SIGNATURE;
+
+	/* Initialising the X509_STORE object. */
+	if (!(ctx->store = create_cert_store(ca_path, ca_file)))
+		goto err;
+
+	/* Loading untrusted certificates. */
+	if (untrusted && !(ctx->certs = TS_CONF_load_certs(untrusted)))
+		goto err;
+
+	ret = 1;
+err:
+	if (!ret) {
+		TS_VERIFY_CTX_free(ctx);
+		ctx = NULL;
+	}
+	BIO_free_all(input);
+	TS_REQ_free(request);
+	return ctx;
+}
+
+static X509_STORE *
+create_cert_store(char *ca_path, char *ca_file)
+{
+	X509_STORE *cert_ctx = NULL;
+	X509_LOOKUP *lookup = NULL;
+	int i;
+
+	/* Creating the X509_STORE object. */
+	cert_ctx = X509_STORE_new();
+
+	/* Setting the callback for certificate chain verification. */
+	X509_STORE_set_verify_cb(cert_ctx, verify_cb);
+
+	/* Adding a trusted certificate directory source. */
+	if (ca_path) {
+		lookup = X509_STORE_add_lookup(cert_ctx,
+		    X509_LOOKUP_hash_dir());
+		if (lookup == NULL) {
+			BIO_printf(bio_err, "memory allocation failure\n");
+			goto err;
+		}
+		i = X509_LOOKUP_add_dir(lookup, ca_path, X509_FILETYPE_PEM);
+		if (!i) {
+			BIO_printf(bio_err, "Error loading directory %s\n",
+			    ca_path);
+			goto err;
+		}
+	}
+	/* Adding a trusted certificate file source. */
+	if (ca_file) {
+		lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_file());
+		if (lookup == NULL) {
+			BIO_printf(bio_err, "memory allocation failure\n");
+			goto err;
+		}
+		i = X509_LOOKUP_load_file(lookup, ca_file, X509_FILETYPE_PEM);
+		if (!i) {
+			BIO_printf(bio_err, "Error loading file %s\n", ca_file);
+			goto err;
+		}
+	}
+	return cert_ctx;
+err:
+	X509_STORE_free(cert_ctx);
+	return NULL;
+}
+
+static int
+verify_cb(int ok, X509_STORE_CTX * ctx)
+{
+	/*
+	char buf[256];
+
+	if (!ok)
+		{
+		X509_NAME_oneline(X509_get_subject_name(ctx->current_cert),
+				  buf, sizeof(buf));
+		printf("%s\n", buf);
+		printf("error %d at %d depth lookup: %s\n",
+		       ctx->error, ctx->error_depth,
+			X509_verify_cert_error_string(ctx->error));
+		}
+	*/
+
+	return ok;
+}
diff --git a/bin/openssl/verify.c b/bin/openssl/verify.c
new file mode 100644
index 0000000000..d9b5ef9795
--- /dev/null
+++ b/bin/openssl/verify.c
@@ -0,0 +1,324 @@
+/* $OpenBSD: verify.c,v 1.6 2015/10/17 15:00:11 doug Exp $ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include 
+#include 
+#include 
+
+#include "apps.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+static int cb(int ok, X509_STORE_CTX * ctx);
+static int check(X509_STORE * ctx, char *file, STACK_OF(X509) * uchain,
+    STACK_OF(X509) * tchain, STACK_OF(X509_CRL) * crls);
+static int v_verbose = 0, vflags = 0;
+
+int
+verify_main(int argc, char **argv)
+{
+	int i, ret = 1, badarg = 0;
+	char *CApath = NULL, *CAfile = NULL;
+	char *untfile = NULL, *trustfile = NULL, *crlfile = NULL;
+	STACK_OF(X509) * untrusted = NULL, *trusted = NULL;
+	STACK_OF(X509_CRL) * crls = NULL;
+	X509_STORE *cert_ctx = NULL;
+	X509_LOOKUP *lookup = NULL;
+	X509_VERIFY_PARAM *vpm = NULL;
+
+	if (single_execution) {
+		if (pledge("stdio rpath", NULL) == -1) {
+			perror("pledge");
+			exit(1);
+		}
+	}
+
+	cert_ctx = X509_STORE_new();
+	if (cert_ctx == NULL)
+		goto end;
+	X509_STORE_set_verify_cb(cert_ctx, cb);
+
+	argc--;
+	argv++;
+	for (;;) {
+		if (argc >= 1) {
+			if (strcmp(*argv, "-CApath") == 0) {
+				if (argc-- < 1)
+					goto end;
+				CApath = *(++argv);
+			} else if (strcmp(*argv, "-CAfile") == 0) {
+				if (argc-- < 1)
+					goto end;
+				CAfile = *(++argv);
+			} else if (args_verify(&argv, &argc, &badarg, bio_err,
+			    &vpm)) {
+				if (badarg)
+					goto end;
+				continue;
+			} else if (strcmp(*argv, "-untrusted") == 0) {
+				if (argc-- < 1)
+					goto end;
+				untfile = *(++argv);
+			} else if (strcmp(*argv, "-trusted") == 0) {
+				if (argc-- < 1)
+					goto end;
+				trustfile = *(++argv);
+			} else if (strcmp(*argv, "-CRLfile") == 0) {
+				if (argc-- < 1)
+					goto end;
+				crlfile = *(++argv);
+			}
+			else if (strcmp(*argv, "-help") == 0)
+				goto end;
+			else if (strcmp(*argv, "-verbose") == 0)
+				v_verbose = 1;
+			else if (argv[0][0] == '-')
+				goto end;
+			else
+				break;
+			argc--;
+			argv++;
+		} else
+			break;
+	}
+
+	if (vpm)
+		X509_STORE_set1_param(cert_ctx, vpm);
+
+	lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_file());
+	if (lookup == NULL)
+		abort();
+	if (CAfile) {
+		i = X509_LOOKUP_load_file(lookup, CAfile, X509_FILETYPE_PEM);
+		if (!i) {
+			BIO_printf(bio_err, "Error loading file %s\n", CAfile);
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+	} else
+		X509_LOOKUP_load_file(lookup, NULL, X509_FILETYPE_DEFAULT);
+
+	lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_hash_dir());
+	if (lookup == NULL)
+		abort();
+	if (CApath) {
+		i = X509_LOOKUP_add_dir(lookup, CApath, X509_FILETYPE_PEM);
+		if (!i) {
+			BIO_printf(bio_err, "Error loading directory %s\n", CApath);
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+	} else
+		X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT);
+
+	ERR_clear_error();
+
+	if (untfile) {
+		untrusted = load_certs(bio_err, untfile, FORMAT_PEM,
+		    NULL, "untrusted certificates");
+		if (!untrusted)
+			goto end;
+	}
+	if (trustfile) {
+		trusted = load_certs(bio_err, trustfile, FORMAT_PEM,
+		    NULL, "trusted certificates");
+		if (!trusted)
+			goto end;
+	}
+	if (crlfile) {
+		crls = load_crls(bio_err, crlfile, FORMAT_PEM,
+		    NULL, "other CRLs");
+		if (!crls)
+			goto end;
+	}
+	ret = 0;
+	if (argc < 1) {
+		if (1 != check(cert_ctx, NULL, untrusted, trusted, crls))
+			ret = -1;
+	} else {
+		for (i = 0; i < argc; i++)
+			if (1 != check(cert_ctx, argv[i], untrusted, trusted,
+			    crls))
+				ret = -1;
+	}
+
+end:
+	if (ret == 1) {
+		BIO_printf(bio_err, "usage: verify [-verbose] [-CApath path] [-CAfile file] [-purpose purpose] [-crl_check]");
+		BIO_printf(bio_err, " [-attime timestamp]");
+		BIO_printf(bio_err, " cert1 cert2 ...\n");
+
+		BIO_printf(bio_err, "recognized usages:\n");
+		for (i = 0; i < X509_PURPOSE_get_count(); i++) {
+			X509_PURPOSE *ptmp;
+			ptmp = X509_PURPOSE_get0(i);
+			BIO_printf(bio_err, "\t%-10s\t%s\n",
+			    X509_PURPOSE_get0_sname(ptmp),
+			    X509_PURPOSE_get0_name(ptmp));
+		}
+	}
+	if (vpm)
+		X509_VERIFY_PARAM_free(vpm);
+	if (cert_ctx != NULL)
+		X509_STORE_free(cert_ctx);
+	sk_X509_pop_free(untrusted, X509_free);
+	sk_X509_pop_free(trusted, X509_free);
+	sk_X509_CRL_pop_free(crls, X509_CRL_free);
+
+	return (ret < 0 ? 2 : ret);
+}
+
+static int
+check(X509_STORE * ctx, char *file, STACK_OF(X509) * uchain,
+    STACK_OF(X509) * tchain, STACK_OF(X509_CRL) * crls)
+{
+	X509 *x = NULL;
+	int i = 0, ret = 0;
+	X509_STORE_CTX *csc;
+
+	x = load_cert(bio_err, file, FORMAT_PEM, NULL, "certificate file");
+	if (x == NULL)
+		goto end;
+	fprintf(stdout, "%s: ", (file == NULL) ? "stdin" : file);
+
+	csc = X509_STORE_CTX_new();
+	if (csc == NULL) {
+		ERR_print_errors(bio_err);
+		goto end;
+	}
+	X509_STORE_set_flags(ctx, vflags);
+	if (!X509_STORE_CTX_init(csc, ctx, x, uchain)) {
+		ERR_print_errors(bio_err);
+		goto end;
+	}
+	if (tchain)
+		X509_STORE_CTX_trusted_stack(csc, tchain);
+	if (crls)
+		X509_STORE_CTX_set0_crls(csc, crls);
+	i = X509_verify_cert(csc);
+	X509_STORE_CTX_free(csc);
+
+	ret = 0;
+
+end:
+	if (i > 0) {
+		fprintf(stdout, "OK\n");
+		ret = 1;
+	} else
+		ERR_print_errors(bio_err);
+	if (x != NULL)
+		X509_free(x);
+
+	return (ret);
+}
+
+static int
+cb(int ok, X509_STORE_CTX * ctx)
+{
+	int cert_error = X509_STORE_CTX_get_error(ctx);
+	X509 *current_cert = X509_STORE_CTX_get_current_cert(ctx);
+
+	if (!ok) {
+		if (current_cert) {
+			X509_NAME_print_ex_fp(stdout,
+			    X509_get_subject_name(current_cert),
+			    0, XN_FLAG_ONELINE);
+			printf("\n");
+		}
+		printf("%serror %d at %d depth lookup:%s\n",
+		    X509_STORE_CTX_get0_parent_ctx(ctx) ? "[CRL path]" : "",
+		    cert_error,
+		    X509_STORE_CTX_get_error_depth(ctx),
+		    X509_verify_cert_error_string(cert_error));
+		switch (cert_error) {
+		case X509_V_ERR_NO_EXPLICIT_POLICY:
+			policies_print(NULL, ctx);
+		case X509_V_ERR_CERT_HAS_EXPIRED:
+
+			/*
+			 * since we are just checking the certificates, it is
+			 * ok if they are self signed. But we should still
+			 * warn the user.
+			 */
+
+		case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+			/* Continue after extension errors too */
+		case X509_V_ERR_INVALID_CA:
+		case X509_V_ERR_INVALID_NON_CA:
+		case X509_V_ERR_PATH_LENGTH_EXCEEDED:
+		case X509_V_ERR_INVALID_PURPOSE:
+		case X509_V_ERR_CRL_HAS_EXPIRED:
+		case X509_V_ERR_CRL_NOT_YET_VALID:
+		case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION:
+			ok = 1;
+
+		}
+
+		return ok;
+
+	}
+	if (cert_error == X509_V_OK && ok == 2)
+		policies_print(NULL, ctx);
+	if (!v_verbose)
+		ERR_clear_error();
+	return (ok);
+}
diff --git a/bin/openssl/version.c b/bin/openssl/version.c
new file mode 100644
index 0000000000..7e570044d2
--- /dev/null
+++ b/bin/openssl/version.c
@@ -0,0 +1,269 @@
+/* $OpenBSD: version.c,v 1.8 2015/10/17 15:00:11 doug Exp $ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2001 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include 
+#include 
+#include 
+
+#include "apps.h"
+
+#include 
+#include 
+#include 
+
+#ifndef OPENSSL_NO_BF
+#include 
+#endif
+
+#ifndef OPENSSL_NO_DES
+#include 
+#endif
+
+#ifndef OPENSSL_NO_IDEA
+#include 
+#endif
+
+#ifndef OPENSSL_NO_RC4
+#include 
+#endif
+
+static struct {
+	int cflags;
+	int date;
+	int dir;
+	int options;
+	int platform;
+	int version;
+} version_config;
+
+static int
+version_all_opts(void)
+{
+	version_config.cflags = 1;
+	version_config.date = 1;
+	version_config.dir= 1;
+	version_config.options = 1;
+	version_config.platform = 1;
+	version_config.version = 1;
+
+	return (0);
+}
+
+static struct option version_options[] = {
+	{
+		.name = "a",
+		.desc = "All information (same as setting all other flags)",
+		.type = OPTION_FUNC,
+		.opt.func = version_all_opts,
+	},
+	{
+		.name = "b",
+		.desc = "Date the current version of OpenSSL was built",
+		.type = OPTION_FLAG,
+		.opt.flag = &version_config.date,
+	},
+	{
+		.name = "d",
+		.desc = "OPENSSLDIR value",
+		.type = OPTION_FLAG,
+		.opt.flag = &version_config.dir,
+	},
+	{
+		.name = "f",
+		.desc = "Compilation flags",
+		.type = OPTION_FLAG,
+		.opt.flag = &version_config.cflags,
+	},
+	{
+		.name = "o",
+		.desc = "Option information",
+		.type = OPTION_FLAG,
+		.opt.flag = &version_config.options,
+	},
+	{
+		.name = "p",
+		.desc = "Platform settings",
+		.type = OPTION_FLAG,
+		.opt.flag = &version_config.platform,
+	},
+	{
+		.name = "v",
+		.desc = "Current OpenSSL version",
+		.type = OPTION_FLAG,
+		.opt.flag = &version_config.version,
+	},
+	{NULL},
+};
+
+static void
+version_usage(void)
+{
+	fprintf(stderr, "usage: version [-abdfopv]\n");
+	options_usage(version_options);
+}
+
+int
+version_main(int argc, char **argv)
+{
+	if (single_execution) {
+		if (pledge("stdio", NULL) == -1) {
+			perror("pledge");
+			exit(1);
+		}
+	}
+
+	memset(&version_config, 0, sizeof(version_config));
+
+	if (options_parse(argc, argv, version_options, NULL, NULL) != 0) {
+		version_usage();
+		return (1);
+	}
+
+	if (argc == 1)
+		version_config.version = 1;
+
+	if (version_config.version) {
+		if (SSLeay() == SSLEAY_VERSION_NUMBER) {
+			printf("%s\n", SSLeay_version(SSLEAY_VERSION));
+		} else {
+			printf("%s (Library: %s)\n",
+			    OPENSSL_VERSION_TEXT,
+			    SSLeay_version(SSLEAY_VERSION));
+		}
+	}
+	if (version_config.date)
+		printf("%s\n", SSLeay_version(SSLEAY_BUILT_ON));
+	if (version_config.platform)
+		printf("%s\n", SSLeay_version(SSLEAY_PLATFORM));
+	if (version_config.options) {
+		printf("options:  ");
+		printf("%s ", BN_options());
+#ifndef OPENSSL_NO_RC4
+		printf("%s ", RC4_options());
+#endif
+#ifndef OPENSSL_NO_DES
+		printf("%s ", DES_options());
+#endif
+#ifndef OPENSSL_NO_IDEA
+		printf("%s ", idea_options());
+#endif
+#ifndef OPENSSL_NO_BF
+		printf("%s ", BF_options());
+#endif
+		printf("\n");
+	}
+	if (version_config.cflags)
+		printf("%s\n", SSLeay_version(SSLEAY_CFLAGS));
+	if (version_config.dir)
+		printf("%s\n", SSLeay_version(SSLEAY_DIR));
+
+	return (0);
+}
diff --git a/bin/openssl/x509.c b/bin/openssl/x509.c
new file mode 100644
index 0000000000..f43b015684
--- /dev/null
+++ b/bin/openssl/x509.c
@@ -0,0 +1,1150 @@
+/* $OpenBSD: x509.c,v 1.14 2017/01/20 08:57:12 deraadt Exp $ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "apps.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+#include 
+
+#define	POSTFIX	".srl"
+#define DEF_DAYS	30
+
+static const char *x509_usage[] = {
+	"usage: x509 args\n",
+	" -inform arg     - input format - default PEM (one of DER, NET or PEM)\n",
+	" -outform arg    - output format - default PEM (one of DER, NET or PEM)\n",
+	" -keyform arg    - private key format - default PEM\n",
+	" -CAform arg     - CA format - default PEM\n",
+	" -CAkeyform arg  - CA key format - default PEM\n",
+	" -in arg         - input file - default stdin\n",
+	" -out arg        - output file - default stdout\n",
+	" -passin arg     - private key password source\n",
+	" -serial         - print serial number value\n",
+	" -subject_hash   - print subject hash value\n",
+#ifndef OPENSSL_NO_MD5
+	" -subject_hash_old   - print old-style (MD5) subject hash value\n",
+#endif
+	" -issuer_hash    - print issuer hash value\n",
+#ifndef OPENSSL_NO_MD5
+	" -issuer_hash_old    - print old-style (MD5) issuer hash value\n",
+#endif
+	" -hash           - synonym for -subject_hash\n",
+	" -subject        - print subject DN\n",
+	" -issuer         - print issuer DN\n",
+	" -email          - print email address(es)\n",
+	" -startdate      - notBefore field\n",
+	" -enddate        - notAfter field\n",
+	" -purpose        - print out certificate purposes\n",
+	" -dates          - both Before and After dates\n",
+	" -modulus        - print the RSA key modulus\n",
+	" -pubkey         - output the public key\n",
+	" -fingerprint    - print the certificate fingerprint\n",
+	" -alias          - output certificate alias\n",
+	" -noout          - no certificate output\n",
+	" -ocspid         - print OCSP hash values for the subject name and public key\n",
+	" -ocsp_uri       - print OCSP Responder URL(s)\n",
+	" -trustout       - output a \"trusted\" certificate\n",
+	" -clrtrust       - clear all trusted purposes\n",
+	" -clrreject      - clear all rejected purposes\n",
+	" -addtrust arg   - trust certificate for a given purpose\n",
+	" -addreject arg  - reject certificate for a given purpose\n",
+	" -setalias arg   - set certificate alias\n",
+	" -days arg       - How long till expiry of a signed certificate - def 30 days\n",
+	" -checkend arg   - check whether the cert expires in the next arg seconds\n",
+	"                   exit 1 if so, 0 if not\n",
+	" -signkey arg    - self sign cert with arg\n",
+	" -x509toreq      - output a certification request object\n",
+	" -req            - input is a certificate request, sign and output.\n",
+	" -CA arg         - set the CA certificate, must be PEM format.\n",
+	" -CAkey arg      - set the CA key, must be PEM format\n",
+	"                   missing, it is assumed to be in the CA file.\n",
+	" -CAcreateserial - create serial number file if it does not exist\n",
+	" -CAserial arg   - serial file\n",
+	" -set_serial     - serial number to use\n",
+	" -text           - print the certificate in text form\n",
+	" -C              - print out C code forms\n",
+	" -md5/-sha1      - digest to use\n",
+	" -extfile        - configuration file with X509V3 extensions to add\n",
+	" -extensions     - section from config file with X509V3 extensions to add\n",
+	" -clrext         - delete extensions before signing and input certificate\n",
+	" -nameopt arg    - various certificate name options\n",
+	" -certopt arg    - various certificate text options\n",
+	NULL
+};
+
+static int callb(int ok, X509_STORE_CTX *ctx);
+static int sign(X509 *x, EVP_PKEY *pkey, int days, int clrext,
+    const EVP_MD *digest, CONF *conf, char *section);
+static int x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest,
+    X509 *x, X509 *xca, EVP_PKEY *pkey, STACK_OF(OPENSSL_STRING) *sigopts,
+    char *serial, int create, int days, int clrext, CONF *conf, char *section,
+    ASN1_INTEGER *sno);
+static int purpose_print(BIO *bio, X509 *cert, X509_PURPOSE *pt);
+static int reqfile = 0;
+
+int
+x509_main(int argc, char **argv)
+{
+	int ret = 1;
+	X509_REQ *req = NULL;
+	X509 *x = NULL, *xca = NULL;
+	ASN1_OBJECT *objtmp;
+	STACK_OF(OPENSSL_STRING) *sigopts = NULL;
+	EVP_PKEY *Upkey = NULL, *CApkey = NULL;
+	ASN1_INTEGER *sno = NULL;
+	int i, num, badops = 0;
+	BIO *out = NULL;
+	BIO *STDout = NULL;
+	STACK_OF(ASN1_OBJECT) *trust = NULL, *reject = NULL;
+	int informat, outformat, keyformat, CAformat, CAkeyformat;
+	char *infile = NULL, *outfile = NULL, *keyfile = NULL, *CAfile = NULL;
+	char *CAkeyfile = NULL, *CAserial = NULL;
+	char *alias = NULL;
+	int text = 0, serial = 0, subject = 0, issuer = 0, startdate = 0,
+	    enddate = 0;
+	int next_serial = 0;
+	int subject_hash = 0, issuer_hash = 0, ocspid = 0;
+#ifndef OPENSSL_NO_MD5
+	int subject_hash_old = 0, issuer_hash_old = 0;
+#endif
+	int noout = 0, sign_flag = 0, CA_flag = 0, CA_createserial = 0,
+	    email = 0;
+	int ocsp_uri = 0;
+	int trustout = 0, clrtrust = 0, clrreject = 0, aliasout = 0, clrext = 0;
+	int C = 0;
+	int x509req = 0, days = DEF_DAYS, modulus = 0, pubkey = 0;
+	int pprint = 0;
+	const char **pp;
+	X509_STORE *ctx = NULL;
+	X509_REQ *rq = NULL;
+	int fingerprint = 0;
+	char buf[256];
+	const EVP_MD *md_alg, *digest = NULL;
+	CONF *extconf = NULL;
+	char *extsect = NULL, *extfile = NULL, *passin = NULL, *passargin = NULL;
+	int checkend = 0, checkoffset = 0;
+	unsigned long nmflag = 0, certflag = 0;
+	const char *errstr = NULL;
+
+	if (single_execution) {
+		if (pledge("stdio cpath wpath rpath tty", NULL) == -1) {
+			perror("pledge");
+			exit(1);
+		}
+	}
+
+	reqfile = 0;
+
+	STDout = BIO_new_fp(stdout, BIO_NOCLOSE);
+
+	informat = FORMAT_PEM;
+	outformat = FORMAT_PEM;
+	keyformat = FORMAT_PEM;
+	CAformat = FORMAT_PEM;
+	CAkeyformat = FORMAT_PEM;
+
+	ctx = X509_STORE_new();
+	if (ctx == NULL)
+		goto end;
+	X509_STORE_set_verify_cb(ctx, callb);
+
+	argc--;
+	argv++;
+	num = 0;
+	while (argc >= 1) {
+		if (strcmp(*argv, "-inform") == 0) {
+			if (--argc < 1)
+				goto bad;
+			informat = str2fmt(*(++argv));
+		} else if (strcmp(*argv, "-outform") == 0) {
+			if (--argc < 1)
+				goto bad;
+			outformat = str2fmt(*(++argv));
+		} else if (strcmp(*argv, "-keyform") == 0) {
+			if (--argc < 1)
+				goto bad;
+			keyformat = str2fmt(*(++argv));
+		} else if (strcmp(*argv, "-req") == 0) {
+			reqfile = 1;
+		} else if (strcmp(*argv, "-CAform") == 0) {
+			if (--argc < 1)
+				goto bad;
+			CAformat = str2fmt(*(++argv));
+		} else if (strcmp(*argv, "-CAkeyform") == 0) {
+			if (--argc < 1)
+				goto bad;
+			CAkeyformat = str2fmt(*(++argv));
+		} else if (strcmp(*argv, "-sigopt") == 0) {
+			if (--argc < 1)
+				goto bad;
+			if (!sigopts)
+				sigopts = sk_OPENSSL_STRING_new_null();
+			if (!sigopts || !sk_OPENSSL_STRING_push(sigopts, *(++argv)))
+				goto bad;
+		} else if (strcmp(*argv, "-days") == 0) {
+			if (--argc < 1)
+				goto bad;
+			days = strtonum(*(++argv), 1, INT_MAX, &errstr);
+			if (errstr) {
+				BIO_printf(bio_err, "bad number of days: %s\n", errstr);
+				goto bad;
+			}
+		} else if (strcmp(*argv, "-passin") == 0) {
+			if (--argc < 1)
+				goto bad;
+			passargin = *(++argv);
+		} else if (strcmp(*argv, "-extfile") == 0) {
+			if (--argc < 1)
+				goto bad;
+			extfile = *(++argv);
+		} else if (strcmp(*argv, "-extensions") == 0) {
+			if (--argc < 1)
+				goto bad;
+			extsect = *(++argv);
+		} else if (strcmp(*argv, "-in") == 0) {
+			if (--argc < 1)
+				goto bad;
+			infile = *(++argv);
+		} else if (strcmp(*argv, "-out") == 0) {
+			if (--argc < 1)
+				goto bad;
+			outfile = *(++argv);
+		} else if (strcmp(*argv, "-signkey") == 0) {
+			if (--argc < 1)
+				goto bad;
+			keyfile = *(++argv);
+			sign_flag = ++num;
+		} else if (strcmp(*argv, "-CA") == 0) {
+			if (--argc < 1)
+				goto bad;
+			CAfile = *(++argv);
+			CA_flag = ++num;
+		} else if (strcmp(*argv, "-CAkey") == 0) {
+			if (--argc < 1)
+				goto bad;
+			CAkeyfile = *(++argv);
+		} else if (strcmp(*argv, "-CAserial") == 0) {
+			if (--argc < 1)
+				goto bad;
+			CAserial = *(++argv);
+		} else if (strcmp(*argv, "-set_serial") == 0) {
+			if (--argc < 1)
+				goto bad;
+			ASN1_INTEGER_free(sno);
+			if (!(sno = s2i_ASN1_INTEGER(NULL, *(++argv))))
+				goto bad;
+		} else if (strcmp(*argv, "-addtrust") == 0) {
+			if (--argc < 1)
+				goto bad;
+			if (!(objtmp = OBJ_txt2obj(*(++argv), 0))) {
+				BIO_printf(bio_err,
+				    "Invalid trust object value %s\n", *argv);
+				goto bad;
+			}
+			if (!trust)
+				trust = sk_ASN1_OBJECT_new_null();
+			sk_ASN1_OBJECT_push(trust, objtmp);
+			trustout = 1;
+		} else if (strcmp(*argv, "-addreject") == 0) {
+			if (--argc < 1)
+				goto bad;
+			if (!(objtmp = OBJ_txt2obj(*(++argv), 0))) {
+				BIO_printf(bio_err,
+				    "Invalid reject object value %s\n", *argv);
+				goto bad;
+			}
+			if (!reject)
+				reject = sk_ASN1_OBJECT_new_null();
+			sk_ASN1_OBJECT_push(reject, objtmp);
+			trustout = 1;
+		} else if (strcmp(*argv, "-setalias") == 0) {
+			if (--argc < 1)
+				goto bad;
+			alias = *(++argv);
+			trustout = 1;
+		} else if (strcmp(*argv, "-certopt") == 0) {
+			if (--argc < 1)
+				goto bad;
+			if (!set_cert_ex(&certflag, *(++argv)))
+				goto bad;
+		} else if (strcmp(*argv, "-nameopt") == 0) {
+			if (--argc < 1)
+				goto bad;
+			if (!set_name_ex(&nmflag, *(++argv)))
+				goto bad;
+		}
+		else if (strcmp(*argv, "-C") == 0)
+			C = ++num;
+		else if (strcmp(*argv, "-email") == 0)
+			email = ++num;
+		else if (strcmp(*argv, "-ocsp_uri") == 0)
+			ocsp_uri = ++num;
+		else if (strcmp(*argv, "-serial") == 0)
+			serial = ++num;
+		else if (strcmp(*argv, "-next_serial") == 0)
+			next_serial = ++num;
+		else if (strcmp(*argv, "-modulus") == 0)
+			modulus = ++num;
+		else if (strcmp(*argv, "-pubkey") == 0)
+			pubkey = ++num;
+		else if (strcmp(*argv, "-x509toreq") == 0)
+			x509req = ++num;
+		else if (strcmp(*argv, "-text") == 0)
+			text = ++num;
+		else if (strcmp(*argv, "-hash") == 0 ||
+		    strcmp(*argv, "-subject_hash") == 0)
+			subject_hash = ++num;
+#ifndef OPENSSL_NO_MD5
+		else if (strcmp(*argv, "-subject_hash_old") == 0)
+			subject_hash_old = ++num;
+#endif
+		else if (strcmp(*argv, "-issuer_hash") == 0)
+			issuer_hash = ++num;
+#ifndef OPENSSL_NO_MD5
+		else if (strcmp(*argv, "-issuer_hash_old") == 0)
+			issuer_hash_old = ++num;
+#endif
+		else if (strcmp(*argv, "-subject") == 0)
+			subject = ++num;
+		else if (strcmp(*argv, "-issuer") == 0)
+			issuer = ++num;
+		else if (strcmp(*argv, "-fingerprint") == 0)
+			fingerprint = ++num;
+		else if (strcmp(*argv, "-dates") == 0) {
+			startdate = ++num;
+			enddate = ++num;
+		} else if (strcmp(*argv, "-purpose") == 0)
+			pprint = ++num;
+		else if (strcmp(*argv, "-startdate") == 0)
+			startdate = ++num;
+		else if (strcmp(*argv, "-enddate") == 0)
+			enddate = ++num;
+		else if (strcmp(*argv, "-checkend") == 0) {
+			if (--argc < 1)
+				goto bad;
+			checkoffset = strtonum(*(++argv), 0, INT_MAX, &errstr);
+			if (errstr) {
+				BIO_printf(bio_err, "checkend unusable: %s\n", errstr);
+				goto bad;
+			}
+			checkend = 1;
+		} else if (strcmp(*argv, "-noout") == 0)
+			noout = ++num;
+		else if (strcmp(*argv, "-trustout") == 0)
+			trustout = 1;
+		else if (strcmp(*argv, "-clrtrust") == 0)
+			clrtrust = ++num;
+		else if (strcmp(*argv, "-clrreject") == 0)
+			clrreject = ++num;
+		else if (strcmp(*argv, "-alias") == 0)
+			aliasout = ++num;
+		else if (strcmp(*argv, "-CAcreateserial") == 0)
+			CA_createserial = ++num;
+		else if (strcmp(*argv, "-clrext") == 0)
+			clrext = 1;
+		else if (strcmp(*argv, "-ocspid") == 0)
+			ocspid = ++num;
+		else if ((md_alg = EVP_get_digestbyname(*argv + 1))) {
+			/* ok */
+			digest = md_alg;
+		} else {
+			BIO_printf(bio_err, "unknown option %s\n", *argv);
+			badops = 1;
+			break;
+		}
+		argc--;
+		argv++;
+	}
+
+	if (badops) {
+bad:
+		for (pp = x509_usage; (*pp != NULL); pp++)
+			BIO_printf(bio_err, "%s", *pp);
+		goto end;
+	}
+
+	if (!app_passwd(bio_err, passargin, NULL, &passin, NULL)) {
+		BIO_printf(bio_err, "Error getting password\n");
+		goto end;
+	}
+	if (!X509_STORE_set_default_paths(ctx)) {
+		ERR_print_errors(bio_err);
+		goto end;
+	}
+	if ((CAkeyfile == NULL) && (CA_flag) && (CAformat == FORMAT_PEM)) {
+		CAkeyfile = CAfile;
+	} else if ((CA_flag) && (CAkeyfile == NULL)) {
+		BIO_printf(bio_err,
+		    "need to specify a CAkey if using the CA command\n");
+		goto end;
+	}
+	if (extfile) {
+		long errorline = -1;
+		X509V3_CTX ctx2;
+		extconf = NCONF_new(NULL);
+		if (!NCONF_load(extconf, extfile, &errorline)) {
+			if (errorline <= 0)
+				BIO_printf(bio_err,
+				    "error loading the config file '%s'\n",
+				    extfile);
+			else
+				BIO_printf(bio_err,
+				    "error on line %ld of config file '%s'\n",
+				    errorline, extfile);
+			goto end;
+		}
+		if (!extsect) {
+			extsect = NCONF_get_string(extconf, "default",
+			    "extensions");
+			if (!extsect) {
+				ERR_clear_error();
+				extsect = "default";
+			}
+		}
+		X509V3_set_ctx_test(&ctx2);
+		X509V3_set_nconf(&ctx2, extconf);
+		if (!X509V3_EXT_add_nconf(extconf, &ctx2, extsect, NULL)) {
+			BIO_printf(bio_err,
+			    "Error Loading extension section %s\n",
+			    extsect);
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+	}
+	if (reqfile) {
+		EVP_PKEY *pkey;
+		BIO *in;
+
+		if (!sign_flag && !CA_flag) {
+			BIO_printf(bio_err, "We need a private key to sign with\n");
+			goto end;
+		}
+		in = BIO_new(BIO_s_file());
+		if (in == NULL) {
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+		if (infile == NULL)
+			BIO_set_fp(in, stdin, BIO_NOCLOSE | BIO_FP_TEXT);
+		else {
+			if (BIO_read_filename(in, infile) <= 0) {
+				perror(infile);
+				BIO_free(in);
+				goto end;
+			}
+		}
+		req = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL);
+		BIO_free(in);
+
+		if (req == NULL) {
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+		if ((req->req_info == NULL) ||
+		    (req->req_info->pubkey == NULL) ||
+		    (req->req_info->pubkey->public_key == NULL) ||
+		    (req->req_info->pubkey->public_key->data == NULL)) {
+			BIO_printf(bio_err, "The certificate request appears to corrupted\n");
+			BIO_printf(bio_err, "It does not contain a public key\n");
+			goto end;
+		}
+		if ((pkey = X509_REQ_get_pubkey(req)) == NULL) {
+			BIO_printf(bio_err, "error unpacking public key\n");
+			goto end;
+		}
+		i = X509_REQ_verify(req, pkey);
+		EVP_PKEY_free(pkey);
+		if (i < 0) {
+			BIO_printf(bio_err, "Signature verification error\n");
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+		if (i == 0) {
+			BIO_printf(bio_err, "Signature did not match the certificate request\n");
+			goto end;
+		} else
+			BIO_printf(bio_err, "Signature ok\n");
+
+		print_name(bio_err, "subject=", X509_REQ_get_subject_name(req), nmflag);
+
+		if ((x = X509_new()) == NULL)
+			goto end;
+
+		if (sno == NULL) {
+			sno = ASN1_INTEGER_new();
+			if (!sno || !rand_serial(NULL, sno))
+				goto end;
+			if (!X509_set_serialNumber(x, sno))
+				goto end;
+			ASN1_INTEGER_free(sno);
+			sno = NULL;
+		} else if (!X509_set_serialNumber(x, sno))
+			goto end;
+
+		if (!X509_set_issuer_name(x, req->req_info->subject))
+			goto end;
+		if (!X509_set_subject_name(x, req->req_info->subject))
+			goto end;
+
+		X509_gmtime_adj(X509_get_notBefore(x), 0);
+		X509_time_adj_ex(X509_get_notAfter(x), days, 0, NULL);
+
+		pkey = X509_REQ_get_pubkey(req);
+		X509_set_pubkey(x, pkey);
+		EVP_PKEY_free(pkey);
+	} else
+		x = load_cert(bio_err, infile, informat, NULL, "Certificate");
+
+	if (x == NULL)
+		goto end;
+	if (CA_flag) {
+		xca = load_cert(bio_err, CAfile, CAformat, NULL, "CA Certificate");
+		if (xca == NULL)
+			goto end;
+	}
+	if (!noout || text || next_serial) {
+		OBJ_create("2.99999.3",
+		    "SET.ex3", "SET x509v3 extension 3");
+
+		out = BIO_new(BIO_s_file());
+		if (out == NULL) {
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+		if (outfile == NULL) {
+			BIO_set_fp(out, stdout, BIO_NOCLOSE);
+		} else {
+			if (BIO_write_filename(out, outfile) <= 0) {
+				perror(outfile);
+				goto end;
+			}
+		}
+	}
+	if (alias)
+		X509_alias_set1(x, (unsigned char *) alias, -1);
+
+	if (clrtrust)
+		X509_trust_clear(x);
+	if (clrreject)
+		X509_reject_clear(x);
+
+	if (trust) {
+		for (i = 0; i < sk_ASN1_OBJECT_num(trust); i++) {
+			objtmp = sk_ASN1_OBJECT_value(trust, i);
+			X509_add1_trust_object(x, objtmp);
+		}
+	}
+	if (reject) {
+		for (i = 0; i < sk_ASN1_OBJECT_num(reject); i++) {
+			objtmp = sk_ASN1_OBJECT_value(reject, i);
+			X509_add1_reject_object(x, objtmp);
+		}
+	}
+	if (num) {
+		for (i = 1; i <= num; i++) {
+			if (issuer == i) {
+				print_name(STDout, "issuer= ",
+				    X509_get_issuer_name(x), nmflag);
+			} else if (subject == i) {
+				print_name(STDout, "subject= ",
+				    X509_get_subject_name(x), nmflag);
+			} else if (serial == i) {
+				BIO_printf(STDout, "serial=");
+				i2a_ASN1_INTEGER(STDout,
+				    X509_get_serialNumber(x));
+				BIO_printf(STDout, "\n");
+			} else if (next_serial == i) {
+				BIGNUM *bnser;
+				ASN1_INTEGER *ser;
+				ser = X509_get_serialNumber(x);
+				bnser = ASN1_INTEGER_to_BN(ser, NULL);
+				if (!bnser)
+					goto end;
+				if (!BN_add_word(bnser, 1))
+					goto end;
+				ser = BN_to_ASN1_INTEGER(bnser, NULL);
+				if (!ser)
+					goto end;
+				BN_free(bnser);
+				i2a_ASN1_INTEGER(out, ser);
+				ASN1_INTEGER_free(ser);
+				BIO_puts(out, "\n");
+			} else if ((email == i) || (ocsp_uri == i)) {
+				int j;
+				STACK_OF(OPENSSL_STRING) *emlst;
+				if (email == i)
+					emlst = X509_get1_email(x);
+				else
+					emlst = X509_get1_ocsp(x);
+				for (j = 0; j < sk_OPENSSL_STRING_num(emlst); j++)
+					BIO_printf(STDout, "%s\n",
+					    sk_OPENSSL_STRING_value(emlst, j));
+				X509_email_free(emlst);
+			} else if (aliasout == i) {
+				unsigned char *alstr;
+				alstr = X509_alias_get0(x, NULL);
+				if (alstr)
+					BIO_printf(STDout, "%s\n", alstr);
+				else
+					BIO_puts(STDout, "\n");
+			} else if (subject_hash == i) {
+				BIO_printf(STDout, "%08lx\n", X509_subject_name_hash(x));
+			}
+#ifndef OPENSSL_NO_MD5
+			else if (subject_hash_old == i) {
+				BIO_printf(STDout, "%08lx\n", X509_subject_name_hash_old(x));
+			}
+#endif
+			else if (issuer_hash == i) {
+				BIO_printf(STDout, "%08lx\n", X509_issuer_name_hash(x));
+			}
+#ifndef OPENSSL_NO_MD5
+			else if (issuer_hash_old == i) {
+				BIO_printf(STDout, "%08lx\n", X509_issuer_name_hash_old(x));
+			}
+#endif
+			else if (pprint == i) {
+				X509_PURPOSE *ptmp;
+				int j;
+				BIO_printf(STDout, "Certificate purposes:\n");
+				for (j = 0; j < X509_PURPOSE_get_count(); j++) {
+					ptmp = X509_PURPOSE_get0(j);
+					purpose_print(STDout, x, ptmp);
+				}
+			} else if (modulus == i) {
+				EVP_PKEY *pkey;
+
+				pkey = X509_get_pubkey(x);
+				if (pkey == NULL) {
+					BIO_printf(bio_err, "Modulus=unavailable\n");
+					ERR_print_errors(bio_err);
+					goto end;
+				}
+				BIO_printf(STDout, "Modulus=");
+				if (pkey->type == EVP_PKEY_RSA)
+					BN_print(STDout, pkey->pkey.rsa->n);
+				else
+						if (pkey->type == EVP_PKEY_DSA)
+							BN_print(STDout, pkey->pkey.dsa->pub_key);
+				else
+						BIO_printf(STDout, "Wrong Algorithm type");
+				BIO_printf(STDout, "\n");
+				EVP_PKEY_free(pkey);
+			} else if (pubkey == i) {
+				EVP_PKEY *pkey;
+
+				pkey = X509_get_pubkey(x);
+				if (pkey == NULL) {
+					BIO_printf(bio_err, "Error getting public key\n");
+					ERR_print_errors(bio_err);
+					goto end;
+				}
+				PEM_write_bio_PUBKEY(STDout, pkey);
+				EVP_PKEY_free(pkey);
+			} else if (C == i) {
+				unsigned char *d;
+				char *m;
+				int y, z;
+
+				X509_NAME_oneline(X509_get_subject_name(x),
+				    buf, sizeof buf);
+				BIO_printf(STDout, "/* subject:%s */\n", buf);
+				m = X509_NAME_oneline(
+				    X509_get_issuer_name(x), buf,
+				    sizeof buf);
+				BIO_printf(STDout, "/* issuer :%s */\n", buf);
+
+				z = i2d_X509(x, NULL);
+				m = malloc(z);
+				if (m == NULL) {
+					BIO_printf(bio_err, "out of mem\n");
+					goto end;
+				}
+
+				d = (unsigned char *) m;
+				z = i2d_X509_NAME(X509_get_subject_name(x), &d);
+				BIO_printf(STDout, "unsigned char XXX_subject_name[%d]={\n", z);
+				d = (unsigned char *) m;
+				for (y = 0; y < z; y++) {
+					BIO_printf(STDout, "0x%02X,", d[y]);
+					if ((y & 0x0f) == 0x0f)
+						BIO_printf(STDout, "\n");
+				}
+				if (y % 16 != 0)
+					BIO_printf(STDout, "\n");
+				BIO_printf(STDout, "};\n");
+
+				z = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(x), &d);
+				BIO_printf(STDout, "unsigned char XXX_public_key[%d]={\n", z);
+				d = (unsigned char *) m;
+				for (y = 0; y < z; y++) {
+					BIO_printf(STDout, "0x%02X,", d[y]);
+					if ((y & 0x0f) == 0x0f)
+						BIO_printf(STDout, "\n");
+				}
+				if (y % 16 != 0)
+					BIO_printf(STDout, "\n");
+				BIO_printf(STDout, "};\n");
+
+				z = i2d_X509(x, &d);
+				BIO_printf(STDout, "unsigned char XXX_certificate[%d]={\n", z);
+				d = (unsigned char *) m;
+				for (y = 0; y < z; y++) {
+					BIO_printf(STDout, "0x%02X,", d[y]);
+					if ((y & 0x0f) == 0x0f)
+						BIO_printf(STDout, "\n");
+				}
+				if (y % 16 != 0)
+					BIO_printf(STDout, "\n");
+				BIO_printf(STDout, "};\n");
+
+				free(m);
+			} else if (text == i) {
+				X509_print_ex(STDout, x, nmflag, certflag);
+			} else if (startdate == i) {
+				BIO_puts(STDout, "notBefore=");
+				ASN1_TIME_print(STDout, X509_get_notBefore(x));
+				BIO_puts(STDout, "\n");
+			} else if (enddate == i) {
+				BIO_puts(STDout, "notAfter=");
+				ASN1_TIME_print(STDout, X509_get_notAfter(x));
+				BIO_puts(STDout, "\n");
+			} else if (fingerprint == i) {
+				int j;
+				unsigned int n;
+				unsigned char md[EVP_MAX_MD_SIZE];
+				const EVP_MD *fdig = digest;
+
+				if (!fdig)
+					fdig = EVP_sha1();
+
+				if (!X509_digest(x, fdig, md, &n)) {
+					BIO_printf(bio_err, "out of memory\n");
+					goto end;
+				}
+				BIO_printf(STDout, "%s Fingerprint=",
+				    OBJ_nid2sn(EVP_MD_type(fdig)));
+				for (j = 0; j < (int) n; j++) {
+					BIO_printf(STDout, "%02X%c", md[j],
+					    (j + 1 == (int)n) ? '\n' : ':');
+				}
+			}
+			/* should be in the library */
+			else if ((sign_flag == i) && (x509req == 0)) {
+				BIO_printf(bio_err, "Getting Private key\n");
+				if (Upkey == NULL) {
+					Upkey = load_key(bio_err,
+					    keyfile, keyformat, 0,
+					    passin, "Private key");
+					if (Upkey == NULL)
+						goto end;
+				}
+				if (!sign(x, Upkey, days, clrext, digest,
+				    extconf, extsect))
+					goto end;
+			} else if (CA_flag == i) {
+				BIO_printf(bio_err, "Getting CA Private Key\n");
+				if (CAkeyfile != NULL) {
+					CApkey = load_key(bio_err,
+					    CAkeyfile, CAkeyformat,
+					    0, passin, "CA Private Key");
+					if (CApkey == NULL)
+						goto end;
+				}
+				if (!x509_certify(ctx, CAfile, digest, x, xca,
+				    CApkey, sigopts,
+				    CAserial, CA_createserial, days, clrext,
+				    extconf, extsect, sno))
+					goto end;
+			} else if (x509req == i) {
+				EVP_PKEY *pk;
+
+				BIO_printf(bio_err, "Getting request Private Key\n");
+				if (keyfile == NULL) {
+					BIO_printf(bio_err, "no request key file specified\n");
+					goto end;
+				} else {
+					pk = load_key(bio_err,
+					    keyfile, keyformat, 0,
+					    passin, "request key");
+					if (pk == NULL)
+						goto end;
+				}
+
+				BIO_printf(bio_err, "Generating certificate request\n");
+
+				rq = X509_to_X509_REQ(x, pk, digest);
+				EVP_PKEY_free(pk);
+				if (rq == NULL) {
+					ERR_print_errors(bio_err);
+					goto end;
+				}
+				if (!noout) {
+					X509_REQ_print(out, rq);
+					PEM_write_bio_X509_REQ(out, rq);
+				}
+				noout = 1;
+			} else if (ocspid == i) {
+				X509_ocspid_print(out, x);
+			}
+		}
+	}
+	if (checkend) {
+		time_t tcheck = time(NULL) + checkoffset;
+
+		if (X509_cmp_time(X509_get_notAfter(x), &tcheck) < 0) {
+			BIO_printf(out, "Certificate will expire\n");
+			ret = 1;
+		} else {
+			BIO_printf(out, "Certificate will not expire\n");
+			ret = 0;
+		}
+		goto end;
+	}
+	if (noout) {
+		ret = 0;
+		goto end;
+	}
+	if (outformat == FORMAT_ASN1)
+		i = i2d_X509_bio(out, x);
+	else if (outformat == FORMAT_PEM) {
+		if (trustout)
+			i = PEM_write_bio_X509_AUX(out, x);
+		else
+			i = PEM_write_bio_X509(out, x);
+	} else if (outformat == FORMAT_NETSCAPE) {
+		NETSCAPE_X509 nx;
+		ASN1_OCTET_STRING hdr;
+
+		hdr.data = (unsigned char *) NETSCAPE_CERT_HDR;
+		hdr.length = strlen(NETSCAPE_CERT_HDR);
+		nx.header = &hdr;
+		nx.cert = x;
+
+		i = ASN1_item_i2d_bio(&NETSCAPE_X509_it, out, &nx);
+	} else {
+		BIO_printf(bio_err, "bad output format specified for outfile\n");
+		goto end;
+	}
+	if (!i) {
+		BIO_printf(bio_err, "unable to write certificate\n");
+		ERR_print_errors(bio_err);
+		goto end;
+	}
+	ret = 0;
+
+end:
+	OBJ_cleanup();
+	NCONF_free(extconf);
+	BIO_free_all(out);
+	BIO_free_all(STDout);
+	X509_STORE_free(ctx);
+	X509_REQ_free(req);
+	X509_free(x);
+	X509_free(xca);
+	EVP_PKEY_free(Upkey);
+	EVP_PKEY_free(CApkey);
+	if (sigopts)
+		sk_OPENSSL_STRING_free(sigopts);
+	X509_REQ_free(rq);
+	ASN1_INTEGER_free(sno);
+	sk_ASN1_OBJECT_pop_free(trust, ASN1_OBJECT_free);
+	sk_ASN1_OBJECT_pop_free(reject, ASN1_OBJECT_free);
+	free(passin);
+
+	return (ret);
+}
+
+static ASN1_INTEGER *
+x509_load_serial(char *CAfile, char *serialfile, int create)
+{
+	char *buf = NULL, *p;
+	ASN1_INTEGER *bs = NULL;
+	BIGNUM *serial = NULL;
+	size_t len;
+
+	len = ((serialfile == NULL) ? (strlen(CAfile) + strlen(POSTFIX) + 1) :
+	    (strlen(serialfile))) + 1;
+	buf = malloc(len);
+	if (buf == NULL) {
+		BIO_printf(bio_err, "out of mem\n");
+		goto end;
+	}
+	if (serialfile == NULL) {
+		strlcpy(buf, CAfile, len);
+		for (p = buf; *p; p++)
+			if (*p == '.') {
+				*p = '\0';
+				break;
+			}
+		strlcat(buf, POSTFIX, len);
+	} else
+		strlcpy(buf, serialfile, len);
+
+	serial = load_serial(buf, create, NULL);
+	if (serial == NULL)
+		goto end;
+
+	if (!BN_add_word(serial, 1)) {
+		BIO_printf(bio_err, "add_word failure\n");
+		goto end;
+	}
+	if (!save_serial(buf, NULL, serial, &bs))
+		goto end;
+
+end:
+	free(buf);
+	BN_free(serial);
+
+	return bs;
+}
+
+static int
+x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest, X509 *x,
+    X509 *xca, EVP_PKEY *pkey, STACK_OF(OPENSSL_STRING) *sigopts,
+    char *serialfile, int create, int days, int clrext, CONF *conf,
+    char *section, ASN1_INTEGER *sno)
+{
+	int ret = 0;
+	ASN1_INTEGER *bs = NULL;
+	X509_STORE_CTX xsc;
+	EVP_PKEY *upkey;
+
+	upkey = X509_get_pubkey(xca);
+	EVP_PKEY_copy_parameters(upkey, pkey);
+	EVP_PKEY_free(upkey);
+
+	if (!X509_STORE_CTX_init(&xsc, ctx, x, NULL)) {
+		BIO_printf(bio_err, "Error initialising X509 store\n");
+		goto end;
+	}
+	if (sno)
+		bs = sno;
+	else if (!(bs = x509_load_serial(CAfile, serialfile, create)))
+		goto end;
+
+/*	if (!X509_STORE_add_cert(ctx,x)) goto end;*/
+
+	/*
+	 * NOTE: this certificate can/should be self signed, unless it was a
+	 * certificate request in which case it is not.
+	 */
+	X509_STORE_CTX_set_cert(&xsc, x);
+	X509_STORE_CTX_set_flags(&xsc, X509_V_FLAG_CHECK_SS_SIGNATURE);
+	if (!reqfile && X509_verify_cert(&xsc) <= 0)
+		goto end;
+
+	if (!X509_check_private_key(xca, pkey)) {
+		BIO_printf(bio_err, "CA certificate and CA private key do not match\n");
+		goto end;
+	}
+	if (!X509_set_issuer_name(x, X509_get_subject_name(xca)))
+		goto end;
+	if (!X509_set_serialNumber(x, bs))
+		goto end;
+
+	if (X509_gmtime_adj(X509_get_notBefore(x), 0L) == NULL)
+		goto end;
+
+	/* hardwired expired */
+	if (X509_time_adj_ex(X509_get_notAfter(x), days, 0, NULL) == NULL)
+		goto end;
+
+	if (clrext) {
+		while (X509_get_ext_count(x) > 0)
+			X509_delete_ext(x, 0);
+	}
+	if (conf) {
+		X509V3_CTX ctx2;
+		X509_set_version(x, 2);	/* version 3 certificate */
+		X509V3_set_ctx(&ctx2, xca, x, NULL, NULL, 0);
+		X509V3_set_nconf(&ctx2, conf);
+		if (!X509V3_EXT_add_nconf(conf, &ctx2, section, x))
+			goto end;
+	}
+	if (!do_X509_sign(bio_err, x, pkey, digest, sigopts))
+		goto end;
+	ret = 1;
+end:
+	X509_STORE_CTX_cleanup(&xsc);
+	if (!ret)
+		ERR_print_errors(bio_err);
+	if (!sno)
+		ASN1_INTEGER_free(bs);
+	return ret;
+}
+
+static int
+callb(int ok, X509_STORE_CTX *ctx)
+{
+	int err;
+	X509 *err_cert;
+
+	/*
+	 * it is ok to use a self signed certificate This case will catch
+	 * both the initial ok == 0 and the final ok == 1 calls to this
+	 * function
+	 */
+	err = X509_STORE_CTX_get_error(ctx);
+	if (err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)
+		return 1;
+
+	/*
+	 * BAD we should have gotten an error.  Normally if everything worked
+	 * X509_STORE_CTX_get_error(ctx) will still be set to
+	 * DEPTH_ZERO_SELF_....
+	 */
+	if (ok) {
+		BIO_printf(bio_err, "error with certificate to be certified - should be self signed\n");
+		return 0;
+	} else {
+		err_cert = X509_STORE_CTX_get_current_cert(ctx);
+		print_name(bio_err, NULL, X509_get_subject_name(err_cert), 0);
+		BIO_printf(bio_err, "error with certificate - error %d at depth %d\n%s\n",
+		    err, X509_STORE_CTX_get_error_depth(ctx),
+		    X509_verify_cert_error_string(err));
+		return 1;
+	}
+}
+
+/* self sign */
+static int
+sign(X509 *x, EVP_PKEY *pkey, int days, int clrext, const EVP_MD *digest,
+    CONF *conf, char *section)
+{
+
+	EVP_PKEY *pktmp;
+
+	pktmp = X509_get_pubkey(x);
+	EVP_PKEY_copy_parameters(pktmp, pkey);
+	EVP_PKEY_save_parameters(pktmp, 1);
+	EVP_PKEY_free(pktmp);
+
+	if (!X509_set_issuer_name(x, X509_get_subject_name(x)))
+		goto err;
+	if (X509_gmtime_adj(X509_get_notBefore(x), 0) == NULL)
+		goto err;
+
+	/* Lets just make it 12:00am GMT, Jan 1 1970 */
+	/* memcpy(x->cert_info->validity->notBefore,"700101120000Z",13); */
+	/* 28 days to be certified */
+
+	if (X509_gmtime_adj(X509_get_notAfter(x),
+	    (long) 60 * 60 * 24 * days) == NULL)
+		goto err;
+
+	if (!X509_set_pubkey(x, pkey))
+		goto err;
+	if (clrext) {
+		while (X509_get_ext_count(x) > 0)
+			X509_delete_ext(x, 0);
+	}
+	if (conf) {
+		X509V3_CTX ctx;
+		X509_set_version(x, 2);	/* version 3 certificate */
+		X509V3_set_ctx(&ctx, x, x, NULL, NULL, 0);
+		X509V3_set_nconf(&ctx, conf);
+		if (!X509V3_EXT_add_nconf(conf, &ctx, section, x))
+			goto err;
+	}
+	if (!X509_sign(x, pkey, digest))
+		goto err;
+	return 1;
+
+err:
+	ERR_print_errors(bio_err);
+	return 0;
+}
+
+static int
+purpose_print(BIO *bio, X509 *cert, X509_PURPOSE *pt)
+{
+	int id, i, idret;
+	char *pname;
+
+	id = X509_PURPOSE_get_id(pt);
+	pname = X509_PURPOSE_get0_name(pt);
+	for (i = 0; i < 2; i++) {
+		idret = X509_check_purpose(cert, id, i);
+		BIO_printf(bio, "%s%s : ", pname, i ? " CA" : "");
+		if (idret == 1)
+			BIO_printf(bio, "Yes\n");
+		else if (idret == 0)
+			BIO_printf(bio, "No\n");
+		else
+			BIO_printf(bio, "Yes (WARNING code=%d)\n", idret);
+	}
+	return 1;
+}
diff --git a/lib/libcrypto/compat/include/unistd.h b/lib/libcrypto/compat/include/unistd.h
new file mode 100644
index 0000000000..d596043318
--- /dev/null
+++ b/lib/libcrypto/compat/include/unistd.h
@@ -0,0 +1,52 @@
+/*
+ * Public domain
+ * unistd.h compatibility shim
+ */
+
+#ifndef LIBCRYPTOCOMPAT_UNISTD_H
+#define LIBCRYPTOCOMPAT_UNISTD_H
+
+#ifndef _MSC_VER
+#include_next 
+#else
+
+#include 
+#include 
+#include 
+
+#define STDOUT_FILENO   1
+#define STDERR_FILENO   2
+
+#define R_OK    4
+#define W_OK    2
+#define X_OK    0
+#define F_OK    0
+
+#define access _access
+
+unsigned int sleep(unsigned int seconds);
+
+#endif
+
+#ifndef HAVE_GETENTROPY
+int getentropy(void *buf, size_t buflen);
+#else
+/*
+ * Solaris 11.3 adds getentropy(2), but defines the function in sys/random.h
+ */
+#if defined(__sun)
+#include 
+#endif
+#endif
+
+#ifndef HAVE_GETPAGESIZE
+int getpagesize(void);
+#endif
+
+#define pledge(request, paths) 0
+
+#ifndef HAVE_PIPE2
+int pipe2(int fildes[2], int flags);
+#endif
+
+#endif
diff --git a/lib/libcrypto/compat/strtonum.c b/lib/libcrypto/compat/strtonum.c
new file mode 100644
index 0000000000..fdfc72aa77
--- /dev/null
+++ b/lib/libcrypto/compat/strtonum.c
@@ -0,0 +1,65 @@
+/*	$OpenBSD: strtonum.c,v 1.8 2015/09/13 08:31:48 guenther Exp $	*/
+
+/*
+ * Copyright (c) 2004 Ted Unangst and Todd Miller
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include 
+#include 
+#include 
+
+#define	INVALID		1
+#define	TOOSMALL	2
+#define	TOOLARGE	3
+
+long long
+strtonum(const char *numstr, long long minval, long long maxval,
+    const char **errstrp)
+{
+	long long ll = 0;
+	int error = 0;
+	char *ep;
+	struct errval {
+		const char *errstr;
+		int err;
+	} ev[4] = {
+		{ NULL,		0 },
+		{ "invalid",	EINVAL },
+		{ "too small",	ERANGE },
+		{ "too large",	ERANGE },
+	};
+
+	ev[0].err = errno;
+	errno = 0;
+	if (minval > maxval) {
+		error = INVALID;
+	} else {
+		ll = strtoll(numstr, &ep, 10);
+		if (numstr == ep || *ep != '\0')
+			error = INVALID;
+		else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
+			error = TOOSMALL;
+		else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
+			error = TOOLARGE;
+	}
+	if (errstrp != NULL)
+		*errstrp = ev[error].errstr;
+	errno = ev[error].err;
+	if (error)
+		ll = 0;
+
+	return (ll);
+}
-- 
2.11.4.GIT