diff options
author | Joel Sing <jsing@cvs.openbsd.org> | 2014-08-26 17:47:26 +0000 |
---|---|---|
committer | Joel Sing <jsing@cvs.openbsd.org> | 2014-08-26 17:47:26 +0000 |
commit | a6b47bad9ae41254c2cc1011e5b345a9ad2775d9 (patch) | |
tree | 56383c4b44d5f037c16071db502c96b6b0291b7c /usr.bin/openssl | |
parent | d682cf53164afe080147f62557681fac8abc7150 (diff) |
Move openssl(1) from /usr/sbin/openssl to /usr/bin/openssl, since it is not
a system/superuser binary. At the same time, move the source code from its
current lib/libssl/src/apps location to a more appropriate home under
usr.bin/openssl.
ok deraadt@ miod@
Diffstat (limited to 'usr.bin/openssl')
57 files changed, 44053 insertions, 0 deletions
diff --git a/usr.bin/openssl/Makefile b/usr.bin/openssl/Makefile new file mode 100644 index 00000000000..f4c9ed4f2b2 --- /dev/null +++ b/usr.bin/openssl/Makefile @@ -0,0 +1,27 @@ +# $OpenBSD: Makefile,v 1.1 2014/08/26 17:47:24 jsing 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 asn1pars.c ca.c ciphers.c cms.c crl.c crl2p7.c dgst.c dh.c \ + dhparam.c dsa.c dsaparam.c ec.c ecparam.c enc.c engine.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 <bsd.prog.mk> diff --git a/usr.bin/openssl/apps.c b/usr.bin/openssl/apps.c new file mode 100644 index 00000000000..ac1c5107f11 --- /dev/null +++ b/usr.bin/openssl/apps.c @@ -0,0 +1,2220 @@ +/* $OpenBSD: apps.c,v 1.1 2014/08/26 17:47:24 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 <sys/types.h> +#include <sys/stat.h> +#include <sys/times.h> + +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include <strings.h> +#include <unistd.h> + +#include "apps.h" + +#include <openssl/bn.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/pkcs12.h> +#include <openssl/safestack.h> +#include <openssl/ui.h> +#include <openssl/x509.h> +#include <openssl/x509v3.h> + +#ifndef OPENSSL_NO_ENGINE +#include <openssl/engine.h> +#endif + +#include <openssl/rsa.h> + +typedef struct { + const char *name; + unsigned long flag; + unsigned long mask; +} NAME_EX_TBL; + +static 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 == 'E') || (*s == 'e')) + return (FORMAT_ENGINE); + 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 *)); + } + 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; +} + +static int +ui_open(UI *ui) +{ + return UI_method_get_opener(UI_OpenSSL()) (ui); +} + +static int +ui_read(UI *ui, UI_STRING *uis) +{ + if (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD && + UI_get0_user_data(ui)) { + switch (UI_get_string_type(uis)) { + case UIT_PROMPT: + case UIT_VERIFY: + { + const char *password = + ((PW_CB_DATA *)UI_get0_user_data(ui))->password; + if (password && password[0] != '\0') { + UI_set_result(ui, uis, password); + return 1; + } + } + break; + default: + break; + } + } + return UI_method_get_reader(UI_OpenSSL()) (ui, uis); +} + +static int +ui_write(UI *ui, UI_STRING *uis) +{ + if (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD && + UI_get0_user_data(ui)) { + switch (UI_get_string_type(uis)) { + case UIT_PROMPT: + case UIT_VERIFY: + { + const char *password = + ((PW_CB_DATA *)UI_get0_user_data(ui))->password; + if (password && password[0] != '\0') + return 1; + } + break; + default: + break; + } + } + return UI_method_get_writer(UI_OpenSSL()) (ui, uis); +} + +static int +ui_close(UI *ui) +{ + return UI_method_get_closer(UI_OpenSSL()) (ui); +} + +int +setup_ui_method(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_method(void) +{ + if (ui_method) { + UI_destroy_method(ui_method); + ui_method = NULL; + } +} + +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) { + OPENSSL_cleanse(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); + OPENSSL_cleanse(buf, (unsigned int) bufsiz); + res = 0; + } + if (ok == -2) { + BIO_printf(bio_err, "aborted!\n"); + OPENSSL_cleanse(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, ENGINE *e, + 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(ASN1_ITEM_rptr(NETSCAPE_X509), + 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, ENGINE *e, 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 || format == FORMAT_ENGINE)) { + BIO_printf(err, "no keyfile specified\n"); + goto end; + } +#ifndef OPENSSL_NO_ENGINE + if (format == FORMAT_ENGINE) { + if (!e) + BIO_printf(err, "no engine specified\n"); + else { + pkey = ENGINE_load_private_key(e, file, + ui_method, &cb_data); + if (!pkey) { + BIO_printf(err, "cannot load %s from engine\n", + key_descrip); + ERR_print_errors(err); + } + } + goto end; + } +#endif + 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, ENGINE *e, 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 || format == FORMAT_ENGINE)) { + BIO_printf(err, "no keyfile specified\n"); + goto end; + } +#ifndef OPENSSL_NO_ENGINE + if (format == FORMAT_ENGINE) { + if (!e) + BIO_printf(bio_err, "no engine specified\n"); + else + pkey = ENGINE_load_public_key(e, file, + ui_method, &cb_data); + goto end; + } +#endif + 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, + ENGINE *e, 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, + ENGINE *e, const char *desc) +{ + STACK_OF(X509) *certs; + + if (!load_certs_crls(err, file, format, pass, e, desc, &certs, NULL)) + return NULL; + return certs; +} + +STACK_OF(X509_CRL) * +load_crls(BIO *err, const char *file, int format, const char *pass, ENGINE *e, + const char *desc) +{ + STACK_OF(X509_CRL) *crls; + + if (!load_certs_crls(err, file, format, pass, e, 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; +} + +#ifndef OPENSSL_NO_ENGINE +/* Try to load an engine in a shareable library */ +static ENGINE * +try_load_engine(BIO *err, const char *engine, int debug) +{ + ENGINE *e = ENGINE_by_id("dynamic"); + + if (e) { + if (!ENGINE_ctrl_cmd_string(e, "SO_PATH", engine, 0) || + !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0)) { + ENGINE_free(e); + e = NULL; + } + } + return e; +} + +ENGINE * +setup_engine(BIO *err, const char *engine, int debug) +{ + ENGINE *e = NULL; + + if (engine) { + if (strcmp(engine, "auto") == 0) { + BIO_printf(err, "enabling auto ENGINE support\n"); + ENGINE_register_all_complete(); + return NULL; + } + if ((e = ENGINE_by_id(engine)) == NULL && + (e = try_load_engine(err, engine, debug)) == NULL) { + BIO_printf(err, "invalid engine \"%s\"\n", engine); + ERR_print_errors(err); + return NULL; + } + if (debug) { + ENGINE_ctrl(e, ENGINE_CTRL_SET_LOGSTREAM, + 0, err, 0); + } + ENGINE_ctrl_cmd(e, "SET_USER_INTERFACE", 0, ui_method, 0, 1); + if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { + BIO_printf(err, "can't use that engine\n"); + ERR_print_errors(err); + ENGINE_free(e); + return NULL; + } + BIO_printf(err, "engine \"%s\" set.\n", ENGINE_get_id(e)); + + /* Free our "structural" reference. */ + ENGINE_free(e); + } + return e; +} +#endif + +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) + +#define BSIZE 256 + +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, 1024)) { + 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 buf[1][BSIZE]; + BIO *out = NULL; + int ret = 0, n; + ASN1_INTEGER *ai = NULL; + int j; + + if (suffix == NULL) + j = strlen(serialfile); + else + j = strlen(serialfile) + strlen(suffix) + 1; + if (j >= BSIZE) { + BIO_printf(bio_err, "file name too long\n"); + goto err; + } + if (suffix == NULL) + n = strlcpy(buf[0], serialfile, BSIZE); + else + n = snprintf(buf[0], sizeof buf[0], "%s.%s", + serialfile, suffix); + if (n == -1 || n >= sizeof(buf[0])) { + 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, buf[0]) <= 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 buf[5][BSIZE]; + int i, j; + + i = strlen(serialfile) + strlen(old_suffix); + j = strlen(serialfile) + strlen(new_suffix); + if (i > j) + j = i; + if (j + 1 >= BSIZE) { + BIO_printf(bio_err, "file name too long\n"); + goto err; + } + snprintf(buf[0], sizeof buf[0], "%s.%s", serialfile, new_suffix); + snprintf(buf[1], sizeof buf[1], "%s.%s", serialfile, old_suffix); + + + if (rename(serialfile, buf[1]) < 0 && + errno != ENOENT && errno != ENOTDIR) { + BIO_printf(bio_err, "unable to rename %s to %s\n", + serialfile, buf[1]); + perror("reason"); + goto err; + } + + + if (rename(buf[0], serialfile) < 0) { + BIO_printf(bio_err, "unable to rename %s to %s\n", + buf[0], serialfile); + perror("reason"); + rename(buf[1], serialfile); + 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 buf[1][BSIZE]; + 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; + + snprintf(buf[0], sizeof buf[0], "%s.attr", dbfile); + dbattr_conf = NCONF_new(NULL); + if (NCONF_load(dbattr_conf, buf[0], &errorline) <= 0) { + if (errorline > 0) { + BIO_printf(bio_err, + "error on line %ld of db attribute file '%s'\n", + errorline, buf[0]); + 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 *dbfile, const char *suffix, CA_DB *db) +{ + char buf[3][BSIZE]; + BIO *out = BIO_new(BIO_s_file()); + int j; + + if (out == NULL) { + ERR_print_errors(bio_err); + goto err; + } + j = strlen(dbfile) + strlen(suffix); + if (j + 6 >= BSIZE) { + BIO_printf(bio_err, "file name too long\n"); + goto err; + } + snprintf(buf[2], sizeof buf[2], "%s.attr", dbfile); + snprintf(buf[1], sizeof buf[1], "%s.attr.%s", dbfile, suffix); + snprintf(buf[0], sizeof buf[0], "%s.%s", dbfile, suffix); + + + if (BIO_write_filename(out, buf[0]) <= 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, buf[1]) <= 0) { + perror(buf[2]); + BIO_printf(bio_err, "unable to open '%s'\n", buf[2]); + 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 buf[5][BSIZE]; + int i, j; + + i = strlen(dbfile) + strlen(old_suffix); + j = strlen(dbfile) + strlen(new_suffix); + if (i > j) + j = i; + if (j + 6 >= BSIZE) { + BIO_printf(bio_err, "file name too long\n"); + goto err; + } + snprintf(buf[4], sizeof buf[4], "%s.attr", dbfile); + snprintf(buf[2], sizeof buf[2], "%s.attr.%s", dbfile, new_suffix); + snprintf(buf[0], sizeof buf[0], "%s.%s", dbfile, new_suffix); + snprintf(buf[1], sizeof buf[1], "%s.%s", dbfile, old_suffix); + snprintf(buf[3], sizeof buf[3], "%s.attr.%s", dbfile, old_suffix); + + + if (rename(dbfile, buf[1]) < 0 && errno != ENOENT && errno != ENOTDIR) { + BIO_printf(bio_err, "unable to rename %s to %s\n", + dbfile, buf[1]); + perror("reason"); + goto err; + } + + + if (rename(buf[0], dbfile) < 0) { + BIO_printf(bio_err, "unable to rename %s to %s\n", + buf[0], dbfile); + perror("reason"); + rename(buf[1], dbfile); + goto err; + } + + + if (rename(buf[4], buf[3]) < 0 && errno != ENOENT && errno != ENOTDIR) { + BIO_printf(bio_err, "unable to rename %s to %s\n", + buf[4], buf[3]); + perror("reason"); + rename(dbfile, buf[0]); + rename(buf[1], dbfile); + goto err; + } + + + if (rename(buf[2], buf[4]) < 0) { + BIO_printf(bio_err, "unable to rename %s to %s\n", + buf[2], buf[4]); + perror("reason"); + rename(buf[3], buf[4]); + rename(dbfile, buf[0]); + rename(buf[1], dbfile); + 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 mutlivalued 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); + 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; + + 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; + + stmp = BUF_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, " <empty>\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); +} + +#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) +/* 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; +} +#endif +/* !OPENSSL_NO_TLSEXT && !OPENSSL_NO_NEXTPROTONEG */ + +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 +app_isdir(const char *name) +{ + struct stat st; + + if (stat(name, &st) == 0) + return S_ISDIR(st.st_mode); + return -1; +} diff --git a/usr.bin/openssl/apps.h b/usr.bin/openssl/apps.h new file mode 100644 index 00000000000..38c5f4be8c8 --- /dev/null +++ b/usr.bin/openssl/apps.h @@ -0,0 +1,285 @@ +/* $OpenBSD: apps.h,v 1.1 2014/08/26 17:47:24 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). + * + */ + +#ifndef HEADER_APPS_H +#define HEADER_APPS_H + +#include <openssl/opensslconf.h> + +#include <openssl/bio.h> +#include <openssl/conf.h> +#include <openssl/lhash.h> +#include <openssl/ossl_typ.h> +#include <openssl/txt_db.h> +#include <openssl/x509.h> + +#ifndef OPENSSL_NO_ENGINE +#include <openssl/engine.h> +#endif + +#ifndef OPENSSL_NO_OCSP +#include <openssl/ocsp.h> +#endif + +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_method(void); +void destroy_ui_method(void); + +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, ENGINE *e, const char *cert_descrip); +EVP_PKEY *load_key(BIO *err, const char *file, int format, int maybe_stdin, + const char *pass, ENGINE *e, const char *key_descrip); +EVP_PKEY *load_pubkey(BIO *err, const char *file, int format, int maybe_stdin, + const char *pass, ENGINE *e, const char *key_descrip); +STACK_OF(X509) *load_certs(BIO *err, const char *file, int format, + const char *pass, ENGINE *e, const char *cert_descrip); +STACK_OF(X509_CRL) *load_crls(BIO *err, const char *file, int format, + const char *pass, ENGINE *e, const char *cert_descrip); +X509_STORE *setup_verify(BIO *bp, char *CAfile, char *CApath); +#ifndef OPENSSL_NO_ENGINE +ENGINE *setup_engine(BIO *err, const char *engine, int debug); +#endif + +#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, ENGINE *e, + 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); + +#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) +unsigned char *next_protos_parse(unsigned short *outlen, const char *in); +#endif /* !OPENSSL_NO_TLSEXT && !OPENSSL_NO_NEXTPROTONEG */ + +#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_ENGINE 7 +#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 + +#endif diff --git a/usr.bin/openssl/asn1pars.c b/usr.bin/openssl/asn1pars.c new file mode 100644 index 00000000000..6ba43afb974 --- /dev/null +++ b/usr.bin/openssl/asn1pars.c @@ -0,0 +1,406 @@ +/* $OpenBSD: asn1pars.c,v 1.1 2014/08/26 17:47:24 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.] + */ + +/* A nice addition from Dr Stephen Henson <steve@openssl.org> to + * add the -strparse option which parses nested binary structures + */ + +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/pem.h> +#include <openssl/x509.h> + +/* -inform arg - input format - default PEM (DER or PEM) + * -in arg - input file - default stdin + * -i - indent the details by depth + * -offset - where in the file to start + * -length - how many bytes to use + * -oid file - extra oid description file + */ + +int asn1parse_main(int, char **); + +static int do_generate(BIO * bio, char *genstr, char *genconf, BUF_MEM * buf); + +int +asn1parse_main(int argc, char **argv) +{ + int i, badops = 0, offset = 0, ret = 1, j; + unsigned int length = 0; + long num, tmplen; + BIO *in = NULL, *out = NULL, *b64 = NULL, *derout = NULL; + int informat, indent = 0, noout = 0, dump = 0; + char *infile = NULL, *str = NULL, *prog, *oidfile = NULL, *derfile = NULL; + char *genstr = NULL, *genconf = NULL; + const char *errstr = NULL; + unsigned char *tmpbuf; + const unsigned char *ctmpbuf; + BUF_MEM *buf = NULL; + STACK_OF(OPENSSL_STRING) * osk = NULL; + ASN1_TYPE *at = NULL; + + informat = FORMAT_PEM; + + prog = argv[0]; + argc--; + argv++; + if ((osk = sk_OPENSSL_STRING_new_null()) == NULL) { + BIO_printf(bio_err, "Memory allocation failure\n"); + goto end; + } + while (argc >= 1) { + if (strcmp(*argv, "-inform") == 0) { + if (--argc < 1) + goto bad; + informat = 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; + derfile = *(++argv); + } else if (strcmp(*argv, "-i") == 0) { + indent = 1; + } else if (strcmp(*argv, "-noout") == 0) + noout = 1; + else if (strcmp(*argv, "-oid") == 0) { + if (--argc < 1) + goto bad; + oidfile = *(++argv); + } else if (strcmp(*argv, "-offset") == 0) { + if (--argc < 1) + goto bad; + offset = strtonum(*(++argv), 0, INT_MAX, &errstr); + if (errstr) + goto bad; + } else if (strcmp(*argv, "-length") == 0) { + if (--argc < 1) + goto bad; + length = strtonum(*(++argv), 1, UINT_MAX, &errstr); + if (errstr) + goto bad; + } else if (strcmp(*argv, "-dump") == 0) { + dump = -1; + } else if (strcmp(*argv, "-dlimit") == 0) { + if (--argc < 1) + goto bad; + dump = strtonum(*(++argv), 1, INT_MAX, &errstr); + if (errstr) + goto bad; + } else if (strcmp(*argv, "-strparse") == 0) { + if (--argc < 1) + goto bad; + sk_OPENSSL_STRING_push(osk, *(++argv)); + } else if (strcmp(*argv, "-genstr") == 0) { + if (--argc < 1) + goto bad; + genstr = *(++argv); + } else if (strcmp(*argv, "-genconf") == 0) { + if (--argc < 1) + goto bad; + genconf = *(++argv); + } else { + BIO_printf(bio_err, "unknown option %s\n", *argv); + badops = 1; + break; + } + argc--; + argv++; + } + + if (badops) { +bad: + BIO_printf(bio_err, "%s [options] <infile\n", prog); + BIO_printf(bio_err, "where options are\n"); + BIO_printf(bio_err, " -inform arg input format - one of DER PEM\n"); + BIO_printf(bio_err, " -in arg input file\n"); + BIO_printf(bio_err, " -out arg output file (output format is always DER\n"); + BIO_printf(bio_err, " -noout arg don't produce any output\n"); + BIO_printf(bio_err, " -offset arg offset into file\n"); + BIO_printf(bio_err, " -length arg length of section in file\n"); + BIO_printf(bio_err, " -i indent entries\n"); + BIO_printf(bio_err, " -dump dump unknown data in hex form\n"); + BIO_printf(bio_err, " -dlimit arg dump the first arg bytes of unknown data in hex form\n"); + BIO_printf(bio_err, " -oid file file of extra oid definitions\n"); + BIO_printf(bio_err, " -strparse offset\n"); + BIO_printf(bio_err, " a series of these can be used to 'dig' into multiple\n"); + BIO_printf(bio_err, " ASN1 blob wrappings\n"); + BIO_printf(bio_err, " -genstr str string to generate ASN1 structure from\n"); + BIO_printf(bio_err, " -genconf file file to generate ASN1 structure from\n"); + goto end; + } + ERR_load_crypto_strings(); + + 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 (oidfile != NULL) { + if (BIO_read_filename(in, oidfile) <= 0) { + BIO_printf(bio_err, "problems opening %s\n", oidfile); + ERR_print_errors(bio_err); + goto end; + } + OBJ_create_objects(in); + } + if (infile == NULL) + BIO_set_fp(in, stdin, BIO_NOCLOSE); + else { + if (BIO_read_filename(in, infile) <= 0) { + perror(infile); + goto end; + } + } + + if (derfile) { + if (!(derout = BIO_new_file(derfile, "wb"))) { + BIO_printf(bio_err, "problems opening %s\n", 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 (genstr || genconf) { + num = do_generate(bio_err, genstr, genconf, buf); + if (num < 0) { + ERR_print_errors(bio_err); + goto end; + } + } else { + + if (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(osk)) { + tmpbuf = (unsigned char *) str; + tmplen = num; + for (i = 0; i < sk_OPENSSL_STRING_num(osk); i++) { + ASN1_TYPE *atmp; + int typ; + j = strtonum(sk_OPENSSL_STRING_value(osk, i), + 1, INT_MAX, &errstr); + if (errstr) { + BIO_printf(bio_err, + "'%s' is an invalid number: %s\n", + sk_OPENSSL_STRING_value(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 (offset >= num) { + BIO_printf(bio_err, "Error: offset too large\n"); + goto end; + } + num -= offset; + + if ((length == 0) || ((long) length > num)) + length = (unsigned int) num; + if (derout) { + if (BIO_write(derout, str + offset, length) != (int) length) { + BIO_printf(bio_err, "Error writing output\n"); + ERR_print_errors(bio_err); + goto end; + } + } + if (!noout && + !ASN1_parse_dump(out, (unsigned char *) &(str[offset]), length, + indent, dump)) { + ERR_print_errors(bio_err); + goto end; + } + ret = 0; +end: + BIO_free(derout); + if (in != NULL) + BIO_free(in); + if (out != NULL) + BIO_free_all(out); + if (b64 != NULL) + BIO_free(b64); + if (ret != 0) + ERR_print_errors(bio_err); + if (buf != NULL) + BUF_MEM_free(buf); + if (at != NULL) + ASN1_TYPE_free(at); + if (osk != NULL) + sk_OPENSSL_STRING_free(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/usr.bin/openssl/ca.c b/usr.bin/openssl/ca.c new file mode 100644 index 00000000000..c19ecc6616d --- /dev/null +++ b/usr.bin/openssl/ca.c @@ -0,0 +1,2743 @@ +/* $OpenBSD: ca.c,v 1.1 2014/08/26 17:47:24 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.] + */ + +/* The PPKI stuff has been donated by Jeff Barber <jeffb@issl.atl.hp.com> */ + +#include <sys/types.h> + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include <unistd.h> + +#include "apps.h" + +#include <openssl/bio.h> +#include <openssl/bn.h> +#include <openssl/conf.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/objects.h> +#include <openssl/ocsp.h> +#include <openssl/pem.h> +#include <openssl/txt_db.h> +#include <openssl/x509.h> +#include <openssl/x509v3.h> + +#define BASE_SECTION "ca" + +#define ENV_DEFAULT_CA "default_ca" + +#define STRING_MASK "string_mask" +#define UTF8_IN "utf8" + +#define ENV_DIR "dir" +#define ENV_CERTS "certs" +#define ENV_CRL_DIR "crl_dir" +#define ENV_CA_DB "CA_DB" +#define ENV_NEW_CERTS_DIR "new_certs_dir" +#define ENV_CERTIFICATE "certificate" +#define ENV_SERIAL "serial" +#define ENV_CRLNUMBER "crlnumber" +#define ENV_CRL "crl" +#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 md2, md5, sha or sha1\n", + " -policy arg - The CA 'policy' to support\n", + " -keyfile arg - private key file\n", + " -keyform arg - private key file format (PEM or ENGINE)\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", +#ifndef OPENSSL_NO_ENGINE + " -engine e - use engine e, possibly a hardware device.\n", +#endif + " -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, ENGINE * e); +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, char **); + +int +ca_main(int argc, char **argv) +{ + ENGINE *e = NULL; + 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; +#define BSIZE 256 + char buf[3][BSIZE]; +#ifndef OPENSSL_NO_ENGINE + char *engine = NULL; +#endif + char *tofree = NULL; + const char *errstr = NULL; + DB_ATTR db_attr; + + 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; + } +#ifndef OPENSSL_NO_ENGINE + else if (strcmp(*argv, "-engine") == 0) { + if (--argc < 1) + goto bad; + engine = *(++argv); + } +#endif + 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; + } + ERR_load_crypto_strings(); + + /*****************************************************************/ + tofree = NULL; + if (configfile == NULL) + configfile = getenv("OPENSSL_CONF"); + if (configfile == NULL) + configfile = getenv("SSLEAY_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; + +#ifndef OPENSSL_NO_ENGINE + e = setup_engine(bio_err, engine, 0); +#endif + + /* 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, e, "CA private key"); + if (key) + OPENSSL_cleanse(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, e, + "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, "there needs to be defined a directory for new certificate to be placed in\n"); + goto err; + } + /* + * outdir is a directory spec, but access() for VMS demands a + * filename. In any case, stat(), below, will catch the + * problem if outdir is not a directory spec, and the fopen() + * or open() will catch an error if there is no write access. + * + * Presumably, this problem could also be solved by using the + * DEC C routines to convert the directory syntax to Unixly, + * and give that to access(). However, time's too short to + * do that just now. + */ + if (access(outdir, R_OK | W_OK | X_OK) != 0) { + BIO_printf(bio_err, + "I am unable to access the %s directory\n", outdir); + perror(outdir); + goto err; + } + if (app_isdir(outdir) <= 0) { + BIO_printf(bio_err, + "%s need to be a directory\n", outdir); + perror(outdir); + 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, e); + 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) { + BIO_printf(bio_err, "\n%d out of %d certificate requests certified, commit? [y/n]", total_done, total); + (void) BIO_flush(bio_err); + buf[0][0] = '\0'; + if (!fgets(buf[0], 10, stdin)) { + BIO_printf(bio_err, "CERTIFICATION CANCELED: I/O error\n"); + ret = 0; + goto err; + } + if ((buf[0][0] != 'y') && (buf[0][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 *serial; + unsigned char *data; + + x = sk_X509_value(cert_sk, i); + + j = x->cert_info->serialNumber->length; + data = (unsigned char *)x->cert_info->serialNumber->data; + if (j > 0) + serial = bin2hex(data, j); + else + serial = strdup("00"); + if (serial) { + k = snprintf(buf[2], sizeof(buf[2]), + "%s/%s.pem", outdir, serial); + free(serial); + if (k == -1 || k >= sizeof(buf[2])) { + 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", buf[2]); + + if (BIO_write_filename(Cout, buf[2]) <= 0) { + perror(buf[2]); + 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, e, 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, ENGINE * e) +{ + 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, e, + 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; + char buf[25]; + + 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 e-mail 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 (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) { + + BIO_printf(bio_err, "Sign the certificate? [y/n]:"); + (void) BIO_flush(bio_err); + buf[0] = '\0'; + if (!fgets(buf, sizeof(buf) - 1, stdin)) { + BIO_printf(bio_err, + "CERTIFICATE WILL NOT BE CERTIFIED: I/O error\n"); + ok = 0; + goto err; + } + if (!((buf[0] == 'y') || (buf[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); + 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_exp_date] == 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 0 + /* ??? Not needed since X509_print prints all this stuff anyway */ + f = X509_NAME_oneline(X509_get_issuer_name(x), buf, 256); + BIO_printf(bp, "issuer :%s\n", f); + + f = X509_NAME_oneline(X509_get_subject_name(x), buf, 256); + BIO_printf(bp, "subject:%s\n", f); + + BIO_puts(bp, "serial :"); + i2a_ASN1_INTEGER(bp, x->cert_info->serialNumber); + BIO_puts(bp, "\n\n"); +#endif + 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; + X509_NAME_ENTRY *ne = 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); + if (ne != NULL) + X509_NAME_ENTRY_free(ne); + + 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); + 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_exp_date] == 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/usr.bin/openssl/ciphers.c b/usr.bin/openssl/ciphers.c new file mode 100644 index 00000000000..bf17f71c065 --- /dev/null +++ b/usr.bin/openssl/ciphers.c @@ -0,0 +1,194 @@ +/* $OpenBSD: ciphers.c,v 1.1 2014/08/26 17:47:24 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.] + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/err.h> +#include <openssl/ssl.h> + +static const char *ciphers_usage[] = { + "usage: ciphers args\n", + " -v - verbose mode, a textual listing of the SSL/TLS ciphers in OpenSSL\n", + " -V - even more verbose\n", + " -ssl3 - SSL3 mode\n", + " -tls1 - TLS1 mode\n", + NULL +}; + +int ciphers_main(int, char **); + +int +ciphers_main(int argc, char **argv) +{ + int ret = 1, i; + int verbose = 0, Verbose = 0; + const char **pp; + const char *p; + int badops = 0; + SSL_CTX *ctx = NULL; + SSL *ssl = NULL; + char *ciphers = NULL; + const SSL_METHOD *meth = NULL; + STACK_OF(SSL_CIPHER) * sk; + BIO *STDout = NULL; + char *desc; + + meth = SSLv3_server_method(); + + STDout = BIO_new_fp(stdout, BIO_NOCLOSE); + + argc--; + argv++; + while (argc >= 1) { + if (strcmp(*argv, "-v") == 0) + verbose = 1; + else if (strcmp(*argv, "-V") == 0) + verbose = Verbose = 1; + else if (strcmp(*argv, "-ssl3") == 0) + meth = SSLv3_client_method(); + else if (strcmp(*argv, "-tls1") == 0) + meth = TLSv1_client_method(); + else if ((strncmp(*argv, "-h", 2) == 0) || + (strcmp(*argv, "-?") == 0)) { + badops = 1; + break; + } else { + ciphers = *argv; + } + argc--; + argv++; + } + + if (badops) { + for (pp = ciphers_usage; (*pp != NULL); pp++) + BIO_printf(bio_err, "%s", *pp); + goto end; + } + + ctx = SSL_CTX_new(meth); + if (ctx == NULL) + goto err; + if (ciphers != NULL) { + if (!SSL_CTX_set_cipher_list(ctx, ciphers)) { + BIO_printf(bio_err, "Error in cipher list\n"); + goto err; + } + } + ssl = SSL_new(ctx); + if (ssl == NULL) + goto err; + + if (!verbose) { + for (i = 0; ; i++) { + p = SSL_get_cipher_list(ssl, i); + if (p == NULL) + break; + if (i != 0) + BIO_printf(STDout, ":"); + BIO_printf(STDout, "%s", p); + } + BIO_printf(STDout, "\n"); + } else { /* verbose */ + sk = SSL_get_ciphers(ssl); + + for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) { + SSL_CIPHER *c; + + c = sk_SSL_CIPHER_value(sk, i); + + if (Verbose) { + unsigned long id = SSL_CIPHER_get_id(c); + int id0 = (int) (id >> 24); + int id1 = (int) ((id >> 16) & 0xffL); + int id2 = (int) ((id >> 8) & 0xffL); + int id3 = (int) (id & 0xffL); + + if ((id & 0xff000000L) == 0x02000000L) + BIO_printf(STDout, " 0x%02X,0x%02X,0x%02X - ", id1, id2, id3); /* SSL2 cipher */ + else if ((id & 0xff000000L) == 0x03000000L) + BIO_printf(STDout, " 0x%02X,0x%02X - ", id2, id3); /* SSL3 cipher */ + else + BIO_printf(STDout, "0x%02X,0x%02X,0x%02X,0x%02X - ", id0, id1, id2, id3); /* whatever */ + } + desc = SSL_CIPHER_description(c, NULL, 0); + BIO_puts(STDout, desc); + if (strcmp(desc, "OPENSSL_malloc Error") != 0) + free(desc); + } + } + + ret = 0; + if (0) { +err: + ERR_print_errors(bio_err); + } + +end: + if (ctx != NULL) + SSL_CTX_free(ctx); + if (ssl != NULL) + SSL_free(ssl); + if (STDout != NULL) + BIO_free_all(STDout); + + return (ret); +} diff --git a/usr.bin/openssl/cms.c b/usr.bin/openssl/cms.c new file mode 100644 index 00000000000..21d27adad1d --- /dev/null +++ b/usr.bin/openssl/cms.c @@ -0,0 +1,1154 @@ +/* $OpenBSD: cms.c,v 1.1 2014/08/26 17:47:24 jsing Exp $ */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2008 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. + * ==================================================================== + */ + +/* CMS utility function */ + +#include <stdio.h> +#include <string.h> + +#include "apps.h" + +#ifndef OPENSSL_NO_CMS + +#include <openssl/cms.h> +#include <openssl/crypto.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/x509_vfy.h> +#include <openssl/x509v3.h> + +static int save_certs(char *signerfile, STACK_OF(X509) * signers); +static int cms_cb(int ok, X509_STORE_CTX * ctx); +static void receipt_request_print(BIO * out, CMS_ContentInfo * cms); +static CMS_ReceiptRequest * make_receipt_request( + STACK_OF(OPENSSL_STRING) * rr_to, int rr_allorfirst, + STACK_OF(OPENSSL_STRING) * rr_from); + +#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_CMSOUT (5 | SMIME_IP | SMIME_OP) +#define SMIME_RESIGN (6 | SMIME_IP | SMIME_OP | SMIME_SIGNERS) +#define SMIME_DATAOUT (7 | SMIME_IP) +#define SMIME_DATA_CREATE (8 | SMIME_OP) +#define SMIME_DIGEST_VERIFY (9 | SMIME_IP) +#define SMIME_DIGEST_CREATE (10 | SMIME_OP) +#define SMIME_UNCOMPRESS (11 | SMIME_IP) +#define SMIME_COMPRESS (12 | SMIME_OP) +#define SMIME_ENCRYPTED_DECRYPT (13 | SMIME_IP) +#define SMIME_ENCRYPTED_ENCRYPT (14 | SMIME_OP) +#define SMIME_SIGN_RECEIPT (15 | SMIME_IP | SMIME_OP) +#define SMIME_VERIFY_RECEIPT (16 | SMIME_IP) + +int verify_err = 0; + +int cms_main(int, char **); + +int +cms_main(int argc, char **argv) +{ + ENGINE *e = NULL; + int operation = 0; + int ret = 0; + char **args; + const char *inmode = "r", *outmode = "w"; + char *infile = NULL, *outfile = NULL, *rctfile = NULL; + char *signerfile = NULL, *recipfile = NULL; + STACK_OF(OPENSSL_STRING) * sksigners = NULL, *skkeys = NULL; + char *certfile = NULL, *keyfile = NULL, *contfile = NULL; + char *certsoutfile = NULL; + const EVP_CIPHER *cipher = NULL; + CMS_ContentInfo *cms = NULL, *rcms = 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, *rctin = NULL; + int badarg = 0; + int flags = CMS_DETACHED, noout = 0, print = 0; + int verify_retcode = 0; + int rr_print = 0, rr_allorfirst = -1; + STACK_OF(OPENSSL_STRING) * rr_to = NULL, *rr_from = NULL; + CMS_ReceiptRequest *rr = NULL; + char *to = NULL, *from = NULL, *subject = NULL; + char *CAfile = NULL, *CApath = NULL; + char *passargin = NULL, *passin = NULL; + const EVP_MD *sign_md = NULL; + int informat = FORMAT_SMIME, outformat = FORMAT_SMIME; + int rctformat = FORMAT_SMIME, keyform = FORMAT_PEM; +#ifndef OPENSSL_NO_ENGINE + char *engine = NULL; +#endif + unsigned char *secret_key = NULL, *secret_keyid = NULL; + unsigned char *pwri_pass = NULL, *pwri_tmp = NULL; + size_t secret_keylen = 0, secret_keyidlen = 0; + + ASN1_OBJECT *econtent_type = NULL; + + X509_VERIFY_PARAM *vpm = NULL; + + 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, "-sign_receipt")) + operation = SMIME_SIGN_RECEIPT; + else if (!strcmp(*args, "-resign")) + operation = SMIME_RESIGN; + else if (!strcmp(*args, "-verify")) + operation = SMIME_VERIFY; + else if (!strcmp(*args, "-verify_retcode")) + verify_retcode = 1; + else if (!strcmp(*args, "-verify_receipt")) { + operation = SMIME_VERIFY_RECEIPT; + if (!args[1]) + goto argerr; + args++; + rctfile = *args; + } else if (!strcmp(*args, "-cmsout")) + operation = SMIME_CMSOUT; + else if (!strcmp(*args, "-data_out")) + operation = SMIME_DATAOUT; + else if (!strcmp(*args, "-data_create")) + operation = SMIME_DATA_CREATE; + else if (!strcmp(*args, "-digest_verify")) + operation = SMIME_DIGEST_VERIFY; + else if (!strcmp(*args, "-digest_create")) + operation = SMIME_DIGEST_CREATE; + else if (!strcmp(*args, "-compress")) + operation = SMIME_COMPRESS; + else if (!strcmp(*args, "-uncompress")) + operation = SMIME_UNCOMPRESS; + else if (!strcmp(*args, "-EncryptedData_decrypt")) + operation = SMIME_ENCRYPTED_DECRYPT; + else if (!strcmp(*args, "-EncryptedData_encrypt")) + operation = SMIME_ENCRYPTED_ENCRYPT; +#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, "-debug_decrypt")) + flags |= CMS_DEBUG_DECRYPT; + else if (!strcmp(*args, "-text")) + flags |= CMS_TEXT; + else if (!strcmp(*args, "-nointern")) + flags |= CMS_NOINTERN; + else if (!strcmp(*args, "-noverify") || + !strcmp(*args, "-no_signer_cert_verify")) + flags |= CMS_NO_SIGNER_CERT_VERIFY; + else if (!strcmp(*args, "-nocerts")) + flags |= CMS_NOCERTS; + else if (!strcmp(*args, "-noattr")) + flags |= CMS_NOATTR; + else if (!strcmp(*args, "-nodetach")) + flags &= ~CMS_DETACHED; + else if (!strcmp(*args, "-nosmimecap")) + flags |= CMS_NOSMIMECAP; + else if (!strcmp(*args, "-binary")) + flags |= CMS_BINARY; + else if (!strcmp(*args, "-keyid")) + flags |= CMS_USE_KEYID; + else if (!strcmp(*args, "-nosigs")) + flags |= CMS_NOSIGS; + else if (!strcmp(*args, "-no_content_verify")) + flags |= CMS_NO_CONTENT_VERIFY; + else if (!strcmp(*args, "-no_attr_verify")) + flags |= CMS_NO_ATTR_VERIFY; + else if (!strcmp(*args, "-stream")) + flags |= CMS_STREAM; + else if (!strcmp(*args, "-indef")) + flags |= CMS_STREAM; + else if (!strcmp(*args, "-noindef")) + flags &= ~CMS_STREAM; + else if (!strcmp(*args, "-nooldmime")) + flags |= CMS_NOOLDMIMETYPE; + else if (!strcmp(*args, "-crlfeol")) + flags |= CMS_CRLFEOL; + else if (!strcmp(*args, "-noout")) + noout = 1; + else if (!strcmp(*args, "-receipt_request_print")) + rr_print = 1; + else if (!strcmp(*args, "-receipt_request_all")) + rr_allorfirst = 0; + else if (!strcmp(*args, "-receipt_request_first")) + rr_allorfirst = 1; + else if (!strcmp(*args, "-receipt_request_from")) { + if (!args[1]) + goto argerr; + args++; + if (!rr_from) + rr_from = sk_OPENSSL_STRING_new_null(); + sk_OPENSSL_STRING_push(rr_from, *args); + } else if (!strcmp(*args, "-receipt_request_to")) { + if (!args[1]) + goto argerr; + args++; + if (!rr_to) + rr_to = sk_OPENSSL_STRING_new_null(); + sk_OPENSSL_STRING_push(rr_to, *args); + } else if (!strcmp(*args, "-print")) { + noout = 1; + print = 1; + } else if (!strcmp(*args, "-secretkey")) { + long ltmp; + if (!args[1]) + goto argerr; + args++; + secret_key = string_to_hex(*args, <mp); + if (!secret_key) { + BIO_printf(bio_err, "Invalid key %s\n", *args); + goto argerr; + } + secret_keylen = (size_t) ltmp; + } else if (!strcmp(*args, "-secretkeyid")) { + long ltmp; + if (!args[1]) + goto argerr; + args++; + secret_keyid = string_to_hex(*args, <mp); + if (!secret_keyid) { + BIO_printf(bio_err, "Invalid id %s\n", *args); + goto argerr; + } + secret_keyidlen = (size_t) ltmp; + } else if (!strcmp(*args, "-pwri_password")) { + if (!args[1]) + goto argerr; + args++; + pwri_pass = (unsigned char *) *args; + } else if (!strcmp(*args, "-econtent_type")) { + if (!args[1]) + goto argerr; + args++; + econtent_type = OBJ_txt2obj(*args, 0); + if (!econtent_type) { + BIO_printf(bio_err, "Invalid OID %s\n", *args); + goto argerr; + } + } +#ifndef OPENSSL_NO_ENGINE + else if (!strcmp(*args, "-engine")) { + if (!args[1]) + goto argerr; + engine = *++args; + } +#endif + 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, "-certsout")) { + if (!args[1]) + goto argerr; + certsoutfile = *++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, "-rctform")) { + if (!args[1]) + goto argerr; + rctformat = 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 (((rr_allorfirst != -1) || rr_from) && !rr_to) { + BIO_puts(bio_err, "No Signed Receipts Recipients\n"); + goto argerr; + } + if (!(operation & SMIME_SIGNERS) && (rr_to || rr_from)) { + BIO_puts(bio_err, "Signed receipts only allowed with -sign\n"); + goto argerr; + } + if (!(operation & SMIME_SIGNERS) && (skkeys || sksigners)) { + BIO_puts(bio_err, "Multiple signers or keys not allowed\n"); + goto argerr; + } + if (operation & SMIME_SIGNERS) { + if (keyfile && !signerfile) { + BIO_puts(bio_err, "Illegal -inkey without -signer\n"); + goto argerr; + } + /* Check to see if any final signer needs to be appended */ + 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 && !secret_key && !pwri_pass) { + BIO_printf(bio_err, + "No recipient certificate or key specified\n"); + badarg = 1; + } + } else if (operation == SMIME_ENCRYPT) { + if (!*args && !secret_key && !pwri_pass) { + 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 cms [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, "-cmsout output CMS 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, "-certsout file certificate output 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, "-keyid use subject key identifier\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 or ENGINE)\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"); +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, "-engine e use engine e, possibly a hardware device.\n"); +#endif + 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; + } +#ifndef OPENSSL_NO_ENGINE + e = setup_engine(bio_err, engine, 0); +#endif + + 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 &= ~CMS_DETACHED; + + if (operation & SMIME_OP) { + if (outformat == FORMAT_ASN1) + outmode = "wb"; + } else { + if (flags & CMS_BINARY) + outmode = "wb"; + } + + if (operation & SMIME_IP) { + if (informat == FORMAT_ASN1) + inmode = "rb"; + } else { + if (flags & CMS_BINARY) + inmode = "rb"; + } + + if (operation == SMIME_ENCRYPT) { + if (!cipher) { +#ifndef OPENSSL_NO_DES + cipher = EVP_des_ede3_cbc(); +#else + BIO_printf(bio_err, "No cipher selected\n"); + goto end; +#endif + } + if (secret_key && !secret_keyid) { + BIO_printf(bio_err, "No secret key id\n"); + goto end; + } + if (*args) + encerts = sk_X509_new_null(); + while (*args) { + if (!(cert = load_cert(bio_err, *args, FORMAT_PEM, + NULL, e, "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, + e, "certificate file"))) { + ERR_print_errors(bio_err); + goto end; + } + } + if (recipfile && (operation == SMIME_DECRYPT)) { + if (!(recip = load_cert(bio_err, recipfile, FORMAT_PEM, NULL, + e, "recipient certificate file"))) { + ERR_print_errors(bio_err); + goto end; + } + } + if (operation == SMIME_SIGN_RECEIPT) { + if (!(signer = load_cert(bio_err, signerfile, FORMAT_PEM, NULL, + e, "receipt signer certificate file"))) { + ERR_print_errors(bio_err); + goto end; + } + } + if (operation == SMIME_DECRYPT) { + if (!keyfile) + keyfile = recipfile; + } else if ((operation == SMIME_SIGN) || + (operation == SMIME_SIGN_RECEIPT)) { + if (!keyfile) + keyfile = signerfile; + } else + keyfile = NULL; + + if (keyfile) { + key = load_key(bio_err, keyfile, keyform, 0, passin, e, + "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) + cms = SMIME_read_CMS(in, &indata); + else if (informat == FORMAT_PEM) + cms = PEM_read_bio_CMS(in, NULL, NULL, NULL); + else if (informat == FORMAT_ASN1) + cms = d2i_CMS_bio(in, NULL); + else { + BIO_printf(bio_err, "Bad input format for CMS file\n"); + goto end; + } + + if (!cms) { + 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 (certsoutfile) { + STACK_OF(X509) * allcerts; + allcerts = CMS_get1_certs(cms); + if (!save_certs(certsoutfile, allcerts)) { + BIO_printf(bio_err, + "Error writing certs to %s\n", + certsoutfile); + ret = 5; + goto end; + } + sk_X509_pop_free(allcerts, X509_free); + } + } + if (rctfile) { + char *rctmode = (rctformat == FORMAT_ASN1) ? "rb" : "r"; + if (!(rctin = BIO_new_file(rctfile, rctmode))) { + BIO_printf(bio_err, + "Can't open receipt file %s\n", rctfile); + goto end; + } + if (rctformat == FORMAT_SMIME) + rcms = SMIME_read_CMS(rctin, NULL); + else if (rctformat == FORMAT_PEM) + rcms = PEM_read_bio_CMS(rctin, NULL, NULL, NULL); + else if (rctformat == FORMAT_ASN1) + rcms = d2i_CMS_bio(rctin, NULL); + else { + BIO_printf(bio_err, "Bad input format for receipt\n"); + goto end; + } + + if (!rcms) { + BIO_printf(bio_err, "Error reading receipt\n"); + 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) || + (operation == SMIME_VERIFY_RECEIPT)) { + if (!(store = setup_verify(bio_err, CAfile, CApath))) + goto end; + X509_STORE_set_verify_cb(store, cms_cb); + if (vpm) + X509_STORE_set1_param(store, vpm); + } + ret = 3; + + if (operation == SMIME_DATA_CREATE) { + cms = CMS_data_create(in, flags); + } else if (operation == SMIME_DIGEST_CREATE) { + cms = CMS_digest_create(in, sign_md, flags); + } else if (operation == SMIME_COMPRESS) { + cms = CMS_compress(in, -1, flags); + } else if (operation == SMIME_ENCRYPT) { + flags |= CMS_PARTIAL; + cms = CMS_encrypt(encerts, in, cipher, flags); + if (!cms) + goto end; + if (secret_key) { + if (!CMS_add0_recipient_key(cms, NID_undef, secret_key, + secret_keylen, secret_keyid, secret_keyidlen, + NULL, NULL, NULL)) + goto end; + /* NULL these because call absorbs them */ + secret_key = NULL; + secret_keyid = NULL; + } + if (pwri_pass) { + pwri_tmp = strdup(pwri_pass); + if (!pwri_tmp) + goto end; + if (!CMS_add0_recipient_password(cms, -1, NID_undef, + NID_undef, pwri_tmp, -1, NULL)) + goto end; + pwri_tmp = NULL; + } + if (!(flags & CMS_STREAM)) { + if (!CMS_final(cms, in, NULL, flags)) + goto end; + } + } else if (operation == SMIME_ENCRYPTED_ENCRYPT) { + cms = CMS_EncryptedData_encrypt(in, cipher, secret_key, + secret_keylen, flags); + + } else if (operation == SMIME_SIGN_RECEIPT) { + CMS_ContentInfo *srcms = NULL; + STACK_OF(CMS_SignerInfo) * sis; + CMS_SignerInfo *si; + sis = CMS_get0_SignerInfos(cms); + if (!sis) + goto end; + si = sk_CMS_SignerInfo_value(sis, 0); + srcms = CMS_sign_receipt(si, signer, key, other, flags); + if (!srcms) + goto end; + CMS_ContentInfo_free(cms); + cms = srcms; + } else if (operation & SMIME_SIGNERS) { + int i; + /* + * If detached data content we enable streaming if S/MIME + * output format. + */ + if (operation == SMIME_SIGN) { + + if (flags & CMS_DETACHED) { + if (outformat == FORMAT_SMIME) + flags |= CMS_STREAM; + } + flags |= CMS_PARTIAL; + cms = CMS_sign(NULL, NULL, other, in, flags); + if (!cms) + goto end; + if (econtent_type) + CMS_set1_eContentType(cms, econtent_type); + + if (rr_to) { + rr = make_receipt_request(rr_to, rr_allorfirst, + rr_from); + if (!rr) { + BIO_puts(bio_err, + "Signed Receipt Request Creation Error\n"); + goto end; + } + } + } else + flags |= CMS_REUSE_DIGEST; + for (i = 0; i < sk_OPENSSL_STRING_num(sksigners); i++) { + CMS_SignerInfo *si; + signerfile = sk_OPENSSL_STRING_value(sksigners, i); + keyfile = sk_OPENSSL_STRING_value(skkeys, i); + signer = load_cert(bio_err, signerfile, FORMAT_PEM, + NULL, e, "signer certificate"); + if (!signer) + goto end; + key = load_key(bio_err, keyfile, keyform, 0, passin, e, + "signing key file"); + if (!key) + goto end; + si = CMS_add1_signer(cms, signer, key, sign_md, flags); + if (!si) + goto end; + if (rr && !CMS_add1_ReceiptRequest(si, rr)) + 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 & CMS_STREAM)) { + if (!CMS_final(cms, in, NULL, flags)) + goto end; + } + } + if (!cms) { + BIO_printf(bio_err, "Error creating CMS structure\n"); + goto end; + } + ret = 4; + if (operation == SMIME_DECRYPT) { + if (flags & CMS_DEBUG_DECRYPT) + CMS_decrypt(cms, NULL, NULL, NULL, NULL, flags); + + if (secret_key) { + if (!CMS_decrypt_set1_key(cms, secret_key, + secret_keylen, secret_keyid, secret_keyidlen)) { + BIO_puts(bio_err, + "Error decrypting CMS using secret key\n"); + goto end; + } + } + if (key) { + if (!CMS_decrypt_set1_pkey(cms, key, recip)) { + BIO_puts(bio_err, + "Error decrypting CMS using private key\n"); + goto end; + } + } + if (pwri_pass) { + if (!CMS_decrypt_set1_password(cms, pwri_pass, -1)) { + BIO_puts(bio_err, + "Error decrypting CMS using password\n"); + goto end; + } + } + if (!CMS_decrypt(cms, NULL, NULL, indata, out, flags)) { + BIO_printf(bio_err, "Error decrypting CMS structure\n"); + goto end; + } + } else if (operation == SMIME_DATAOUT) { + if (!CMS_data(cms, out, flags)) + goto end; + } else if (operation == SMIME_UNCOMPRESS) { + if (!CMS_uncompress(cms, indata, out, flags)) + goto end; + } else if (operation == SMIME_DIGEST_VERIFY) { + if (CMS_digest_verify(cms, indata, out, flags) > 0) + BIO_printf(bio_err, "Verification successful\n"); + else { + BIO_printf(bio_err, "Verification failure\n"); + goto end; + } + } else if (operation == SMIME_ENCRYPTED_DECRYPT) { + if (!CMS_EncryptedData_decrypt(cms, secret_key, secret_keylen, + indata, out, flags)) + goto end; + } else if (operation == SMIME_VERIFY) { + if (CMS_verify(cms, other, store, indata, out, flags) > 0) + BIO_printf(bio_err, "Verification successful\n"); + else { + BIO_printf(bio_err, "Verification failure\n"); + if (verify_retcode) + ret = verify_err + 32; + goto end; + } + if (signerfile) { + STACK_OF(X509) * signers; + signers = CMS_get0_signers(cms); + if (!save_certs(signerfile, signers)) { + BIO_printf(bio_err, + "Error writing signers to %s\n", + signerfile); + ret = 5; + goto end; + } + sk_X509_free(signers); + } + if (rr_print) + receipt_request_print(bio_err, cms); + + } else if (operation == SMIME_VERIFY_RECEIPT) { + if (CMS_verify_receipt(rcms, cms, other, store, flags) > 0) + BIO_printf(bio_err, "Verification successful\n"); + else { + BIO_printf(bio_err, "Verification failure\n"); + goto end; + } + } else { + if (noout) { + if (print) + CMS_ContentInfo_print_ctx(out, cms, 0, NULL); + } else if (outformat == FORMAT_SMIME) { + 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 (operation == SMIME_RESIGN) + ret = SMIME_write_CMS(out, cms, indata, flags); + else + ret = SMIME_write_CMS(out, cms, in, flags); + } else if (outformat == FORMAT_PEM) + ret = PEM_write_bio_CMS_stream(out, cms, in, flags); + else if (outformat == FORMAT_ASN1) + ret = i2d_CMS_bio_stream(out, cms, in, flags); + else { + BIO_printf(bio_err, "Bad output format for CMS file\n"); + goto end; + } + if (ret <= 0) { + ret = 6; + 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); + free(secret_key); + free(secret_keyid); + free(pwri_tmp); + if (econtent_type) + ASN1_OBJECT_free(econtent_type); + if (rr) + CMS_ReceiptRequest_free(rr); + if (rr_to) + sk_OPENSSL_STRING_free(rr_to); + if (rr_from) + sk_OPENSSL_STRING_free(rr_from); + X509_STORE_free(store); + X509_free(cert); + X509_free(recip); + X509_free(signer); + EVP_PKEY_free(key); + CMS_ContentInfo_free(cms); + CMS_ContentInfo_free(rcms); + BIO_free(rctin); + 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 +cms_cb(int ok, X509_STORE_CTX * ctx) +{ + int error; + + error = X509_STORE_CTX_get_error(ctx); + + verify_err = error; + + if ((error != X509_V_ERR_NO_EXPLICIT_POLICY) && + ((error != X509_V_OK) || (ok != 2))) + return ok; + + policies_print(NULL, ctx); + + return ok; +} + +static void +gnames_stack_print(BIO * out, STACK_OF(GENERAL_NAMES) * gns) +{ + STACK_OF(GENERAL_NAME) * gens; + GENERAL_NAME *gen; + int i, j; + + for (i = 0; i < sk_GENERAL_NAMES_num(gns); i++) { + gens = sk_GENERAL_NAMES_value(gns, i); + for (j = 0; j < sk_GENERAL_NAME_num(gens); j++) { + gen = sk_GENERAL_NAME_value(gens, j); + BIO_puts(out, " "); + GENERAL_NAME_print(out, gen); + BIO_puts(out, "\n"); + } + } + return; +} + +static void +receipt_request_print(BIO * out, CMS_ContentInfo * cms) +{ + STACK_OF(CMS_SignerInfo) * sis; + CMS_SignerInfo *si; + CMS_ReceiptRequest *rr; + int allorfirst; + STACK_OF(GENERAL_NAMES) * rto, *rlist; + ASN1_STRING *scid; + int i, rv; + + sis = CMS_get0_SignerInfos(cms); + for (i = 0; i < sk_CMS_SignerInfo_num(sis); i++) { + si = sk_CMS_SignerInfo_value(sis, i); + rv = CMS_get1_ReceiptRequest(si, &rr); + BIO_printf(bio_err, "Signer %d:\n", i + 1); + if (rv == 0) + BIO_puts(bio_err, " No Receipt Request\n"); + else if (rv < 0) { + BIO_puts(bio_err, " Receipt Request Parse Error\n"); + ERR_print_errors(bio_err); + } else { + char *id; + int idlen; + CMS_ReceiptRequest_get0_values(rr, &scid, &allorfirst, + &rlist, &rto); + BIO_puts(out, " Signed Content ID:\n"); + idlen = ASN1_STRING_length(scid); + id = (char *) ASN1_STRING_data(scid); + BIO_dump_indent(out, id, idlen, 4); + BIO_puts(out, " Receipts From"); + if (rlist) { + BIO_puts(out, " List:\n"); + gnames_stack_print(out, rlist); + } else if (allorfirst == 1) + BIO_puts(out, ": First Tier\n"); + else if (allorfirst == 0) + BIO_puts(out, ": All\n"); + else + BIO_printf(out, " Unknown (%d)\n", allorfirst); + BIO_puts(out, " Receipts To:\n"); + gnames_stack_print(out, rto); + } + if (rr) + CMS_ReceiptRequest_free(rr); + } +} + +static STACK_OF(GENERAL_NAMES) * +make_names_stack(STACK_OF(OPENSSL_STRING) * ns) +{ + int i; + STACK_OF(GENERAL_NAMES) * ret; + GENERAL_NAMES *gens = NULL; + GENERAL_NAME *gen = NULL; + ret = sk_GENERAL_NAMES_new_null(); + if (!ret) + goto err; + for (i = 0; i < sk_OPENSSL_STRING_num(ns); i++) { + char *str = sk_OPENSSL_STRING_value(ns, i); + gen = a2i_GENERAL_NAME(NULL, NULL, NULL, GEN_EMAIL, str, 0); + if (!gen) + goto err; + gens = GENERAL_NAMES_new(); + if (!gens) + goto err; + if (!sk_GENERAL_NAME_push(gens, gen)) + goto err; + gen = NULL; + if (!sk_GENERAL_NAMES_push(ret, gens)) + goto err; + gens = NULL; + } + + return ret; + +err: + if (ret) + sk_GENERAL_NAMES_pop_free(ret, GENERAL_NAMES_free); + if (gens) + GENERAL_NAMES_free(gens); + if (gen) + GENERAL_NAME_free(gen); + return NULL; +} + + +static CMS_ReceiptRequest * +make_receipt_request(STACK_OF(OPENSSL_STRING) * rr_to, int rr_allorfirst, + STACK_OF(OPENSSL_STRING) * rr_from) +{ + STACK_OF(GENERAL_NAMES) * rct_to, *rct_from; + CMS_ReceiptRequest *rr; + + rct_to = make_names_stack(rr_to); + if (!rct_to) + goto err; + if (rr_from) { + rct_from = make_names_stack(rr_from); + if (!rct_from) + goto err; + } else + rct_from = NULL; + rr = CMS_ReceiptRequest_create0(NULL, -1, rr_allorfirst, rct_from, + rct_to); + return rr; + +err: + return NULL; +} + +#endif diff --git a/usr.bin/openssl/crl.c b/usr.bin/openssl/crl.c new file mode 100644 index 00000000000..04de5a2f122 --- /dev/null +++ b/usr.bin/openssl/crl.c @@ -0,0 +1,415 @@ +/* $OpenBSD: crl.c,v 1.1 2014/08/26 17:47:24 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.] + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/bio.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/x509.h> +#include <openssl/x509v3.h> + +#define POSTFIX ".rvk" + +static const char *crl_usage[] = { + "usage: crl args\n", + "\n", + " -inform arg - input format - default PEM (DER or PEM)\n", + " -outform arg - output format - default PEM\n", + " -text - print out a text format version\n", + " -in arg - input file - default stdin\n", + " -out arg - output file - default stdout\n", + " -hash - print hash value\n", +#ifndef OPENSSL_NO_MD5 + " -hash_old - print old-style (MD5) hash value\n", +#endif + " -fingerprint - print the crl fingerprint\n", + " -issuer - print issuer DN\n", + " -lastupdate - lastUpdate field\n", + " -nextupdate - nextUpdate field\n", + " -crlnumber - print CRL number\n", + " -noout - no CRL output\n", + " -CAfile name - verify CRL using certificates in file \"name\"\n", + " -CApath dir - verify CRL using certificates in \"dir\"\n", + " -nameopt arg - various certificate name options\n", + NULL +}; + +static X509_CRL *load_crl(char *file, int format); +static BIO *bio_out = NULL; + +int crl_main(int, char **); + +int +crl_main(int argc, char **argv) +{ + unsigned long nmflag = 0; + X509_CRL *x = NULL; + char *CAfile = NULL, *CApath = NULL; + int ret = 1, i, num, badops = 0; + BIO *out = NULL; + int informat, outformat; + char *infile = NULL, *outfile = NULL; + int hash = 0, issuer = 0, lastupdate = 0, nextupdate = 0, noout = 0, + text = 0; +#ifndef OPENSSL_NO_MD5 + int hash_old = 0; +#endif + int fingerprint = 0, crlnumber = 0; + const char **pp; + X509_STORE *store = NULL; + X509_STORE_CTX ctx; + X509_LOOKUP *lookup = NULL; + X509_OBJECT xobj; + EVP_PKEY *pkey; + int do_ver = 0; + const EVP_MD *md_alg, *digest = EVP_sha1(); + + if (bio_out == NULL) + if ((bio_out = BIO_new(BIO_s_file())) != NULL) { + BIO_set_fp(bio_out, stdout, BIO_NOCLOSE); + } + informat = FORMAT_PEM; + outformat = FORMAT_PEM; + + argc--; + argv++; + num = 0; + while (argc >= 1) { +#ifdef undef + if (strcmp(*argv, "-p") == 0) { + if (--argc < 1) + goto bad; + if (!args_from_file(++argv, Nargc, Nargv)) { + goto end; + } + } +#endif + 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, "-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, "-CApath") == 0) { + if (--argc < 1) + goto bad; + CApath = *(++argv); + do_ver = 1; + } else if (strcmp(*argv, "-CAfile") == 0) { + if (--argc < 1) + goto bad; + CAfile = *(++argv); + do_ver = 1; + } else if (strcmp(*argv, "-verify") == 0) + do_ver = 1; + else if (strcmp(*argv, "-text") == 0) + text = 1; + else if (strcmp(*argv, "-hash") == 0) + hash = ++num; +#ifndef OPENSSL_NO_MD5 + else if (strcmp(*argv, "-hash_old") == 0) + hash_old = ++num; +#endif + else if (strcmp(*argv, "-nameopt") == 0) { + if (--argc < 1) + goto bad; + if (!set_name_ex(&nmflag, *(++argv))) + goto bad; + } else if (strcmp(*argv, "-issuer") == 0) + issuer = ++num; + else if (strcmp(*argv, "-lastupdate") == 0) + lastupdate = ++num; + else if (strcmp(*argv, "-nextupdate") == 0) + nextupdate = ++num; + else if (strcmp(*argv, "-noout") == 0) + noout = ++num; + else if (strcmp(*argv, "-fingerprint") == 0) + fingerprint = ++num; + else if (strcmp(*argv, "-crlnumber") == 0) + crlnumber = ++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 = crl_usage; (*pp != NULL); pp++) + BIO_printf(bio_err, "%s", *pp); + goto end; + } + ERR_load_crypto_strings(); + x = load_crl(infile, informat); + if (x == NULL) { + goto end; + } + if (do_ver) { + store = X509_STORE_new(); + lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); + if (lookup == NULL) + goto end; + if (!X509_LOOKUP_load_file(lookup, 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, 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"); + } + if (num) { + for (i = 1; i <= num; i++) { + if (issuer == i) { + print_name(bio_out, "issuer=", + X509_CRL_get_issuer(x), nmflag); + } + if (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, "<NONE>"); + BIO_printf(bio_out, "\n"); + } + if (hash == i) { + BIO_printf(bio_out, "%08lx\n", + X509_NAME_hash(X509_CRL_get_issuer(x))); + } +#ifndef OPENSSL_NO_MD5 + if (hash_old == i) { + BIO_printf(bio_out, "%08lx\n", + X509_NAME_hash_old(X509_CRL_get_issuer(x))); + } +#endif + if (lastupdate == i) { + BIO_printf(bio_out, "lastUpdate="); + ASN1_TIME_print(bio_out, + X509_CRL_get_lastUpdate(x)); + BIO_printf(bio_out, "\n"); + } + if (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 (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 (outfile == NULL) { + BIO_set_fp(out, stdout, BIO_NOCLOSE); + } else { + if (BIO_write_filename(out, outfile) <= 0) { + perror(outfile); + goto end; + } + } + + if (text) + X509_CRL_print(out, x); + + if (noout) { + ret = 0; + goto end; + } + if (outformat == FORMAT_ASN1) + i = (int) i2d_X509_CRL_bio(out, x); + else if (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/usr.bin/openssl/crl2p7.c b/usr.bin/openssl/crl2p7.c new file mode 100644 index 00000000000..7fdb6ccfd47 --- /dev/null +++ b/usr.bin/openssl/crl2p7.c @@ -0,0 +1,314 @@ +/* $OpenBSD: crl2p7.c,v 1.1 2014/08/26 17:47:24 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.] + */ + +/* This was written by Gordon Chaffee <chaffee@plateau.cs.berkeley.edu> + * and donated 'to the cause' along with lots and lots of other fixes to + * the library. */ + +#include <sys/types.h> + +#include <stdio.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/objects.h> +#include <openssl/pem.h> +#include <openssl/pkcs7.h> +#include <openssl/x509.h> + +static int add_certs_from_file(STACK_OF(X509) * stack, char *certfile); + +/* -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 + */ + +int crl2pkcs7_main(int, char **); + +int +crl2pkcs7_main(int argc, char **argv) +{ + int i, badops = 0; + BIO *in = NULL, *out = NULL; + int informat, outformat; + char *infile, *outfile, *prog, *certfile; + PKCS7 *p7 = NULL; + PKCS7_SIGNED *p7s = NULL; + X509_CRL *crl = NULL; + STACK_OF(OPENSSL_STRING) * certflst = NULL; + STACK_OF(X509_CRL) * crl_stack = NULL; + STACK_OF(X509) * cert_stack = NULL; + int ret = 1, nocrl = 0; + + 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, "-in") == 0) { + if (--argc < 1) + goto bad; + infile = *(++argv); + } else if (strcmp(*argv, "-nocrl") == 0) { + nocrl = 1; + } else if (strcmp(*argv, "-out") == 0) { + if (--argc < 1) + goto bad; + outfile = *(++argv); + } else if (strcmp(*argv, "-certfile") == 0) { + if (--argc < 1) + goto bad; + if (!certflst) + certflst = sk_OPENSSL_STRING_new_null(); + sk_OPENSSL_STRING_push(certflst, *(++argv)); + } else { + BIO_printf(bio_err, "unknown option %s\n", *argv); + badops = 1; + break; + } + argc--; + argv++; + } + + if (badops) { +bad: + BIO_printf(bio_err, "%s [options] <infile >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, " -certfile arg certificates file of chain to a trusted CA\n"); + BIO_printf(bio_err, " (can be used more than once)\n"); + BIO_printf(bio_err, " -nocrl no crl to load, just certs from '-certfile'\n"); + ret = 1; + goto end; + } + ERR_load_crypto_strings(); + + 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 (!nocrl) { + 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) + crl = d2i_X509_CRL_bio(in, NULL); + else if (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 (certflst) + for (i = 0; i < sk_OPENSSL_STRING_num(certflst); i++) { + certfile = sk_OPENSSL_STRING_value(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(certflst); + + if (outfile == NULL) { + BIO_set_fp(out, stdout, BIO_NOCLOSE); + } else { + if (BIO_write_filename(out, outfile) <= 0) { + perror(outfile); + goto end; + } + } + + if (outformat == FORMAT_ASN1) + i = i2d_PKCS7_bio(out, p7); + else if (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); +} + +/* + *---------------------------------------------------------------------- + * int add_certs_from_file + * + * Read a list of certificates to be checked from a file. + * + * Results: + * number of certs added if successful, -1 if not. + *---------------------------------------------------------------------- + */ +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/usr.bin/openssl/dgst.c b/usr.bin/openssl/dgst.c new file mode 100644 index 00000000000..ab64af91928 --- /dev/null +++ b/usr.bin/openssl/dgst.c @@ -0,0 +1,547 @@ +/* $OpenBSD: dgst.c,v 1.1 2014/08/26 17:47:24 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.] + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/bio.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/hmac.h> +#include <openssl/objects.h> +#include <openssl/pem.h> +#include <openssl/x509.h> + +#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, char **); + +int +dgst_main(int argc, char **argv) +{ + ENGINE *e = NULL; + 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; +#ifndef OPENSSL_NO_ENGINE + char *engine = NULL; +#endif + char *hmac_key = NULL; + char *mac_name = NULL; + STACK_OF(OPENSSL_STRING) * sigopts = NULL, *macopts = NULL; + + 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)); + } +#ifndef OPENSSL_NO_ENGINE + else if (strcmp(*argv, "-engine") == 0) { + if (--argc < 1) + break; + engine = *(++argv); + e = setup_engine(bio_err, engine, 0); + } +#endif + 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 or ENGINE)\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"); +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, "-engine e use engine e, possibly a hardware device.\n"); +#endif + + 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 (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 ((in == NULL) || (bmd == NULL)) { + ERR_print_errors(bio_err); + 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, + e, "key file"); + else + sigkey = load_key(bio_err, keyfile, keyform, 0, passin, + e, "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, e, 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, e, + (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; + sigbio = BIO_new_file(sigfile, "rb"); + siglen = EVP_PKEY_size(sigkey); + sigbuf = malloc(siglen); + 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) { + OPENSSL_cleanse(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/usr.bin/openssl/dh.c b/usr.bin/openssl/dh.c new file mode 100644 index 00000000000..447b4c800fd --- /dev/null +++ b/usr.bin/openssl/dh.c @@ -0,0 +1,308 @@ +/* $OpenBSD: dh.c,v 1.1 2014/08/26 17:47:24 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.] + */ + +#include <openssl/opensslconf.h> /* for OPENSSL_NO_DH */ + +#ifndef OPENSSL_NO_DH + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "apps.h" + +#include <openssl/bio.h> +#include <openssl/bn.h> +#include <openssl/err.h> +#include <openssl/dh.h> +#include <openssl/pem.h> +#include <openssl/x509.h> + +/* -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 + * -check - check the parameters are ok + * -noout + * -text + * -C + */ + +int dh_main(int, char **); + +int +dh_main(int argc, char **argv) +{ + DH *dh = NULL; + int i, badops = 0, text = 0; + BIO *in = NULL, *out = NULL; + int informat, outformat, check = 0, noout = 0, C = 0, ret = 1; + char *infile, *outfile, *prog; +#ifndef OPENSSL_NO_ENGINE + char *engine; +#endif + +#ifndef OPENSSL_NO_ENGINE + engine = NULL; +#endif + 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, "-in") == 0) { + if (--argc < 1) + goto bad; + infile = *(++argv); + } else if (strcmp(*argv, "-out") == 0) { + if (--argc < 1) + goto bad; + outfile = *(++argv); + } +#ifndef OPENSSL_NO_ENGINE + else if (strcmp(*argv, "-engine") == 0) { + if (--argc < 1) + goto bad; + engine = *(++argv); + } +#endif + else if (strcmp(*argv, "-check") == 0) + check = 1; + else if (strcmp(*argv, "-text") == 0) + text = 1; + else if (strcmp(*argv, "-C") == 0) + C = 1; + else if (strcmp(*argv, "-noout") == 0) + noout = 1; + else { + BIO_printf(bio_err, "unknown option %s\n", *argv); + badops = 1; + break; + } + argc--; + argv++; + } + + if (badops) { +bad: + BIO_printf(bio_err, "%s [options] <infile >outfile\n", prog); + BIO_printf(bio_err, "where options are\n"); + BIO_printf(bio_err, " -inform arg input format - one of DER PEM\n"); + BIO_printf(bio_err, " -outform arg output format - one of DER PEM\n"); + BIO_printf(bio_err, " -in arg input file\n"); + BIO_printf(bio_err, " -out arg output file\n"); + BIO_printf(bio_err, " -check check the DH parameters\n"); + BIO_printf(bio_err, " -text print a text form of the DH parameters\n"); + BIO_printf(bio_err, " -C Output C code\n"); + BIO_printf(bio_err, " -noout no output\n"); +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, " -engine e use engine e, possibly a hardware device.\n"); +#endif + goto end; + } + ERR_load_crypto_strings(); + +#ifndef OPENSSL_NO_ENGINE + setup_engine(bio_err, engine, 0); +#endif + + 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 (infile == NULL) + BIO_set_fp(in, stdin, BIO_NOCLOSE); + else { + if (BIO_read_filename(in, infile) <= 0) { + perror(infile); + 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 (informat == FORMAT_ASN1) + dh = d2i_DHparams_bio(in, NULL); + else if (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 (text) { + DHparams_print(out, dh); +#ifdef undef + printf("p="); + BN_print(stdout, dh->p); + printf("\ng="); + BN_print(stdout, dh->g); + printf("\n"); + if (dh->length != 0) + printf("recommended private length=%ld\n", dh->length); +#endif + } + if (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 (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 (!noout) { + if (outformat == FORMAT_ASN1) + i = i2d_DHparams_bio(out, dh); + else if (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/usr.bin/openssl/dhparam.c b/usr.bin/openssl/dhparam.c new file mode 100644 index 00000000000..0022f726701 --- /dev/null +++ b/usr.bin/openssl/dhparam.c @@ -0,0 +1,472 @@ +/* $OpenBSD: dhparam.c,v 1.1 2014/08/26 17:47:24 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-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 <openssl/opensslconf.h> /* for OPENSSL_NO_DH */ + +#ifndef OPENSSL_NO_DH + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "apps.h" + +#include <openssl/bio.h> +#include <openssl/bn.h> +#include <openssl/err.h> +#include <openssl/dh.h> +#include <openssl/pem.h> +#include <openssl/x509.h> + +#include <openssl/dsa.h> + +#define DEFBITS 512 + +/* -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 + * -dsaparam - read or generate DSA parameters, convert to DH + * -check - check the parameters are ok + * -noout + * -text + * -C + */ + +static int dh_cb(int p, int n, BN_GENCB * cb); + +int dhparam_main(int, char **); + +int +dhparam_main(int argc, char **argv) +{ + DH *dh = NULL; + int i, badops = 0, text = 0; + int dsaparam = 0; + BIO *in = NULL, *out = NULL; + int informat, outformat, check = 0, noout = 0, C = 0, ret = 1; + char *infile, *outfile, *prog; +#ifndef OPENSSL_NO_ENGINE + char *engine = NULL; +#endif + int num = 0, g = 0; + + 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, "-in") == 0) { + if (--argc < 1) + goto bad; + infile = *(++argv); + } else if (strcmp(*argv, "-out") == 0) { + if (--argc < 1) + goto bad; + outfile = *(++argv); + } +#ifndef OPENSSL_NO_ENGINE + else if (strcmp(*argv, "-engine") == 0) { + if (--argc < 1) + goto bad; + engine = *(++argv); + } +#endif + else if (strcmp(*argv, "-check") == 0) + check = 1; + else if (strcmp(*argv, "-text") == 0) + text = 1; + else if (strcmp(*argv, "-dsaparam") == 0) + dsaparam = 1; + else if (strcmp(*argv, "-C") == 0) + C = 1; + else if (strcmp(*argv, "-noout") == 0) + noout = 1; + else if (strcmp(*argv, "-2") == 0) + g = 2; + else if (strcmp(*argv, "-5") == 0) + g = 5; + else if (((sscanf(*argv, "%d", &num) == 0) || (num <= 0))) + goto bad; + argv++; + argc--; + } + + if (badops) { +bad: + BIO_printf(bio_err, "%s [options] [numbits]\n", prog); + BIO_printf(bio_err, "where options are\n"); + BIO_printf(bio_err, " -inform arg input format - one of DER PEM\n"); + BIO_printf(bio_err, " -outform arg output format - one of DER PEM\n"); + BIO_printf(bio_err, " -in arg input file\n"); + BIO_printf(bio_err, " -out arg output file\n"); + BIO_printf(bio_err, " -dsaparam read or generate DSA parameters, convert to DH\n"); + BIO_printf(bio_err, " -check check the DH parameters\n"); + BIO_printf(bio_err, " -text print a text form of the DH parameters\n"); + BIO_printf(bio_err, " -C Output C code\n"); + BIO_printf(bio_err, " -2 generate parameters using 2 as the generator value\n"); + BIO_printf(bio_err, " -5 generate parameters using 5 as the generator value\n"); + BIO_printf(bio_err, " numbits number of bits in to generate (default 512)\n"); +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, " -engine e use engine e, possibly a hardware device.\n"); +#endif + BIO_printf(bio_err, " -noout no output\n"); + goto end; + } + ERR_load_crypto_strings(); + +#ifndef OPENSSL_NO_ENGINE + setup_engine(bio_err, engine, 0); +#endif + + if (g && !num) + num = DEFBITS; + + if (dsaparam) { + if (g) { + BIO_printf(bio_err, "generator may not be chosen for DSA parameters\n"); + goto end; + } + } else + { + /* DH parameters */ + if (num && !g) + g = 2; + } + + if (num) { + + BN_GENCB cb; + BN_GENCB_set(&cb, dh_cb, bio_err); + if (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, g); + BIO_printf(bio_err, "This is going to take a long time\n"); + if (!dh || !DH_generate_parameters_ex(dh, num, 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 (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 && informat != FORMAT_PEM) { + BIO_printf(bio_err, "bad input format specified\n"); + goto end; + } + if (dsaparam) { + DSA *dsa; + + if (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 (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 (outfile == NULL) { + BIO_set_fp(out, stdout, BIO_NOCLOSE); + } else { + if (BIO_write_filename(out, outfile) <= 0) { + perror(outfile); + goto end; + } + } + + + if (text) { + DHparams_print(out, dh); + } + if (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 (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 <openssl/dh.h>\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 (!noout) { + if (outformat == FORMAT_ASN1) + i = i2d_DHparams_bio(out, dh); + else if (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/usr.bin/openssl/dsa.c b/usr.bin/openssl/dsa.c new file mode 100644 index 00000000000..b8ca7dd2ef2 --- /dev/null +++ b/usr.bin/openssl/dsa.c @@ -0,0 +1,332 @@ +/* $OpenBSD: dsa.c,v 1.1 2014/08/26 17:47:24 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.] + */ + +#include <openssl/opensslconf.h> /* for OPENSSL_NO_DSA */ + + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/bio.h> +#include <openssl/bn.h> +#include <openssl/dsa.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/pem.h> +#include <openssl/x509.h> + +/* -inform arg - input format - default PEM (one of DER, NET or PEM) + * -outform arg - output format - default PEM + * -in arg - input file - default stdin + * -out arg - output file - default stdout + * -des - encrypt output if PEM format with DES in cbc mode + * -des3 - encrypt output if PEM format + * -idea - encrypt output if PEM format + * -aes128 - encrypt output if PEM format + * -aes192 - encrypt output if PEM format + * -aes256 - encrypt output if PEM format + * -camellia128 - encrypt output if PEM format + * -camellia192 - encrypt output if PEM format + * -camellia256 - encrypt output if PEM format + * -seed - encrypt output if PEM format + * -text - print a text version + * -modulus - print the DSA public key + */ + +int dsa_main(int, char **); + +int +dsa_main(int argc, char **argv) +{ + ENGINE *e = NULL; + int ret = 1; + DSA *dsa = NULL; + int i, badops = 0; + const EVP_CIPHER *enc = NULL; + BIO *in = NULL, *out = NULL; + int informat, outformat, text = 0, noout = 0; + int pubin = 0, pubout = 0; + char *infile, *outfile, *prog; +#ifndef OPENSSL_NO_ENGINE + char *engine; +#endif + char *passargin = NULL, *passargout = NULL; + char *passin = NULL, *passout = NULL; + int modulus = 0; + + int pvk_encr = 2; + +#ifndef OPENSSL_NO_ENGINE + engine = NULL; +#endif + 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, "-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, "-passin") == 0) { + if (--argc < 1) + goto bad; + passargin = *(++argv); + } else if (strcmp(*argv, "-passout") == 0) { + if (--argc < 1) + goto bad; + passargout = *(++argv); + } +#ifndef OPENSSL_NO_ENGINE + else if (strcmp(*argv, "-engine") == 0) { + if (--argc < 1) + goto bad; + engine = *(++argv); + } +#endif + else if (strcmp(*argv, "-pvk-strong") == 0) + pvk_encr = 2; + else if (strcmp(*argv, "-pvk-weak") == 0) + pvk_encr = 1; + else if (strcmp(*argv, "-pvk-none") == 0) + pvk_encr = 0; + else if (strcmp(*argv, "-noout") == 0) + noout = 1; + else if (strcmp(*argv, "-text") == 0) + text = 1; + else if (strcmp(*argv, "-modulus") == 0) + modulus = 1; + else if (strcmp(*argv, "-pubin") == 0) + pubin = 1; + else if (strcmp(*argv, "-pubout") == 0) + pubout = 1; + else if ((enc = EVP_get_cipherbyname(&(argv[0][1]))) == NULL) { + BIO_printf(bio_err, "unknown option %s\n", *argv); + badops = 1; + break; + } + argc--; + argv++; + } + + if (badops) { +bad: + BIO_printf(bio_err, "%s [options] <infile >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, " -passin arg input file pass phrase source\n"); + BIO_printf(bio_err, " -out arg output file\n"); + BIO_printf(bio_err, " -passout arg output file pass phrase source\n"); +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, " -engine e use engine e, possibly a hardware device.\n"); +#endif + BIO_printf(bio_err, " -des encrypt PEM output with cbc des\n"); + BIO_printf(bio_err, " -des3 encrypt PEM output with ede cbc des using 168 bit key\n"); +#ifndef OPENSSL_NO_IDEA + BIO_printf(bio_err, " -idea encrypt PEM output with cbc 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, " -text print the key in text\n"); + BIO_printf(bio_err, " -noout don't print key out\n"); + BIO_printf(bio_err, " -modulus print the DSA public value\n"); + goto end; + } + ERR_load_crypto_strings(); + +#ifndef OPENSSL_NO_ENGINE + e = setup_engine(bio_err, engine, 0); +#endif + + if (!app_passwd(bio_err, passargin, 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 (infile == NULL) + BIO_set_fp(in, stdin, BIO_NOCLOSE); + else { + if (BIO_read_filename(in, infile) <= 0) { + perror(infile); + goto end; + } + } + + BIO_printf(bio_err, "read DSA key\n"); + + { + EVP_PKEY *pkey; + + if (pubin) + pkey = load_pubkey(bio_err, infile, informat, 1, + passin, e, "Public Key"); + else + pkey = load_key(bio_err, infile, informat, 1, + passin, e, "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 (outfile == NULL) { + BIO_set_fp(out, stdout, BIO_NOCLOSE); + } else { + if (BIO_write_filename(out, outfile) <= 0) { + perror(outfile); + goto end; + } + } + + if (text) { + if (!DSA_print(out, dsa, 0)) { + perror(outfile); + ERR_print_errors(bio_err); + goto end; + } + } + if (modulus) { + fprintf(stdout, "Public Key="); + BN_print(out, dsa->pub_key); + fprintf(stdout, "\n"); + } + if (noout) + goto end; + BIO_printf(bio_err, "writing DSA key\n"); + if (outformat == FORMAT_ASN1) { + if (pubin || pubout) + i = i2d_DSA_PUBKEY_bio(out, dsa); + else + i = i2d_DSAPrivateKey_bio(out, dsa); + } else if (outformat == FORMAT_PEM) { + if (pubin || pubout) + i = PEM_write_bio_DSA_PUBKEY(out, dsa); + else + i = PEM_write_bio_DSAPrivateKey(out, dsa, enc, + NULL, 0, NULL, passout); +#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_RC4) + } else if (outformat == FORMAT_MSBLOB || outformat == FORMAT_PVK) { + EVP_PKEY *pk; + pk = EVP_PKEY_new(); + EVP_PKEY_set1_DSA(pk, dsa); + if (outformat == FORMAT_PVK) + i = i2b_PVK_bio(out, pk, pvk_encr, 0, passout); + else if (pubin || 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/usr.bin/openssl/dsaparam.c b/usr.bin/openssl/dsaparam.c new file mode 100644 index 00000000000..5c17a2c9ac2 --- /dev/null +++ b/usr.bin/openssl/dsaparam.c @@ -0,0 +1,414 @@ +/* $OpenBSD: dsaparam.c,v 1.1 2014/08/26 17:47:24 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.] + */ + +#include <openssl/opensslconf.h> /* 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "apps.h" + +#include <openssl/bio.h> +#include <openssl/bn.h> +#include <openssl/err.h> +#include <openssl/dsa.h> +#include <openssl/pem.h> +#include <openssl/x509.h> + +/* -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 + * -noout + * -text + * -C + * -noout + * -genkey + * #ifdef GENCB_TEST + * -timebomb n - interrupt keygen after <n> seconds + * #endif + */ + +#ifdef GENCB_TEST + +static int stop_keygen_flag = 0; + +static void +timebomb_sigalarm(int foo) +{ + stop_keygen_flag = 1; +} + +#endif + +static int dsa_cb(int p, int n, BN_GENCB * cb); + +int dsaparam_main(int, char **); + +int +dsaparam_main(int argc, char **argv) +{ + DSA *dsa = NULL; + int i, badops = 0, text = 0; + BIO *in = NULL, *out = NULL; + int informat, outformat, noout = 0, C = 0, ret = 1; + char *infile, *outfile, *prog; + int numbits = -1, num, genkey = 0; +#ifndef OPENSSL_NO_ENGINE + char *engine = NULL; +#endif +#ifdef GENCB_TEST + const char *errstr = NULL; + int timebomb = 0; +#endif + + 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, "-in") == 0) { + if (--argc < 1) + goto bad; + infile = *(++argv); + } else if (strcmp(*argv, "-out") == 0) { + if (--argc < 1) + goto bad; + outfile = *(++argv); + } +#ifndef OPENSSL_NO_ENGINE + else if (strcmp(*argv, "-engine") == 0) { + if (--argc < 1) + goto bad; + engine = *(++argv); + } +#endif +#ifdef GENCB_TEST + else if (strcmp(*argv, "-timebomb") == 0) { + if (--argc < 1) + goto bad; + timebomb = strtonum(*(++argv), 0, INT_MAX, &errstr); + if (errstr) + goto bad; + } +#endif + else if (strcmp(*argv, "-text") == 0) + text = 1; + else if (strcmp(*argv, "-C") == 0) + C = 1; + else if (strcmp(*argv, "-genkey") == 0) { + genkey = 1; + } else if (strcmp(*argv, "-noout") == 0) + noout = 1; + else if (sscanf(*argv, "%d", &num) == 1) { + /* generate a key */ + numbits = num; + } else { + BIO_printf(bio_err, "unknown option %s\n", *argv); + badops = 1; + break; + } + argc--; + argv++; + } + + if (badops) { +bad: + BIO_printf(bio_err, "%s [options] [bits] <infile >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 print as text\n"); + BIO_printf(bio_err, " -C Output C code\n"); + BIO_printf(bio_err, " -noout no output\n"); + BIO_printf(bio_err, " -genkey generate a DSA key\n"); +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, " -engine e use engine e, possibly a hardware device.\n"); +#endif +#ifdef GENCB_TEST + BIO_printf(bio_err, " -timebomb n interrupt keygen after <n> seconds\n"); +#endif + BIO_printf(bio_err, " number number of bits to use for generating private key\n"); + goto end; + } + ERR_load_crypto_strings(); + + 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 (infile == NULL) + BIO_set_fp(in, stdin, BIO_NOCLOSE); + else { + if (BIO_read_filename(in, infile) <= 0) { + perror(infile); + goto end; + } + } + if (outfile == NULL) { + BIO_set_fp(out, stdout, BIO_NOCLOSE); + } else { + if (BIO_write_filename(out, outfile) <= 0) { + perror(outfile); + goto end; + } + } + +#ifndef OPENSSL_NO_ENGINE + setup_engine(bio_err, engine, 0); +#endif + + 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", num); + BIO_printf(bio_err, "This could take some time\n"); +#ifdef GENCB_TEST + if (timebomb > 0) { + struct sigaction act; + act.sa_handler = timebomb_sigalarm; + act.sa_flags = 0; + BIO_printf(bio_err, "(though I'll stop it if not done within %d secs)\n", + timebomb); + if (sigaction(SIGALRM, &act, NULL) != 0) { + BIO_printf(bio_err, "Error, couldn't set SIGALRM handler\n"); + goto end; + } + alarm(timebomb); + } +#endif + if (!DSA_generate_parameters_ex(dsa, num, NULL, 0, NULL, NULL, &cb)) { +#ifdef GENCB_TEST + if (stop_keygen_flag) { + BIO_printf(bio_err, "DSA key generation time-stopped\n"); + /* This is an asked-for behaviour! */ + ret = 0; + goto end; + } +#endif + ERR_print_errors(bio_err); + BIO_printf(bio_err, "Error, DSA key generation failed\n"); + goto end; + } + } else if (informat == FORMAT_ASN1) + dsa = d2i_DSAparams_bio(in, NULL); + else if (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 (text) { + DSAparams_print(out, dsa); + } + if (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 (!noout) { + if (outformat == FORMAT_ASN1) + i = i2d_DSAparams_bio(out, dsa); + else if (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 (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 (outformat == FORMAT_ASN1) + i = i2d_DSAPrivateKey_bio(out, dsakey); + else if (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/usr.bin/openssl/ec.c b/usr.bin/openssl/ec.c new file mode 100644 index 00000000000..f1bdf55e334 --- /dev/null +++ b/usr.bin/openssl/ec.c @@ -0,0 +1,341 @@ +/* $OpenBSD: ec.c,v 1.1 2014/08/26 17:47:24 jsing 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 <openssl/opensslconf.h> + +#ifndef OPENSSL_NO_EC + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/bio.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/pem.h> + +/* -inform arg - input format - default PEM (one of DER, NET or PEM) + * -outform arg - output format - default PEM + * -in arg - input file - default stdin + * -out arg - output file - default stdout + * -des - encrypt output if PEM format with DES in cbc mode + * -text - print a text version + * -param_out - print the elliptic curve parameters + * -conv_form arg - specifies the point encoding form + * -param_enc arg - specifies the parameter encoding + */ + +int ec_main(int, char **); + +int +ec_main(int argc, char **argv) +{ + int ret = 1; + EC_KEY *eckey = NULL; + const EC_GROUP *group; + int i, badops = 0; + const EVP_CIPHER *enc = NULL; + BIO *in = NULL, *out = NULL; + int informat, outformat, text = 0, noout = 0; + int pubin = 0, pubout = 0, param_out = 0; + char *infile, *outfile, *prog, *engine; + char *passargin = NULL, *passargout = NULL; + char *passin = NULL, *passout = NULL; + point_conversion_form_t form = POINT_CONVERSION_UNCOMPRESSED; + int new_form = 0; + int asn1_flag = OPENSSL_EC_NAMED_CURVE; + int new_asn1_flag = 0; + + engine = NULL; + 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, "-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, "-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, "-engine") == 0) { + if (--argc < 1) + goto bad; + engine = *(++argv); + } else if (strcmp(*argv, "-noout") == 0) + noout = 1; + else if (strcmp(*argv, "-text") == 0) + text = 1; + else if (strcmp(*argv, "-conv_form") == 0) { + if (--argc < 1) + goto bad; + ++argv; + new_form = 1; + if (strcmp(*argv, "compressed") == 0) + form = POINT_CONVERSION_COMPRESSED; + else if (strcmp(*argv, "uncompressed") == 0) + form = POINT_CONVERSION_UNCOMPRESSED; + else if (strcmp(*argv, "hybrid") == 0) + form = POINT_CONVERSION_HYBRID; + else + goto bad; + } else if (strcmp(*argv, "-param_enc") == 0) { + if (--argc < 1) + goto bad; + ++argv; + new_asn1_flag = 1; + if (strcmp(*argv, "named_curve") == 0) + asn1_flag = OPENSSL_EC_NAMED_CURVE; + else if (strcmp(*argv, "explicit") == 0) + asn1_flag = 0; + else + goto bad; + } else if (strcmp(*argv, "-param_out") == 0) + param_out = 1; + else if (strcmp(*argv, "-pubin") == 0) + pubin = 1; + else if (strcmp(*argv, "-pubout") == 0) + pubout = 1; + else if ((enc = EVP_get_cipherbyname(&(argv[0][1]))) == NULL) { + BIO_printf(bio_err, "unknown option %s\n", *argv); + badops = 1; + break; + } + argc--; + argv++; + } + + if (badops) { +bad: + BIO_printf(bio_err, "%s [options] <infile >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, " -passin arg input file pass " + "phrase source\n"); + BIO_printf(bio_err, " -out arg output file\n"); + BIO_printf(bio_err, " -passout arg output file pass " + "phrase source\n"); + BIO_printf(bio_err, " -engine e use engine e, " + "possibly a hardware device.\n"); + BIO_printf(bio_err, " -des encrypt PEM output, " + "instead of 'des' every other \n" + " cipher " + "supported by OpenSSL can be used\n"); + BIO_printf(bio_err, " -text print the key\n"); + BIO_printf(bio_err, " -noout don't print key out\n"); + BIO_printf(bio_err, " -param_out print the elliptic " + "curve parameters\n"); + BIO_printf(bio_err, " -conv_form arg specifies the " + "point conversion form \n"); + BIO_printf(bio_err, " possible values:" + " compressed\n"); + BIO_printf(bio_err, " " + " uncompressed (default)\n"); + BIO_printf(bio_err, " " + " hybrid\n"); + BIO_printf(bio_err, " -param_enc arg specifies the way" + " the ec parameters are encoded\n"); + BIO_printf(bio_err, " in the asn1 der " + "encoding\n"); + BIO_printf(bio_err, " possible values:" + " named_curve (default)\n"); + BIO_printf(bio_err, " " + "explicit\n"); + goto end; + } + ERR_load_crypto_strings(); + +#ifndef OPENSSL_NO_ENGINE + setup_engine(bio_err, engine, 0); +#endif + + if (!app_passwd(bio_err, passargin, 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 (infile == NULL) + BIO_set_fp(in, stdin, BIO_NOCLOSE); + else { + if (BIO_read_filename(in, infile) <= 0) { + perror(infile); + goto end; + } + } + + BIO_printf(bio_err, "read EC key\n"); + if (informat == FORMAT_ASN1) { + if (pubin) + eckey = d2i_EC_PUBKEY_bio(in, NULL); + else + eckey = d2i_ECPrivateKey_bio(in, NULL); + } else if (informat == FORMAT_PEM) { + if (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 (outfile == NULL) { + BIO_set_fp(out, stdout, BIO_NOCLOSE); + } else { + if (BIO_write_filename(out, outfile) <= 0) { + perror(outfile); + goto end; + } + } + + group = EC_KEY_get0_group(eckey); + + if (new_form) + EC_KEY_set_conv_form(eckey, form); + + if (new_asn1_flag) + EC_KEY_set_asn1_flag(eckey, asn1_flag); + + if (text) + if (!EC_KEY_print(out, eckey, 0)) { + perror(outfile); + ERR_print_errors(bio_err); + goto end; + } + if (noout) { + ret = 0; + goto end; + } + BIO_printf(bio_err, "writing EC key\n"); + if (outformat == FORMAT_ASN1) { + if (param_out) + i = i2d_ECPKParameters_bio(out, group); + else if (pubin || pubout) + i = i2d_EC_PUBKEY_bio(out, eckey); + else + i = i2d_ECPrivateKey_bio(out, eckey); + } else if (outformat == FORMAT_PEM) { + if (param_out) + i = PEM_write_bio_ECPKParameters(out, group); + else if (pubin || pubout) + i = PEM_write_bio_EC_PUBKEY(out, eckey); + else + i = PEM_write_bio_ECPrivateKey(out, eckey, 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/usr.bin/openssl/ecparam.c b/usr.bin/openssl/ecparam.c new file mode 100644 index 00000000000..9623cb96ce1 --- /dev/null +++ b/usr.bin/openssl/ecparam.c @@ -0,0 +1,613 @@ +/* $OpenBSD: ecparam.c,v 1.1 2014/08/26 17:47:24 jsing 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 <openssl/opensslconf.h> + +#ifndef OPENSSL_NO_EC + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "apps.h" + +#include <openssl/bio.h> +#include <openssl/bn.h> +#include <openssl/ec.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/x509.h> + +/* -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 + * -noout - do not print the ec parameter + * -text - print the ec parameters in text form + * -check - validate the ec parameters + * -C - print a 'C' function creating the parameters + * -name arg - use the ec parameters with 'short name' name + * -list_curves - prints a list of all currently available curve 'short names' + * -conv_form arg - specifies the point conversion form + * - possible values: compressed + * uncompressed (default) + * hybrid + * -param_enc arg - specifies the way the ec parameters are encoded + * in the asn1 der encoding + * possible values: named_curve (default) + * explicit + * -no_seed - if 'explicit' parameters are chosen do not use the seed + * -genkey - generate ec key + * -engine e - use engine e, possibly a hardware device + */ + + +static int ecparam_print_var(BIO *, BIGNUM *, const char *, int, unsigned char *); + +int ecparam_main(int, char **); + +int +ecparam_main(int argc, char **argv) +{ + EC_GROUP *group = NULL; + point_conversion_form_t form = POINT_CONVERSION_UNCOMPRESSED; + int new_form = 0; + int asn1_flag = OPENSSL_EC_NAMED_CURVE; + int new_asn1_flag = 0; + char *curve_name = NULL; + int list_curves = 0, no_seed = 0, check = 0, badops = 0, text = 0, + i, genkey = 0; + char *infile = NULL, *outfile = NULL, *prog; + BIO *in = NULL, *out = NULL; + int informat, outformat, noout = 0, C = 0, ret = 1; + char *engine = NULL; + + BIGNUM *ec_p = NULL, *ec_a = NULL, *ec_b = NULL, *ec_gen = NULL, + *ec_order = NULL, *ec_cofactor = NULL; + unsigned char *buffer = 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, "-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, "-text") == 0) + text = 1; + else if (strcmp(*argv, "-C") == 0) + C = 1; + else if (strcmp(*argv, "-check") == 0) + check = 1; + else if (strcmp(*argv, "-name") == 0) { + if (--argc < 1) + goto bad; + curve_name = *(++argv); + } else if (strcmp(*argv, "-list_curves") == 0) + list_curves = 1; + else if (strcmp(*argv, "-conv_form") == 0) { + if (--argc < 1) + goto bad; + ++argv; + new_form = 1; + if (strcmp(*argv, "compressed") == 0) + form = POINT_CONVERSION_COMPRESSED; + else if (strcmp(*argv, "uncompressed") == 0) + form = POINT_CONVERSION_UNCOMPRESSED; + else if (strcmp(*argv, "hybrid") == 0) + form = POINT_CONVERSION_HYBRID; + else + goto bad; + } else if (strcmp(*argv, "-param_enc") == 0) { + if (--argc < 1) + goto bad; + ++argv; + new_asn1_flag = 1; + if (strcmp(*argv, "named_curve") == 0) + asn1_flag = OPENSSL_EC_NAMED_CURVE; + else if (strcmp(*argv, "explicit") == 0) + asn1_flag = 0; + else + goto bad; + } else if (strcmp(*argv, "-no_seed") == 0) + no_seed = 1; + else if (strcmp(*argv, "-noout") == 0) + noout = 1; + else if (strcmp(*argv, "-genkey") == 0) { + genkey = 1; + } else if (strcmp(*argv, "-engine") == 0) { + if (--argc < 1) + goto bad; + engine = *(++argv); + } else { + BIO_printf(bio_err, "unknown option %s\n", *argv); + badops = 1; + break; + } + argc--; + argv++; + } + + if (badops) { +bad: + BIO_printf(bio_err, "%s [options] <infile >outfile\n", prog); + BIO_printf(bio_err, "where options are\n"); + BIO_printf(bio_err, " -inform arg input format - " + "default PEM (DER or PEM)\n"); + BIO_printf(bio_err, " -outform arg output format - " + "default PEM\n"); + BIO_printf(bio_err, " -in arg input file - " + "default stdin\n"); + BIO_printf(bio_err, " -out arg output file - " + "default stdout\n"); + BIO_printf(bio_err, " -noout do not print the " + "ec parameter\n"); + BIO_printf(bio_err, " -text print the ec " + "parameters in text form\n"); + BIO_printf(bio_err, " -check validate the ec " + "parameters\n"); + BIO_printf(bio_err, " -C print a 'C' " + "function creating the parameters\n"); + BIO_printf(bio_err, " -name arg use the " + "ec parameters with 'short name' name\n"); + BIO_printf(bio_err, " -list_curves prints a list of " + "all currently available curve 'short names'\n"); + BIO_printf(bio_err, " -conv_form arg specifies the " + "point conversion form \n"); + BIO_printf(bio_err, " possible values:" + " compressed\n"); + BIO_printf(bio_err, " " + " uncompressed (default)\n"); + BIO_printf(bio_err, " " + " hybrid\n"); + BIO_printf(bio_err, " -param_enc arg specifies the way" + " the ec parameters are encoded\n"); + BIO_printf(bio_err, " in the asn1 der " + "encoding\n"); + BIO_printf(bio_err, " possible values:" + " named_curve (default)\n"); + BIO_printf(bio_err, " " + " explicit\n"); + BIO_printf(bio_err, " -no_seed if 'explicit'" + " parameters are chosen do not" + " use the seed\n"); + BIO_printf(bio_err, " -genkey generate ec" + " key\n"); + BIO_printf(bio_err, " -engine e use engine e, " + "possibly a hardware device\n"); + goto end; + } + ERR_load_crypto_strings(); + + 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 (infile == NULL) + BIO_set_fp(in, stdin, BIO_NOCLOSE); + else { + if (BIO_read_filename(in, infile) <= 0) { + perror(infile); + goto end; + } + } + if (outfile == NULL) { + BIO_set_fp(out, stdout, BIO_NOCLOSE); + } else { + if (BIO_write_filename(out, outfile) <= 0) { + perror(outfile); + goto end; + } + } + +#ifndef OPENSSL_NO_ENGINE + setup_engine(bio_err, engine, 0); +#endif + + if (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 (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(curve_name, "secp192r1")) { + BIO_printf(bio_err, "using curve name prime192v1 " + "instead of secp192r1\n"); + nid = NID_X9_62_prime192v1; + } else if (!strcmp(curve_name, "secp256r1")) { + BIO_printf(bio_err, "using curve name prime256v1 " + "instead of secp256r1\n"); + nid = NID_X9_62_prime256v1; + } else + nid = OBJ_sn2nid(curve_name); + + if (nid == 0) { + BIO_printf(bio_err, "unknown curve name (%s)\n", + 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", + curve_name); + goto end; + } + EC_GROUP_set_asn1_flag(group, asn1_flag); + EC_GROUP_set_point_conversion_form(group, form); + } else if (informat == FORMAT_ASN1) { + group = d2i_ECPKParameters_bio(in, NULL); + } else if (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 (new_form) + EC_GROUP_set_point_conversion_form(group, form); + + if (new_asn1_flag) + EC_GROUP_set_asn1_flag(group, asn1_flag); + + if (no_seed) { + EC_GROUP_set_seed(group, NULL, 0); + } + if (text) { + if (!ECPKParameters_print(out, group, 0)) + goto end; + } + if (check) { + if (group == NULL) + BIO_printf(bio_err, "no elliptic curve parameters\n"); + 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 (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 { + /* TODO */ + 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; + + if (!ec_p || !ec_a || !ec_b || !ec_gen || + !ec_order || !ec_cofactor) + 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 { + /* TODO */ + goto end; + } + 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 (!noout) { + if (outformat == FORMAT_ASN1) + i = i2d_ECPKParameters_bio(out, group); + else if (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 (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 (outformat == FORMAT_ASN1) + i = i2d_ECPrivateKey_bio(out, eckey); + else if (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: + if (ec_p) + BN_free(ec_p); + if (ec_a) + BN_free(ec_a); + if (ec_b) + BN_free(ec_b); + if (ec_gen) + BN_free(ec_gen); + if (ec_order) + BN_free(ec_order); + if (ec_cofactor) + BN_free(ec_cofactor); + free(buffer); + BIO_free(in); + if (out != NULL) + BIO_free_all(out); + if (group != NULL) + 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/usr.bin/openssl/enc.c b/usr.bin/openssl/enc.c new file mode 100644 index 00000000000..eff49818f9a --- /dev/null +++ b/usr.bin/openssl/enc.c @@ -0,0 +1,649 @@ +/* $OpenBSD: enc.c,v 1.1 2014/08/26 17:47:24 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.] + */ + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/bio.h> +#include <openssl/comp.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/objects.h> +#include <openssl/pem.h> +#include <openssl/rand.h> +#include <openssl/x509.h> + +int set_hex(char *in, unsigned char *out, int size); + +#define SIZE (512) +#define BSIZE (8*1024) +#define PROG enc_main + +static void +show_ciphers(const OBJ_NAME * name, void *bio_) +{ + BIO *bio = bio_; + static int n; + + if (!islower((unsigned char) *name->name)) + return; + + BIO_printf(bio, "-%-25s", name->name); + if (++n == 3) { + BIO_printf(bio, "\n"); + n = 0; + } else + BIO_printf(bio, " "); +} + +int enc_main(int, char **); + +int +enc_main(int argc, char **argv) +{ + static const char magic[] = "Salted__"; + char mbuf[sizeof magic - 1]; + char *strbuf = NULL; + unsigned char *buff = NULL, *bufsize = NULL; + int bsize = BSIZE, verbose = 0; + int ret = 1, inl; + int nopad = 0; + unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH]; + unsigned char salt[PKCS5_SALT_LEN]; + char *str = NULL, *passarg = NULL, *pass = NULL; + char *hkey = NULL, *hiv = NULL, *hsalt = NULL; + char *md = NULL; + int enc = 1, printkey = 0, i, base64 = 0; +#ifdef ZLIB + int do_zlib = 0; + BIO *bzl = NULL; +#endif + int debug = 0, olb64 = 0, nosalt = 0; + const EVP_CIPHER *cipher = NULL, *c; + EVP_CIPHER_CTX *ctx = NULL; + char *inf = NULL, *outf = NULL; + BIO *in = NULL, *out = NULL, *b64 = NULL, *benc = NULL, *rbio = NULL, + *wbio = NULL; +#define PROG_NAME_SIZE 39 + char pname[PROG_NAME_SIZE + 1]; +#ifndef OPENSSL_NO_ENGINE + char *engine = NULL; +#endif + const EVP_MD *dgst = NULL; + + /* first check the program name */ + program_name(argv[0], pname, sizeof pname); + if (strcmp(pname, "base64") == 0) + base64 = 1; +#ifdef ZLIB + if (strcmp(pname, "zlib") == 0) + do_zlib = 1; +#endif + + cipher = EVP_get_cipherbyname(pname); +#ifdef ZLIB + if (!do_zlib && !base64 && (cipher == NULL) + && (strcmp(pname, "enc") != 0)) +#else + if (!base64 && (cipher == NULL) && (strcmp(pname, "enc") != 0)) +#endif + { + BIO_printf(bio_err, "%s is an unknown cipher\n", pname); + goto bad; + } + argc--; + argv++; + while (argc >= 1) { + if (strcmp(*argv, "-e") == 0) + enc = 1; + else if (strcmp(*argv, "-in") == 0) { + if (--argc < 1) + goto bad; + inf = *(++argv); + } else if (strcmp(*argv, "-out") == 0) { + if (--argc < 1) + goto bad; + outf = *(++argv); + } else if (strcmp(*argv, "-pass") == 0) { + if (--argc < 1) + goto bad; + passarg = *(++argv); + } +#ifndef OPENSSL_NO_ENGINE + else if (strcmp(*argv, "-engine") == 0) { + if (--argc < 1) + goto bad; + engine = *(++argv); + } +#endif + else if (strcmp(*argv, "-d") == 0) + enc = 0; + else if (strcmp(*argv, "-p") == 0) + printkey = 1; + else if (strcmp(*argv, "-v") == 0) + verbose = 1; + else if (strcmp(*argv, "-nopad") == 0) + nopad = 1; + else if (strcmp(*argv, "-salt") == 0) + nosalt = 0; + else if (strcmp(*argv, "-nosalt") == 0) + nosalt = 1; + else if (strcmp(*argv, "-debug") == 0) + debug = 1; + else if (strcmp(*argv, "-P") == 0) + printkey = 2; + else if (strcmp(*argv, "-A") == 0) + olb64 = 1; + else if (strcmp(*argv, "-a") == 0) + base64 = 1; + else if (strcmp(*argv, "-base64") == 0) + base64 = 1; +#ifdef ZLIB + else if (strcmp(*argv, "-z") == 0) + do_zlib = 1; +#endif + else if (strcmp(*argv, "-bufsize") == 0) { + if (--argc < 1) + goto bad; + bufsize = (unsigned char *) *(++argv); + } else if (strcmp(*argv, "-k") == 0) { + if (--argc < 1) + goto bad; + str = *(++argv); + } else if (strcmp(*argv, "-kfile") == 0) { + static char buf[128]; + FILE *infile; + char *file; + + if (--argc < 1) + goto bad; + file = *(++argv); + infile = fopen(file, "r"); + if (infile == NULL) { + BIO_printf(bio_err, "unable to read key from '%s'\n", + file); + goto bad; + } + buf[0] = '\0'; + if (!fgets(buf, sizeof buf, infile)) { + BIO_printf(bio_err, "unable to read key from '%s'\n", + file); + fclose(infile); + goto bad; + } + 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 bad; + } + str = buf; + } else if (strcmp(*argv, "-K") == 0) { + if (--argc < 1) + goto bad; + hkey = *(++argv); + } else if (strcmp(*argv, "-S") == 0) { + if (--argc < 1) + goto bad; + hsalt = *(++argv); + } else if (strcmp(*argv, "-iv") == 0) { + if (--argc < 1) + goto bad; + hiv = *(++argv); + } else if (strcmp(*argv, "-md") == 0) { + if (--argc < 1) + goto bad; + md = *(++argv); + } else if ((argv[0][0] == '-') && + ((c = EVP_get_cipherbyname(&(argv[0][1]))) != NULL)) { + cipher = c; + } else if (strcmp(*argv, "-none") == 0) + cipher = NULL; + else { + BIO_printf(bio_err, "unknown option '%s'\n", *argv); + bad: + BIO_printf(bio_err, "options are\n"); + BIO_printf(bio_err, "%-14s input file\n", "-in <file>"); + BIO_printf(bio_err, "%-14s output file\n", "-out <file>"); + BIO_printf(bio_err, "%-14s pass phrase source\n", "-pass <arg>"); + BIO_printf(bio_err, "%-14s encrypt\n", "-e"); + BIO_printf(bio_err, "%-14s decrypt\n", "-d"); + BIO_printf(bio_err, "%-14s base64 encode/decode, depending on encryption flag\n", "-a/-base64"); + BIO_printf(bio_err, "%-14s passphrase is the next argument\n", "-k"); + BIO_printf(bio_err, "%-14s passphrase is the first line of the file argument\n", "-kfile"); + BIO_printf(bio_err, "%-14s the next argument is the md to use to create a key\n", "-md"); + BIO_printf(bio_err, "%-14s from a passphrase. One of md2, md5, sha or sha1\n", ""); + BIO_printf(bio_err, "%-14s salt in hex is the next argument\n", "-S"); + BIO_printf(bio_err, "%-14s key/iv in hex is the next argument\n", "-K/-iv"); + BIO_printf(bio_err, "%-14s print the iv/key (then exit if -P)\n", "-[pP]"); + BIO_printf(bio_err, "%-14s buffer size\n", "-bufsize <n>"); + BIO_printf(bio_err, "%-14s disable standard block padding\n", "-nopad"); +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, "%-14s use engine e, possibly a hardware device.\n", "-engine e"); +#endif + + BIO_printf(bio_err, "Cipher Types\n"); + OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH, + show_ciphers, + bio_err); + BIO_printf(bio_err, "\n"); + + goto end; + } + argc--; + argv++; + } + +#ifndef OPENSSL_NO_ENGINE + setup_engine(bio_err, engine, 0); +#endif + + if (md && (dgst = EVP_get_digestbyname(md)) == NULL) { + BIO_printf(bio_err, "%s is an unsupported message digest type\n", md); + goto end; + } + if (dgst == NULL) { + dgst = EVP_md5(); + } + if (bufsize != NULL) { + unsigned long n; + + for (n = 0; *bufsize; bufsize++) { + i = *bufsize; + if ((i <= '9') && (i >= '0')) + n = n * 10 + i - '0'; + else if (i == 'k') { + n *= 1024; + bufsize++; + break; + } + } + if (*bufsize != '\0') { + BIO_printf(bio_err, "invalid 'bufsize' specified.\n"); + goto end; + } + /* It must be large enough for a base64 encoded line */ + if (base64 && n < 80) + n = 80; + + bsize = (int) n; + if (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 (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 (inf == NULL) { + if (bufsize != NULL) + setvbuf(stdin, (char *) NULL, _IONBF, 0); + BIO_set_fp(in, stdin, BIO_NOCLOSE); + } else { + if (BIO_read_filename(in, inf) <= 0) { + perror(inf); + goto end; + } + } + + if (!str && passarg) { + if (!app_passwd(bio_err, passarg, NULL, &pass, NULL)) { + BIO_printf(bio_err, "Error getting password\n"); + goto end; + } + str = pass; + } + if ((str == NULL) && (cipher != NULL) && (hkey == NULL)) { + for (;;) { + char buf[200]; + int ret; + + ret = snprintf(buf, sizeof buf, "enter %s %s password:", + OBJ_nid2ln(EVP_CIPHER_nid(cipher)), + (enc) ? "encryption" : "decryption"); + if (ret == -1 || ret >= 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); + if (i == 0) { + if (strbuf[0] == '\0') { + ret = 1; + goto end; + } + str = strbuf; + break; + } + if (i < 0) { + BIO_printf(bio_err, "bad password read\n"); + goto end; + } + } + } + if (outf == NULL) { + BIO_set_fp(out, stdout, BIO_NOCLOSE); + if (bufsize != NULL) + setvbuf(stdout, (char *) NULL, _IONBF, 0); + } else { + if (BIO_write_filename(out, outf) <= 0) { + perror(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 (base64) { + if ((b64 = BIO_new(BIO_f_base64())) == NULL) + goto end; + if (debug) { + BIO_set_callback(b64, BIO_debug_callback); + BIO_set_callback_arg(b64, (char *) bio_err); + } + if (olb64) + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + if (enc) + wbio = BIO_push(b64, wbio); + else + rbio = BIO_push(b64, rbio); + } + if (cipher != NULL) { + /* + * Note that str is NULL if a key was passed on the command + * line, so we get no salt in that case. Is this a bug? + */ + if (str != NULL) { + /* + * Salt handling: if encrypting generate a salt and + * write to output BIO. If decrypting read salt from + * input BIO. + */ + unsigned char *sptr; + if (nosalt) + sptr = NULL; + else { + if (enc) { + if (hsalt) { + if (!set_hex(hsalt, salt, sizeof salt)) { + BIO_printf(bio_err, + "invalid hex salt value\n"); + goto end; + } + } else if (RAND_pseudo_bytes(salt, sizeof salt) < 0) + goto end; + /* + * If -P option then don't bother + * writing + */ + if ((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(cipher, dgst, sptr, + (unsigned char *) str, + strlen(str), 1, key, iv); + /* + * zero the complete buffer or the string passed from + * the command line bug picked up by Larry J. Hughes + * Jr. <hughes@indiana.edu> + */ + if (str == strbuf) + OPENSSL_cleanse(str, SIZE); + else + OPENSSL_cleanse(str, strlen(str)); + } + if ((hiv != NULL) && !set_hex(hiv, iv, sizeof iv)) { + BIO_printf(bio_err, "invalid hex iv value\n"); + goto end; + } + if ((hiv == NULL) && (str == NULL) + && EVP_CIPHER_iv_length(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 ((hkey != NULL) && !set_hex(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, cipher, NULL, NULL, NULL, enc)) { + BIO_printf(bio_err, "Error setting cipher %s\n", + EVP_CIPHER_name(cipher)); + ERR_print_errors(bio_err); + goto end; + } + if (nopad) + EVP_CIPHER_CTX_set_padding(ctx, 0); + + if (!EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, enc)) { + BIO_printf(bio_err, "Error setting cipher %s\n", + EVP_CIPHER_name(cipher)); + ERR_print_errors(bio_err); + goto end; + } + if (debug) { + BIO_set_callback(benc, BIO_debug_callback); + BIO_set_callback_arg(benc, (char *) bio_err); + } + if (printkey) { + if (!nosalt) { + printf("salt="); + for (i = 0; i < (int) sizeof(salt); i++) + printf("%02X", salt[i]); + printf("\n"); + } + if (cipher->key_len > 0) { + printf("key="); + for (i = 0; i < cipher->key_len; i++) + printf("%02X", key[i]); + printf("\n"); + } + if (cipher->iv_len > 0) { + printf("iv ="); + for (i = 0; i < cipher->iv_len; i++) + printf("%02X", iv[i]); + printf("\n"); + } + if (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 (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/usr.bin/openssl/engine.c b/usr.bin/openssl/engine.c new file mode 100644 index 00000000000..2d24e07254b --- /dev/null +++ b/usr.bin/openssl/engine.c @@ -0,0 +1,494 @@ +/* $OpenBSD: engine.c,v 1.1 2014/08/26 17:47:24 jsing Exp $ */ +/* Written by Richard Levitte <richard@levitte.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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "apps.h" + +#ifndef OPENSSL_NO_ENGINE +#include <openssl/engine.h> +#include <openssl/err.h> +#include <openssl/ssl.h> + +static const char *engine_usage[] = { + "usage: engine opts [engine ...]\n", + " -v[v[v[v]]] - verbose mode, for each engine, list its 'control commands'\n", + " -vv will additionally display each command's description\n", + " -vvv will also add the input flags for each command\n", + " -vvvv will also show internal input flags\n", + " -c - for each engine, also list the capabilities\n", + " -t[t] - for each engine, check that they are really available\n", + " -tt will display error trace for unavailable engines\n", + " -pre <cmd> - runs command 'cmd' against the ENGINE before any attempts\n", + " to load it (if -t is used)\n", + " -post <cmd> - runs command 'cmd' against the ENGINE after loading it\n", + " (only used if -t is also provided)\n", + " NB: -pre and -post will be applied to all ENGINEs supplied on the command\n", + " line, or all supported ENGINEs if none are specified.\n", + " Eg. '-pre \"SO_PATH:/lib/libdriver.so\"' calls command \"SO_PATH\" with\n", + " argument \"/lib/libdriver.so\".\n", + NULL +}; + +static void +identity(char *ptr) +{ + return; +} + +static int +append_buf(char **buf, const char *s, int *size, int step) +{ + int l = strlen(s); + + if (*buf == NULL) { + *size = step; + *buf = malloc(*size); + if (*buf == NULL) + return 0; + **buf = '\0'; + } + if (**buf != '\0') + l += 2; /* ", " */ + + if (strlen(*buf) + strlen(s) >= (unsigned int) *size) { + *size += step; + *buf = realloc(*buf, *size); + } + if (*buf == NULL) + return 0; + + if (**buf != '\0') + strlcat(*buf, ", ", *size); + strlcat(*buf, s, *size); + + return 1; +} + +static int +util_flags(BIO * bio_out, unsigned int flags, const char *indent) +{ + int started = 0, err = 0; + /* Indent before displaying input flags */ + BIO_printf(bio_out, "%s%s(input flags): ", indent, indent); + if (flags == 0) { + BIO_printf(bio_out, "<no flags>\n"); + return 1; + } + /* + * If the object is internal, mark it in a way that shows instead of + * having it part of all the other flags, even if it really is. + */ + if (flags & ENGINE_CMD_FLAG_INTERNAL) { + BIO_printf(bio_out, "[Internal] "); + } + if (flags & ENGINE_CMD_FLAG_NUMERIC) { + BIO_printf(bio_out, "NUMERIC"); + started = 1; + } + /* + * Now we check that no combinations of the mutually exclusive + * NUMERIC, STRING, and NO_INPUT flags have been used. Future flags + * that can be OR'd together with these would need to added after + * these to preserve the testing logic. + */ + if (flags & ENGINE_CMD_FLAG_STRING) { + if (started) { + BIO_printf(bio_out, "|"); + err = 1; + } + BIO_printf(bio_out, "STRING"); + started = 1; + } + if (flags & ENGINE_CMD_FLAG_NO_INPUT) { + if (started) { + BIO_printf(bio_out, "|"); + err = 1; + } + BIO_printf(bio_out, "NO_INPUT"); + started = 1; + } + /* Check for unknown flags */ + flags = flags & ~ENGINE_CMD_FLAG_NUMERIC & + ~ENGINE_CMD_FLAG_STRING & + ~ENGINE_CMD_FLAG_NO_INPUT & + ~ENGINE_CMD_FLAG_INTERNAL; + if (flags) { + if (started) + BIO_printf(bio_out, "|"); + BIO_printf(bio_out, "<0x%04X>", flags); + } + if (err) + BIO_printf(bio_out, " <illegal flags!>"); + BIO_printf(bio_out, "\n"); + return 1; +} + +static int +util_verbose(ENGINE * e, int verbose, BIO * bio_out, const char *indent) +{ + static const int line_wrap = 78; + int num; + int ret = 0; + char *name = NULL; + char *desc = NULL; + int flags; + int xpos = 0; + STACK_OF(OPENSSL_STRING) * cmds = NULL; + if (!ENGINE_ctrl(e, ENGINE_CTRL_HAS_CTRL_FUNCTION, 0, NULL, NULL) || + ((num = ENGINE_ctrl(e, ENGINE_CTRL_GET_FIRST_CMD_TYPE, + 0, NULL, NULL)) <= 0)) { +#if 0 + BIO_printf(bio_out, "%s<no control commands>\n", indent); +#endif + return 1; + } + cmds = sk_OPENSSL_STRING_new_null(); + + if (!cmds) + goto err; + do { + int len; + /* Get the command input flags */ + if ((flags = ENGINE_ctrl(e, ENGINE_CTRL_GET_CMD_FLAGS, num, + NULL, NULL)) < 0) + goto err; + if (!(flags & ENGINE_CMD_FLAG_INTERNAL) || verbose >= 4) { + /* Get the command name */ + if ((len = ENGINE_ctrl(e, ENGINE_CTRL_GET_NAME_LEN_FROM_CMD, num, + NULL, NULL)) <= 0) + goto err; + if ((name = malloc(len + 1)) == NULL) + goto err; + if (ENGINE_ctrl(e, ENGINE_CTRL_GET_NAME_FROM_CMD, num, name, + NULL) <= 0) + goto err; + /* Get the command description */ + if ((len = ENGINE_ctrl(e, ENGINE_CTRL_GET_DESC_LEN_FROM_CMD, num, + NULL, NULL)) < 0) + goto err; + if (len > 0) { + if ((desc = malloc(len + 1)) == NULL) + goto err; + if (ENGINE_ctrl(e, ENGINE_CTRL_GET_DESC_FROM_CMD, num, desc, + NULL) <= 0) + goto err; + } + /* Now decide on the output */ + if (xpos == 0) + /* Do an indent */ + xpos = BIO_puts(bio_out, indent); + else + /* Otherwise prepend a ", " */ + xpos += BIO_printf(bio_out, ", "); + if (verbose == 1) { + /* We're just listing names, comma-delimited */ + if ((xpos > (int) strlen(indent)) && + (xpos + (int) strlen(name) > line_wrap)) { + BIO_printf(bio_out, "\n"); + xpos = BIO_puts(bio_out, indent); + } + xpos += BIO_printf(bio_out, "%s", name); + } else { + /* We're listing names plus descriptions */ + BIO_printf(bio_out, "%s: %s\n", name, + (desc == NULL) ? "<no description>" : desc); + /* ... and sometimes input flags */ + if ((verbose >= 3) && !util_flags(bio_out, flags, + indent)) + goto err; + xpos = 0; + } + } + free(name); + name = NULL; + free(desc); + desc = NULL; + + /* Move to the next command */ + num = ENGINE_ctrl(e, ENGINE_CTRL_GET_NEXT_CMD_TYPE, + num, NULL, NULL); + } while (num > 0); + if (xpos > 0) + BIO_printf(bio_out, "\n"); + ret = 1; +err: + if (cmds) + sk_OPENSSL_STRING_pop_free(cmds, identity); + free(name); + free(desc); + return ret; +} + +static void +util_do_cmds(ENGINE * e, STACK_OF(OPENSSL_STRING) * cmds, + BIO * bio_out, const char *indent) +{ + int loop, res, num = sk_OPENSSL_STRING_num(cmds); + + if (num < 0) { + BIO_printf(bio_out, "[Error]: internal stack error\n"); + return; + } + for (loop = 0; loop < num; loop++) { + char buf[256]; + const char *cmd, *arg; + cmd = sk_OPENSSL_STRING_value(cmds, loop); + res = 1; /* assume success */ + /* Check if this command has no ":arg" */ + if ((arg = strstr(cmd, ":")) == NULL) { + if (!ENGINE_ctrl_cmd_string(e, cmd, NULL, 0)) + res = 0; + } else { + if ((int) (arg - cmd) > 254) { + BIO_printf(bio_out, "[Error]: command name too long\n"); + return; + } + memcpy(buf, cmd, (int) (arg - cmd)); + buf[arg - cmd] = '\0'; + arg++; /* Move past the ":" */ + /* Call the command with the argument */ + if (!ENGINE_ctrl_cmd_string(e, buf, arg, 0)) + res = 0; + } + if (res) + BIO_printf(bio_out, "[Success]: %s\n", cmd); + else { + BIO_printf(bio_out, "[Failure]: %s\n", cmd); + ERR_print_errors(bio_out); + } + } +} + +int engine_main(int, char **); + +int +engine_main(int argc, char **argv) +{ + int ret = 1, i; + const char **pp; + int verbose = 0, list_cap = 0, test_avail = 0, test_avail_noise = 0; + ENGINE *e; + STACK_OF(OPENSSL_STRING) * engines = sk_OPENSSL_STRING_new_null(); + STACK_OF(OPENSSL_STRING) * pre_cmds = sk_OPENSSL_STRING_new_null(); + STACK_OF(OPENSSL_STRING) * post_cmds = sk_OPENSSL_STRING_new_null(); + int badops = 1; + BIO *bio_out = NULL; + const char *indent = " "; + + bio_out = BIO_new_fp(stdout, BIO_NOCLOSE); + + argc--; + argv++; + while (argc >= 1) { + if (strncmp(*argv, "-v", 2) == 0) { + if (strspn(*argv + 1, "v") < strlen(*argv + 1)) + goto skip_arg_loop; + if ((verbose = strlen(*argv + 1)) > 4) + goto skip_arg_loop; + } else if (strcmp(*argv, "-c") == 0) + list_cap = 1; + else if (strncmp(*argv, "-t", 2) == 0) { + test_avail = 1; + if (strspn(*argv + 1, "t") < strlen(*argv + 1)) + goto skip_arg_loop; + if ((test_avail_noise = strlen(*argv + 1) - 1) > 1) + goto skip_arg_loop; + } else if (strcmp(*argv, "-pre") == 0) { + argc--; + argv++; + if (argc == 0) + goto skip_arg_loop; + sk_OPENSSL_STRING_push(pre_cmds, *argv); + } else if (strcmp(*argv, "-post") == 0) { + argc--; + argv++; + if (argc == 0) + goto skip_arg_loop; + sk_OPENSSL_STRING_push(post_cmds, *argv); + } else if ((strncmp(*argv, "-h", 2) == 0) || + (strcmp(*argv, "-?") == 0)) + goto skip_arg_loop; + else + sk_OPENSSL_STRING_push(engines, *argv); + argc--; + argv++; + } + /* Looks like everything went OK */ + badops = 0; +skip_arg_loop: + + if (badops) { + for (pp = engine_usage; (*pp != NULL); pp++) + BIO_printf(bio_err, "%s", *pp); + goto end; + } + if (sk_OPENSSL_STRING_num(engines) == 0) { + for (e = ENGINE_get_first(); e != NULL; e = ENGINE_get_next(e)) { + sk_OPENSSL_STRING_push(engines, (char *) ENGINE_get_id(e)); + } + } + for (i = 0; i < sk_OPENSSL_STRING_num(engines); i++) { + const char *id = sk_OPENSSL_STRING_value(engines, i); + if ((e = ENGINE_by_id(id)) != NULL) { + const char *name = ENGINE_get_name(e); + /* Do "id" first, then "name". Easier to auto-parse. */ + BIO_printf(bio_out, "(%s) %s\n", id, name); + util_do_cmds(e, pre_cmds, bio_out, indent); + if (strcmp(ENGINE_get_id(e), id) != 0) { + BIO_printf(bio_out, "Loaded: (%s) %s\n", + ENGINE_get_id(e), ENGINE_get_name(e)); + } + if (list_cap) { + int cap_size = 256; + char *cap_buf = NULL; + int k, n; + const int *nids; + ENGINE_CIPHERS_PTR fn_c; + ENGINE_DIGESTS_PTR fn_d; + ENGINE_PKEY_METHS_PTR fn_pk; + + if (ENGINE_get_RSA(e) != NULL + && !append_buf(&cap_buf, "RSA", + &cap_size, 256)) + goto end; + if (ENGINE_get_DSA(e) != NULL + && !append_buf(&cap_buf, "DSA", + &cap_size, 256)) + goto end; + if (ENGINE_get_DH(e) != NULL + && !append_buf(&cap_buf, "DH", + &cap_size, 256)) + goto end; + if (ENGINE_get_RAND(e) != NULL + && !append_buf(&cap_buf, "RAND", + &cap_size, 256)) + goto end; + + fn_c = ENGINE_get_ciphers(e); + if (!fn_c) + goto skip_ciphers; + n = fn_c(e, NULL, &nids, 0); + for (k = 0; k < n; ++k) + if (!append_buf(&cap_buf, + OBJ_nid2sn(nids[k]), + &cap_size, 256)) + goto end; + + skip_ciphers: + fn_d = ENGINE_get_digests(e); + if (!fn_d) + goto skip_digests; + n = fn_d(e, NULL, &nids, 0); + for (k = 0; k < n; ++k) + if (!append_buf(&cap_buf, + OBJ_nid2sn(nids[k]), + &cap_size, 256)) + goto end; + + skip_digests: + fn_pk = ENGINE_get_pkey_meths(e); + if (!fn_pk) + goto skip_pmeths; + n = fn_pk(e, NULL, &nids, 0); + for (k = 0; k < n; ++k) + if (!append_buf(&cap_buf, + OBJ_nid2sn(nids[k]), + &cap_size, 256)) + goto end; + skip_pmeths: + if (cap_buf && (*cap_buf != '\0')) + BIO_printf(bio_out, " [%s]\n", cap_buf); + + free(cap_buf); + } + if (test_avail) { + BIO_printf(bio_out, "%s", indent); + if (ENGINE_init(e)) { + BIO_printf(bio_out, "[ available ]\n"); + util_do_cmds(e, post_cmds, bio_out, indent); + ENGINE_finish(e); + } else { + BIO_printf(bio_out, "[ unavailable ]\n"); + if (test_avail_noise) + ERR_print_errors_fp(stdout); + ERR_clear_error(); + } + } + if ((verbose > 0) && !util_verbose(e, verbose, bio_out, indent)) + goto end; + ENGINE_free(e); + } else + ERR_print_errors(bio_err); + } + + ret = 0; +end: + + ERR_print_errors(bio_err); + sk_OPENSSL_STRING_pop_free(engines, identity); + sk_OPENSSL_STRING_pop_free(pre_cmds, identity); + sk_OPENSSL_STRING_pop_free(post_cmds, identity); + if (bio_out != NULL) + BIO_free_all(bio_out); + + return (ret); +} +#endif diff --git a/usr.bin/openssl/errstr.c b/usr.bin/openssl/errstr.c new file mode 100644 index 00000000000..163da2e5b37 --- /dev/null +++ b/usr.bin/openssl/errstr.c @@ -0,0 +1,108 @@ +/* $OpenBSD: errstr.c,v 1.1 2014/08/26 17:47:24 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.] + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/bio.h> +#include <openssl/err.h> +#include <openssl/lhash.h> +#include <openssl/ssl.h> + +int errstr_main(int, char **); + +int +errstr_main(int argc, char **argv) +{ + int i, ret = 0; + char buf[256]; + unsigned long l; + + if ((argc > 1) && (strcmp(argv[1], "-stats") == 0)) { + BIO *out = NULL; + + out = BIO_new(BIO_s_file()); + if ((out != NULL) && BIO_set_fp(out, stdout, BIO_NOCLOSE)) { + 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); + } + if (out != NULL) + BIO_free_all(out); + argc--; + argv++; + } + for (i = 1; i < argc; i++) { + if (sscanf(argv[i], "%lx", &l)) { + ERR_error_string_n(l, buf, sizeof buf); + printf("%s\n", buf); + } else { + printf("%s: bad error code\n", argv[i]); + printf("usage: errstr [-stats] <errno> ...\n"); + ret++; + } + } + + return (ret); +} diff --git a/usr.bin/openssl/gendh.c b/usr.bin/openssl/gendh.c new file mode 100644 index 00000000000..06d62c1b0d3 --- /dev/null +++ b/usr.bin/openssl/gendh.c @@ -0,0 +1,204 @@ +/* $OpenBSD: gendh.c,v 1.1 2014/08/26 17:47:24 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.] + */ + +#include <openssl/opensslconf.h> + +/* 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 <sys/types.h> +#include <sys/stat.h> + +#include <stdio.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/bio.h> +#include <openssl/bn.h> +#include <openssl/dh.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/rand.h> +#include <openssl/x509.h> + +#define DEFBITS 512 + +static int dh_cb(int p, int n, BN_GENCB * cb); + +int gendh_main(int, char **); + +int +gendh_main(int argc, char **argv) +{ + BN_GENCB cb; + DH *dh = NULL; + int ret = 1, num = DEFBITS; + int g = 2; + char *outfile = NULL; +#ifndef OPENSSL_NO_ENGINE + char *engine = NULL; +#endif + BIO *out = NULL; + + BN_GENCB_set(&cb, dh_cb, bio_err); + + argv++; + argc--; + for (;;) { + if (argc <= 0) + break; + if (strcmp(*argv, "-out") == 0) { + if (--argc < 1) + goto bad; + outfile = *(++argv); + } else if (strcmp(*argv, "-2") == 0) + g = 2; + /* + * else if (strcmp(*argv,"-3") == 0) g=3; + */ + else if (strcmp(*argv, "-5") == 0) + g = 5; +#ifndef OPENSSL_NO_ENGINE + else if (strcmp(*argv, "-engine") == 0) { + if (--argc < 1) + goto bad; + engine = *(++argv); + } +#endif + else + break; + argv++; + argc--; + } + if ((argc >= 1) && ((sscanf(*argv, "%d", &num) == 0) || (num < 0))) { +bad: + BIO_printf(bio_err, "usage: gendh [args] [numbits]\n"); + BIO_printf(bio_err, " -out file - output the key to 'file\n"); + BIO_printf(bio_err, " -2 - use 2 as the generator value\n"); + /* + * BIO_printf(bio_err," -3 - use 3 as the generator + * value\n"); + */ + BIO_printf(bio_err, " -5 - use 5 as the generator value\n"); +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, " -engine e - use engine e, possibly a hardware device.\n"); +#endif + goto end; + } +#ifndef OPENSSL_NO_ENGINE + setup_engine(bio_err, engine, 0); +#endif + + 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; + } + } + + BIO_printf(bio_err, "Generating DH parameters, %d bit long safe prime, generator %d\n", num, g); + BIO_printf(bio_err, "This is going to take a long time\n"); + + if (((dh = DH_new()) == NULL) || !DH_generate_parameters_ex(dh, num, 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/usr.bin/openssl/gendsa.c b/usr.bin/openssl/gendsa.c new file mode 100644 index 00000000000..7c9f568830c --- /dev/null +++ b/usr.bin/openssl/gendsa.c @@ -0,0 +1,230 @@ +/* $OpenBSD: gendsa.c,v 1.1 2014/08/26 17:47:24 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.] + */ + +#include <openssl/opensslconf.h> /* for OPENSSL_NO_DSA */ + + +#include <sys/types.h> +#include <sys/stat.h> + +#include <stdio.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/bio.h> +#include <openssl/bn.h> +#include <openssl/dsa.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/x509.h> + +#define DEFBITS 512 + +int gendsa_main(int, char **); + +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; +#ifndef OPENSSL_NO_ENGINE + char *engine = NULL; +#endif + + 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); + } +#ifndef OPENSSL_NO_ENGINE + else if (strcmp(*argv, "-engine") == 0) { + if (--argc < 1) + goto bad; + engine = *(++argv); + } +#endif + 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 +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, " -engine e - use engine e, possibly a hardware device.\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; + } +#ifndef OPENSSL_NO_ENGINE + setup_engine(bio_err, engine, 0); +#endif + + 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/usr.bin/openssl/genpkey.c b/usr.bin/openssl/genpkey.c new file mode 100644 index 00000000000..02332f66825 --- /dev/null +++ b/usr.bin/openssl/genpkey.c @@ -0,0 +1,383 @@ +/* $OpenBSD: genpkey.c,v 1.1 2014/08/26 17:47:24 jsing 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 <stdio.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/pem.h> + +#ifndef OPENSSL_NO_ENGINE +#include <openssl/engine.h> +#endif + +static int +init_keygen_file(BIO * err, EVP_PKEY_CTX ** pctx, const char *file, + ENGINE * e); +static int genpkey_cb(EVP_PKEY_CTX * ctx); + + +int genpkey_main(int, char **); + +int +genpkey_main(int argc, char **argv) +{ + ENGINE *e = NULL; + 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; + + outformat = FORMAT_PEM; + + ERR_load_crypto_strings(); + OpenSSL_add_all_algorithms(); + 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); + } +#ifndef OPENSSL_NO_ENGINE + else if (strcmp(*args, "-engine") == 0) { + if (!args[1]) + goto bad; + e = setup_engine(bio_err, *(++args), 0); + } +#endif + 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, e)) + 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), e, 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, "-<cipher> use cipher <cipher> to encrypt the key\n"); +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, "-engine e use engine e, possibly a hardware device.\n"); +#endif + 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 <opt>\n" + " to value <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, ENGINE * e) +{ + 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, e); + 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, ENGINE * e, int do_param) +{ + EVP_PKEY_CTX *ctx = NULL; + const EVP_PKEY_ASN1_METHOD *ameth; + ENGINE *tmpeng = NULL; + int pkey_id; + + if (*pctx) { + BIO_puts(err, "Algorithm already set!\n"); + return 0; + } + ameth = EVP_PKEY_asn1_find_str(&tmpeng, algname, -1); + +#ifndef OPENSSL_NO_ENGINE + if (!ameth && e) + ameth = ENGINE_get_pkey_asn1_meth_str(e, algname, -1); +#endif + + 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); +#ifndef OPENSSL_NO_ENGINE + if (tmpeng) + ENGINE_finish(tmpeng); +#endif + ctx = EVP_PKEY_CTX_new_id(pkey_id, e); + + 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/usr.bin/openssl/genrsa.c b/usr.bin/openssl/genrsa.c new file mode 100644 index 00000000000..7844fb815fb --- /dev/null +++ b/usr.bin/openssl/genrsa.c @@ -0,0 +1,286 @@ +/* $OpenBSD: genrsa.c,v 1.1 2014/08/26 17:47:24 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.] + */ + +#include <openssl/opensslconf.h> + +/* 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 <sys/types.h> +#include <sys/stat.h> + +#include <stdio.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/bio.h> +#include <openssl/bn.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/pem.h> +#include <openssl/rand.h> +#include <openssl/rsa.h> +#include <openssl/x509.h> + +#define DEFBITS 2048 + +static int genrsa_cb(int p, int n, BN_GENCB * cb); + +int genrsa_main(int, char **); + +int +genrsa_main(int argc, char **argv) +{ + BN_GENCB cb; +#ifndef OPENSSL_NO_ENGINE + ENGINE *e = NULL; +#endif + 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; +#ifndef OPENSSL_NO_ENGINE + char *engine = NULL; +#endif + BIO *out = NULL; + BIGNUM *bn = BN_new(); + RSA *rsa = NULL; + + 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_ENGINE + else if (strcmp(*argv, "-engine") == 0) { + if (--argc < 1) + goto bad; + engine = *(++argv); + } +#endif +#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"); +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, " -engine e use engine e, possibly a hardware device.\n"); +#endif + goto err; + } + ERR_load_crypto_strings(); + + if (!app_passwd(bio_err, NULL, passargout, NULL, &passout)) { + BIO_printf(bio_err, "Error getting password\n"); + goto err; + } +#ifndef OPENSSL_NO_ENGINE + e = setup_engine(bio_err, engine, 0); +#endif + + 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); +#ifdef OPENSSL_NO_ENGINE + rsa = RSA_new(); +#else + rsa = RSA_new_method(e); +#endif + 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/usr.bin/openssl/nseq.c b/usr.bin/openssl/nseq.c new file mode 100644 index 00000000000..6c32f7c4b4c --- /dev/null +++ b/usr.bin/openssl/nseq.c @@ -0,0 +1,162 @@ +/* $OpenBSD: nseq.c,v 1.1 2014/08/26 17:47:24 jsing 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 <stdio.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/err.h> +#include <openssl/pem.h> + +int nseq_main(int, char **); + +int +nseq_main(int argc, char **argv) +{ + char **args, *infile = NULL, *outfile = NULL; + BIO *in = NULL, *out = NULL; + int toseq = 0; + X509 *x509 = NULL; + NETSCAPE_CERT_SEQUENCE *seq = NULL; + int i, ret = 1; + int badarg = 0; + + ERR_load_crypto_strings(); + + args = argv + 1; + while (!badarg && *args && *args[0] == '-') { + if (!strcmp(*args, "-toseq")) + toseq = 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 + badarg = 1; + args++; + } + + if (badarg) { + BIO_printf(bio_err, "Netscape certificate sequence utility\n"); + BIO_printf(bio_err, "Usage nseq [options]\n"); + BIO_printf(bio_err, "where options are\n"); + BIO_printf(bio_err, "-in file input file\n"); + BIO_printf(bio_err, "-out file output file\n"); + BIO_printf(bio_err, "-toseq output NS Sequence file\n"); + return (1); + } + if (infile) { + if (!(in = BIO_new_file(infile, "r"))) { + BIO_printf(bio_err, + "Can't open input file %s\n", infile); + goto end; + } + } else + in = BIO_new_fp(stdin, BIO_NOCLOSE); + + if (outfile) { + if (!(out = BIO_new_file(outfile, "w"))) { + BIO_printf(bio_err, + "Can't open output file %s\n", outfile); + goto end; + } + } else { + out = BIO_new_fp(stdout, BIO_NOCLOSE); + } + if (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", 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", 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/usr.bin/openssl/ocsp.c b/usr.bin/openssl/ocsp.c new file mode 100644 index 00000000000..bdc224d8bc1 --- /dev/null +++ b/usr.bin/openssl/ocsp.c @@ -0,0 +1,1217 @@ +/* $OpenBSD: ocsp.c,v 1.1 2014/08/26 17:47:24 jsing 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 <sys/select.h> + +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include <time.h> + +/* Needs to be included before the openssl headers! */ +#include "apps.h" + +#include <openssl/bn.h> +#include <openssl/crypto.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/ssl.h> +#include <openssl/x509v3.h> + +/* 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, char **); + +int +ocsp_main(int argc, char **argv) +{ + ENGINE *e = NULL; + 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; + + 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, e, "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, e, "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, "-<dgst alg> 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, e, "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, e, "CA certificate"); + if (rcertfile) { + rother = load_certs(bio_err, rcertfile, FORMAT_PEM, + NULL, e, "responder other certificates"); + if (!rother) + goto end; + } + rkey = load_key(bio_err, rkeyfile, FORMAT_PEM, 0, NULL, 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, e, "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, e, "signer certificates"); + if (!sign_other) + goto end; + } + key = load_key(bio_err, keyfile, FORMAT_PEM, 0, NULL, 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(out, "Responder Error: %s (%d)\n", + OCSP_response_status_str(i), i); + if (ignore_err) + goto redo_accept; + ret = 0; + 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, e, "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; + fd_set confds; + struct timeval tv; + + 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) { + FD_ZERO(&confds); + FD_SET(fd, &confds); + tv.tv_usec = 0; + tv.tv_sec = req_timeout; + rv = select(fd + 1, NULL, &confds, NULL, &tv); + if (rv == 0) { + BIO_puts(err, "Timeout on connect\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; + FD_ZERO(&confds); + FD_SET(fd, &confds); + tv.tv_usec = 0; + tv.tv_sec = req_timeout; + if (BIO_should_read(cbio)) + rv = select(fd + 1, &confds, NULL, NULL, &tv); + else if (BIO_should_write(cbio)) + rv = select(fd + 1, NULL, &confds, NULL, &tv); + else { + BIO_puts(err, "Unexpected retry condition\n"); + goto err; + } + if (rv == 0) { + BIO_puts(err, "Timeout on request\n"); + break; + } + if (rv == -1) { + BIO_puts(err, "Select 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/usr.bin/openssl/openssl.1 b/usr.bin/openssl/openssl.1 new file mode 100644 index 00000000000..b374728ba9e --- /dev/null +++ b/usr.bin/openssl/openssl.1 @@ -0,0 +1,10407 @@ +.\" $OpenBSD: openssl.1,v 1.1 2014/08/26 17:47:24 jsing 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: August 26 2014 $ +.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 \*(Ba +.Cm list-message-digest-commands \*(Ba +.Cm list-cipher-commands \*(Ba +.Cm list-cipher-algorithms \*(Ba +.Cm list-message-digest-algorithms \*(Ba +.Cm list-public-key-algorithms +.Pp +.Nm +.Cm no- Ns Ar XXX +.Op Ar arbitrary options +.Sh DESCRIPTION +.Nm OpenSSL +is a cryptography toolkit implementing the Secure Sockets Layer +.Pq SSL v3 +and Transport Layer Security +.Pq TLS v1 +network protocols and related cryptography standards required by them. +.Pp +The +.Nm +program is a command line tool for using the various +cryptography functions of +.Nm OpenSSL Ns Li 's +.Em crypto +library from the shell. +It can be used for +.Pp +.Bl -bullet -offset indent -compact +.It +Creation and management of private keys, public keys, and parameters +.It +Public key cryptographic operations +.It +Creation of X.509 certificates, CSRs and CRLs +.It +Calculation of Message Digests +.It +Encryption and Decryption with Ciphers +.It +SSL/TLS Client and Server Tests +.It +Handling of S/MIME signed or encrypted mail +.It +Time stamp requests, generation, and verification +.El +.Sh COMMAND SUMMARY +The +.Nm +program provides a rich variety of commands +.Pf ( Cm command +in the +.Sx SYNOPSIS +above), +each of which often has a wealth of options and arguments +.Pf ( Ar command_opts +and +.Ar command_args +in the +.Sx SYNOPSIS ) . +.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 =\*(Gt to +.Pp +The pseudo-command +.Cm list-public-key-algorithms +lists all supported public key algorithms. +.Pp +The pseudo-command +.Cm no- Ns Ar XXX +tests whether a command of the +specified name is available. +If no command named +.Ar XXX +exists, +it returns 0 +.Pq success +and prints +.Cm no- Ns Ar XXX ; +otherwise it returns 1 and prints +.Ar XXX . +In both cases, the output goes to +.Em stdout +and nothing is printed to +.Em 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 XXX +is not able to detect pseudo-commands such as +.Cm quit , +.Cm list- Ns Ar ... Ns Cm -commands , +or +.Cm no- Ns Ar XXX +itself. +.Sh STANDARD COMMANDS +.Bl -tag -width "asn1parse" +.It Cm asn1parse +Parse an ASN.1 sequence. +.It Cm ca +Certificate Authority +.Pq CA +management. +.It Cm ciphers +Cipher suite description determination. +.It Cm crl +Certificate Revocation List +.Pq CRL +management. +.It Cm crl2pkcs7 +CRL to PKCS#7 conversion. +.It Cm dgst +Message digest calculation. +.It Cm dh +Diffie-Hellman parameter management. +Obsoleted by +.Cm dhparam . +.It Cm dhparam +Generation and management of Diffie-Hellman parameters. +Superseded by +.Cm genpkey +and +.Cm pkeyparam . +.It Cm dsa +DSA data management. +.It Cm dsaparam +DSA parameter generation and management. +Superseded by +.Cm genpkey +and +.Cm pkeyparam . +.It Cm ec +Elliptic curve (EC) key processing. +.It Cm ecparam +EC parameter manipulation and generation. +.It Cm enc +Encoding with ciphers. +.It Cm engine +Engine (loadable module) information and manipulation. +.It Cm errstr +Error number to error string conversion. +.It Cm gendh +Generation of Diffie-Hellman parameters. +Obsoleted by +.Cm dhparam . +.It Cm gendsa +Generation of DSA private key from parameters. +Superseded by +.Cm genpkey +and +.Cm pkey . +.It Cm genpkey +Generation of private keys or parameters. +.It Cm genrsa +Generation of RSA private key. +Superseded by +.Cm genpkey . +.It Cm nseq +Create or examine a Netscape certificate sequence. +.It Cm ocsp +Online Certificate Status Protocol utility. +.It Cm passwd +Generation of hashed passwords. +.It Cm pkcs7 +PKCS#7 data management. +.It Cm pkcs8 +PKCS#8 data management. +.It Cm pkcs12 +PKCS#12 data management. +.It Cm pkey +Public and private key management. +.It Cm pkeyparam +Public key algorithm parameter management. +.It Cm pkeyutl +Public key algorithm cryptographic operation utility. +.It Cm prime +Generate prime numbers or test numbers for primality. +.It Cm rand +Generate pseudo-random bytes. +.It Cm req +PKCS#10 X.509 Certificate Signing Request +.Pq CSR +management. +.It Cm rsa +RSA key management. +.It Cm rsautl +RSA utility for signing, verification, encryption, and decryption. +Superseded by +.Cm pkeyutl . +.It Cm s_client +This implements a generic SSL/TLS client which can establish a transparent +connection to a remote server speaking SSL/TLS. +It's intended for testing purposes only and provides only rudimentary +interface functionality but internally uses mostly all functionality of the +.Nm OpenSSL +.Em ssl +library. +.It Cm s_server +This implements a generic SSL/TLS server which accepts connections from remote +clients speaking SSL/TLS. +It's intended for testing purposes only and provides only rudimentary +interface functionality but internally uses mostly all functionality of the +.Nm OpenSSL +.Em ssl +library. +It provides both an own command line oriented protocol for testing +SSL functions and a simple HTTP response +facility to emulate an SSL/TLS-aware webserver. +.It Cm s_time +SSL connection timer. +.It Cm sess_id +SSL session data management. +.It Cm smime +S/MIME mail processing. +.It Cm speed +Algorithm speed measurement. +.It Cm spkac +SPKAC printing and generating utility. +.It Cm ts +Time stamping authority tool (client/server). +.It Cm verify +X.509 certificate verification. +.It Cm version +.Nm OpenSSL +version information. +.It Cm x509 +X.509 certificate data management. +.El +.Sh MESSAGE DIGEST COMMANDS +.Bl -tag -width "asn1parse" +.It Cm md2 +MD2 digest. +.It Cm md4 +MD4 digest. +.It Cm md5 +MD5 digest. +.It Cm ripemd160 +RIPEMD-160 digest. +.It Cm sha +SHA digest. +.It Cm sha1 +SHA-1 digest. +.El +.Sh ENCODING AND CIPHER COMMANDS +.Bl -tag -width Ds -compact +.It Cm aes-128-cbc | aes-128-ecb | aes-192-cbc | aes-192-ecb +.It Cm aes-256-cbc | aes-256-ecb +AES cipher. +.Pp +.It Cm base64 +Base64 encoding. +.Pp +.It Xo +.Cm bf | bf-cbc | bf-cfb | +.Cm bf-ecb | bf-ofb +.Xc +Blowfish cipher. +.Pp +.It Cm cast | cast-cbc +CAST cipher. +.Pp +.It Cm cast5-cbc | cast5-cfb | cast5-ecb | cast5-ofb +CAST5 cipher. +.Pp +.It Xo +.Cm des | des-cbc | des-cfb | des-ecb | +.Cm des-ede | des-ede-cbc +.Xc +.It Cm des-ede-cfb | des-ede-ofb | des-ofb +DES cipher. +.Pp +.It Xo +.Cm des3 | desx | des-ede3 | +.Cm des-ede3-cbc | des-ede3-cfb | des-ede3-ofb +.Xc +Triple DES cipher. +.Pp +.It Xo +.Cm rc2 | rc2-40-cbc | rc2-64-cbc | rc2-cbc | +.Cm rc2-cfb | rc2-ecb | rc2-ofb +.Xc +RC2 cipher. +.Pp +.It Cm rc4 | rc4-40 +RC4 cipher. +.El +.Sh PASS PHRASE ARGUMENTS +Several commands accept password arguments, typically using +.Fl passin +and +.Fl passout +for input and output passwords, respectively. +These allow the password to be obtained from a variety of sources. +Both of these options take a single argument whose format is 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 "fd:number" +.It Ar pass : Ns Ar password +The actual password is +.Ar password . +Since the password is visible to utilities +(like +.Xr ps 1 +under +.Ux ) +this form should only be used where security is not important. +.It Ar env : Ns Ar var +Obtain the password from the environment variable +.Ar var . +Since the environment of other processes is visible on certain platforms +(e.g.\& +.Xr ps 1 +under certain +.Ux +OSes) this option should be used with caution. +.It Ar 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 Ar 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 Ar stdin +Read the password from standard input. +.El +.\" +.\" ASN1PARSE +.\" +.Sh ASN1PARSE +.nr nS 1 +.Nm "openssl asn1parse" +.Bk -words +.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 Ar 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 +.Ek +.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 +.Xr ASN1_generate_nconf 3 +format. +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 ASN1 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 +Indents the output according to the +.Qq depth +of the structures. +.It Fl in Ar file +The input file; default is standard input. +.It Fl inform Ar DER | PEM | TXT +The input format. +.Ar DER +.Pq Distinguished Encoding Rules +is binary format and +.Ar PEM +.Pq Privacy Enhanced Mail , +the default, is base64-encoded. +.Ar TXT +is plain text. +.It Fl length Ar number +Number of bytes to parse; default is until end of file. +.It Fl noout +Don't output the parsed version of the input file. +.It Fl offset Ar number +Starting offset to begin parsing; default is start of file. +.It Fl oid Ar file +A file containing additional object identifiers +.Pq OIDs . +The format of this file is described in the +.Sx ASN1PARSE NOTES +section below. +.It Fl out Ar file +Output file to place the DER-encoded data into. +If this option is not present, no encoded data will be output. +This is most useful when combined with the +.Fl strparse +option. +.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 ASN1PARSE OUTPUT +The output will typically contain lines like this: +.Bd -literal -offset 2n +0:d=0 hl=4 l= 681 cons: SEQUENCE + +\&..... + +229:d=3 hl=3 l= 141 prim: BIT STRING +373:d=2 hl=3 l= 162 cons: cont [ 3 ] +376:d=3 hl=3 l= 159 cons: SEQUENCE +379:d=4 hl=2 l= 29 cons: SEQUENCE +381:d=5 hl=2 l= 3 prim: OBJECT :X509v3 Subject Key Identifier +386:d=5 hl=2 l= 22 prim: OCTET STRING +410:d=4 hl=2 l= 112 cons: SEQUENCE +412:d=5 hl=2 l= 3 prim: OBJECT :X509v3 Authority Key Identifier +417:d=5 hl=2 l= 105 prim: OCTET STRING +524:d=4 hl=2 l= 12 cons: SEQUENCE + +\&..... +.Ed +.Pp +This example is part of a self-signed certificate. +Each line starts with the offset in decimal. +.Cm d=XX +specifies the current depth. +The depth is increased within the scope of any SET or SEQUENCE. +.Cm hl=XX +gives the header length +.Pq tag and length octets +of the current type. +.Cm l=XX +gives the length of the content octets. +.Pp +The +.Fl i +option can be used to make the output more readable. +.Pp +Some knowledge of the ASN.1 structure is needed to interpret the output. +.Pp +In this example, the BIT STRING at offset 229 is the certificate public key. +The content octets of this will contain the public key information. +This can be examined using the option +.Fl strparse Cm 229 +to yield: +.Bd -literal + 0:d=0 hl=3 l= 137 cons: SEQUENCE + 3:d=1 hl=3 l= 129 prim: INTEGER :E5D21E1F5C8D208EA7A2166C7FA +F9F6BDF2059669C60876DDB70840F1A5AAFA59699FE471F379F1DD6A487E7D5409AB6A88D4A +9746E24B91D8CF55DB3521015460C8EDE44EE8A4189F7A7BE77D6CD3A9AF2696F486855CF58 +BF0EDF2B4068058C7A947F52548DDF7E15E96B385F86422BEA9064A3EE9 + 135:d=1 hl=2 l= 3 prim: INTEGER :010001 +.Ed +.Sh ASN1PARSE NOTES +If an OID +.Pq object identifier +is not part of +.Nm OpenSSL Ns Li 's +internal table it will be represented in +numerical form +.Pq for example 1.2.3.4 . +The file passed to the +.Fl oid +option allows additional OIDs to be included. +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. +Example: +.Pp +.Dl \&"1.2.3.4 shortname A long name\&" +.Sh ASN1 EXAMPLES +Parse a file: +.Pp +.Dl $ openssl asn1parse -in file.pem +.Pp +Parse a DER file: +.Pp +.Dl $ openssl asn1parse -inform DER -in file.der +.Sh ASN1PARSE BUGS +There should be options to change the format of output lines. +The output of some ASN.1 types is not well handled +.Pq if at all . +.\" +.\" CA +.\" +.Sh CA +.nr nS 1 +.Nm "openssl ca" +.Bk -words +.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 engine Ar id +.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 ENGINE | 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 +.Ek +.nr nS 0 +.Pp +The +.Nm ca +command is a minimal CA application. +It can be used to sign certificate requests in a variety of forms +and generate CRLs. +It also maintains a text database of issued certificates and their status. +.Pp +The options descriptions will be divided into each purpose. +.Sh CA OPTIONS +.Bl -tag -width "XXXX" +.It Fl batch +This sets the 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 +Specifies the configuration file to use. +.It Fl days Ar arg +The number of days to certify the certificate for. +.It Fl enddate Ar date +This allows the expiry date to be explicitly set. +The format of the date is YYMMDDHHMMSSZ +.Pq the same as an ASN1 UTCTime structure . +.It Fl engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm ca +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.It Fl extensions Ar section +The section of the configuration file containing certificate extensions +to be added when a certificate is issued (defaults to +.Em 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 +(e.g.\& +.Ux +with the +.Xr ps 1 +utility) this option should be used with caution. +.It Fl keyfile Ar file +The private key to sign requests with. +.It Fl keyform Ar ENGINE | 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 e-mail set into +the +.Em 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. +For more information about the format of +.Ar arg , +see the +.Sx PASS PHRASE ARGUMENTS +section above. +.It Fl policy Ar arg +This option defines the CA +.Qq policy +to use. +This is a section in the configuration file which decides which fields +should be mandatory or match the CA certificate. +Check out the +.Sx CA POLICY FORMAT +section for more information. +.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. +See the +.Sx SPKAC FORMAT +section for information on the required format. +.It Fl ss_cert Ar file +A single self-signed certificate to be signed by the CA. +.It Fl startdate Ar date +This allows the start date to be explicitly set. +The format of the date is YYMMDDHHMMSSZ +.Pq the same as an ASN1 UTCTime structure . +.It Fl status Ar serial +Show status of certificate with serial number +.Ar serial . +.It Fl updatedb +Update database for expired certificates. +.It Fl verbose +This prints extra details about the operations being performed. +.El +.Sh CRL OPTIONS +.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 +This sets 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 +This sets 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 +.Em 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 +.Pq even if it is empty +then a V2 CRL is created. +The CRL extensions specified are CRL extensions and +.Em not +CRL entry extensions. +It should be noted that some software +.Pq for example Netscape +can't handle V2 CRLs. +.It Fl crlhours Ar num +The number of hours before the next CRL is due. +.It Fl gencrl +This option generates 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 +.Sh CA CONFIGURATION FILE OPTIONS +The section of the configuration file containing options for +.Nm ca +is found as follows: +If the +.Fl name +command line option is used, then it names the section to be used. +Otherwise the section to be used must be named in the +.Em default_ca +option of the +.Em ca +section of the configuration file (or in the default section of the +configuration file). +Besides +.Em default_ca , +the following options are read directly from the +.Em ca +section: +.Pp +.Bl -tag -width Ds -offset indent -compact +.It preserve +.It msie_hack +.El +.Pp +This is probably a bug and may change in future releases. +.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 Ar certificate +The same as +.Fl cert . +It gives the file containing the CA certificate. +Mandatory. +.It Ar copy_extensions +Determines how extensions in certificate requests should be handled. +If set to +.Ar none +or this option is not present, then extensions are +ignored and not copied to the certificate. +If set to +.Ar copy , +then any extensions present in the request that are not already present +are copied to the certificate. +If set to +.Ar 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. +See the +.Sx CA WARNINGS +section before using this option. +.Pp +The main use of this option is to allow a certificate request to supply +values for certain extensions such as +.Em subjectAltName . +.It Ar crl_extensions +The same as +.Fl crlexts . +.It Ar 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 Ar database +The text database file to use. +Mandatory. +This file must be present, though initially it will be empty. +.It Ar 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 Ar default_days +The same as the +.Fl days +option. +The number of days to certify a certificate for. +.It Ar default_enddate +The same as the +.Fl enddate +option. +Either this option or +.Ar default_days +.Pq or the command line equivalents +must be present. +.It Ar default_md +The same as the +.Fl md +option. +The message digest to use. +Mandatory. +.It Ar 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 Ar 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 Ar msie_hack +The same as +.Fl msie_hack . +.It Ar 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 +.Ar no_signame +and +.Ar 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 +.Em 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 +.Em strongly +discouraged because it only displays fields mentioned in the +.Ar policy +section, +mishandles multicharacter string types and does not display extensions. +.It Ar new_certs_dir +The same as the +.Fl outdir +command line option. +It specifies the directory where new certificates will be placed. +Mandatory. +.It Ar 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 Ar 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 Ar policy +The same as +.Fl policy . +Mandatory. +See the +.Sx CA POLICY FORMAT +section for more information. +.It Ar preserve +The same as +.Fl preserveDN . +.It Ar private_key +Same as the +.Fl keyfile +option. +The file containing the CA private key. +Mandatory. +.It Ar 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 Ar unique_subject +If the value +.Ar yes +is given, the valid certificate entries in the +database must have unique subjects. +If the value +.Ar no +is given, +several valid certificate entries may have the exact same subject. +The default value is +.Ar yes . +.It Ar x509_extensions +The same as +.Fl extensions . +.El +.Sh CA POLICY FORMAT +The policy section consists of a set of variables corresponding to +certificate DN fields. +If the value is +.Qq match , +then the field value must match the same field in the CA certificate. +If the value is +.Qq supplied , +then it must be present. +If the value is +.Qq optional , +then it 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. +.Sh SPKAC FORMAT +The input to the +.Fl spkac +command line option is a Netscape signed public key and challenge. +This will usually come from the +.Em 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 \&. . +.Sh CA EXAMPLES +.Sy Note : +these examples assume that the +.Nm ca +directory structure is already set up and the relevant files already exist. +This usually involves creating a CA certificate and private key with +.Cm req , +a serial number file and an empty index file and placing them in +the relevant directories. +.Pp +To use the sample configuration file below, the directories +.Pa demoCA , +.Pa demoCA/private +and +.Pa demoCA/newcerts +would be created. +The CA certificate would be copied to +.Pa demoCA/cacert.pem +and its private key to +.Pa demoCA/private/cakey.pem . +A file +.Pa demoCA/serial +would be created containing, for example, +.Qq 01 +and the empty index file +.Pa demoCA/index.txt . +.Pp +Sign a certificate request: +.Pp +.Dl $ openssl ca -in req.pem -out newcert.pem +.Pp +Sign a certificate request, using CA extensions: +.Pp +.Dl $ openssl ca -in req.pem -extensions v3_ca -out newcert.pem +.Pp +Generate a CRL: +.Pp +.Dl $ openssl ca -gencrl -out crl.pem +.Pp +Sign several requests: +.Pp +.Dl $ openssl ca -infiles req1.pem req2.pem req3.pem +.Pp +Certify a Netscape SPKAC: +.Pp +.Dl $ openssl ca -spkac spkac.txt +.Pp +A sample SPKAC file +.Pq the SPKAC line has been truncated for clarity : +.Bd -literal -offset indent +SPKAC=MIG0MGAwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAn7PDhCeV/xIxUg8V70YRxK +CN=Steve Test +emailAddress=steve@openssl.org +0.OU=OpenSSL Group +1.OU=Another Group +.Ed +.Pp +A sample configuration file with the relevant sections for +.Nm ca : +.Bd -literal +\& [ ca ] +\& default_ca = CA_default # The default ca section + +\& [ CA_default ] + +\& dir = ./demoCA # top dir +\& database = $dir/index.txt # index file +\& new_certs_dir = $dir/newcerts # new certs dir + +\& certificate = $dir/cacert.pem # The CA cert +\& serial = $dir/serial # serial no file +\& private_key = $dir/private/cakey.pem# CA private key + +\& default_days = 365 # how long to certify for +\& default_crl_days= 30 # how long before next CRL +\& default_md = md5 # md to use + +\& policy = policy_any # default policy +\& email_in_dn = no # Don't add the email into cert DN + +\& name_opt = ca_default # Subject name display option +\& cert_opt = ca_default # Certificate display option +\& copy_extensions = none #Don't copy extensions from request + +\& [ policy_any ] +\& countryName = supplied +\& stateOrProvinceName = optional +\& organizationName = optional +\& organizationalUnitName = optional +\& commonName = supplied +\& emailAddress = optional +.Ed +.Sh CA FILES +.Sy Note : +the location of all files can change either by compile time options, +configuration file entries, environment variables, or command line options. +The values below reflect the default values. +.Bd -literal -offset indent +/etc/ssl/openssl.cnf - master configuration file +\&./demoCA - main CA directory +\&./demoCA/cacert.pem - CA certificate +\&./demoCA/private/cakey.pem - CA private key +\&./demoCA/serial - CA serial number file +\&./demoCA/serial.old - CA serial number backup file +\&./demoCA/index.txt - CA text database file +\&./demoCA/index.txt.old - CA text database backup file +\&./demoCA/certs - certificate output file +\&./demoCA/.rnd - CA random seed information +.Ed +.Sh CA ENVIRONMENT VARIABLES +.Ev OPENSSL_CONF +reflects the location of the master configuration file; +it can be overridden by the +.Fl config +command line option. +.Sh CA RESTRICTIONS +The text database index file is a critical part of the process, +and if corrupted it can be difficult to fix. +It is theoretically possible to rebuild the index file from all the +issued certificates and a current CRL; however there is no option to do this. +.Pp +V2 CRL features like delta CRLs are not currently supported. +.Pp +Although several requests can be input and handled at once, it is only +possible to include one SPKAC or self-signed certificate. +.Sh CA BUGS +The use of an in-memory text database can cause problems when large +numbers of certificates are present because, as the name implies, +the database has to be kept in memory. +.Pp +It is not possible to certify two certificates with the same DN; this +is a side effect of how the text database is indexed and it cannot easily +be fixed without introducing other problems. +Some S/MIME clients can use two certificates with the same DN for separate +signing and encryption keys. +.Pp +The +.Nm ca +command really needs rewriting or the required functionality +exposed at either a command or interface level so a more friendly utility +.Pq perl script or GUI +can handle things properly. +The scripts +.Nm CA.sh +and +.Nm CA.pl +help a little but not very much. +.Pp +Any fields in a request that are not present in a policy are silently +deleted. +This does not happen if the +.Fl preserveDN +option is used. +To enforce the absence of the EMAIL field within the DN, as suggested +by RFCs, regardless of the contents of the request's subject the +.Fl noemailDN +option can be used. +The behaviour should be more friendly and configurable. +.Pp +Cancelling some commands by refusing to certify a certificate can +create an empty file. +.Sh CA WARNINGS +The +.Nm ca +command is quirky and at times downright unfriendly. +.Pp +The +.Nm ca +utility was originally meant as an example of how to do things in a CA. +It was not supposed to be used as a full blown CA itself: +nevertheless some people are using it for this purpose. +.Pp +The +.Nm ca +command is effectively a single user command: no locking is done on the +various files, and attempts to run more than one +.Nm ca +command on the same database can have unpredictable results. +.Pp +The +.Ar 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 +.Em basicConstraints +extension with CA:TRUE and the +.Ar copy_extensions +value is set to +.Ar 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 +.Ar copy_extensions +to +.Ar copy +and including +.Em basicConstraints +with CA:FALSE in the configuration file. +Then if the request contains a +.Em basicConstraints +extension, it will be ignored. +.Pp +It is advisable to also include values for other extensions such +as +.Ar keyUsage +to prevent a request supplying its own values. +.Pp +Additional restrictions can be placed on the CA certificate itself. +For example if the CA certificate has: +.Pp +.D1 basicConstraints = CA:TRUE, pathlen:0 +.Pp +then even if a certificate is issued with CA:TRUE it will not be valid. +.\" +.\" CIPHERS +.\" +.Sh CIPHERS +.Nm openssl ciphers +.Op Fl hVv +.Op Fl ssl3 | 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 test tool to determine the appropriate cipherlist. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl h , \&? +Print a brief usage message. +.It Fl ssl3 +Only include SSL v3 ciphers. +.It Fl tls1 +Only include TLS v1 ciphers. +.It Fl V +Like +.Fl v , +but include cipher suite codes in output (hex format). +.It Fl v +Verbose option. +List ciphers with a complete description of protocol version +.Pq SSLv3, which includes TLS , +key exchange, authentication, encryption and mac algorithms used along with +any key size restrictions and whether the algorithm is classed as an +.Em export +cipher. +Note that without the +.Fl v +option, ciphers may seem to appear twice in a cipher list; +this is when similar ciphers are available for SSL v3/TLS v1. +.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. +The format is described below. +.El +.Sh CIPHERS LIST FORMAT +The cipher list consists of one or more +.Em cipher strings +separated by colons. +Commas or spaces are also acceptable separators, but colons are normally used. +.Pp +The actual +.Em cipher string +can take several different forms: +.Pp +It can consist of a single cipher suite such as +.Em RC4-SHA . +.Pp +It can represent a list of cipher suites containing a certain algorithm, +or cipher suites of a certain type. +For example +.Em SHA1 +represents all cipher suites using the digest algorithm SHA1, and +.Em SSLv3 +represents all SSL v3 algorithms. +.Pp +Lists of cipher suites can be combined in a single +.Em cipher string +using the +.Sq + +character. +This is used as a logical +.Em and +operation. +For example, +.Em SHA1+DES +represents all cipher suites containing the SHA1 and the DES algorithms. +.Pp +Each cipher string can be optionally preceded by the characters +.Sq \&! , +.Sq - , +or +.Sq + . +.Pp +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. +.Pp +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. +.Pp +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 +.Em @STRENGTH +can be used at any point to sort the current cipher list in order of +encryption algorithm key length. +.Sh CIPHERS STRINGS +The following is a list of all permitted cipher strings and their meanings. +.Bl -tag -width "XXXX" +.It Ar DEFAULT +The default cipher list. +This is determined at compile time and is currently +.Ar ALL:!aNULL:!eNULL:!SSLv2 . +This must be the first +.Ar cipher string +specified. +.It Ar COMPLEMENTOFDEFAULT +The ciphers included in +.Ar ALL , +but not enabled by default. +Currently this is +.Ar ADH . +Note that this rule does not cover +.Ar eNULL , +which is not included by +.Ar ALL +(use +.Ar COMPLEMENTOFALL +if necessary). +.It Ar ALL +All cipher suites except the +.Ar eNULL +ciphers which must be explicitly enabled. +.It Ar COMPLEMENTOFALL +The cipher suites not enabled by +.Ar ALL , +currently being +.Ar eNULL . +.It Ar HIGH +.Qq High +encryption cipher suites. +This currently means those with key lengths larger than 128 bits. +.It Ar MEDIUM +.Qq Medium +encryption cipher suites, currently those using 128-bit encryption. +.It Ar LOW +.Qq Low +encryption cipher suites, currently those using 64- or 56-bit encryption +algorithms, but excluding export cipher suites. +.It Ar EXP , EXPORT +Export encryption algorithms. +Including 40- and 56-bit algorithms. +.It Ar EXPORT40 +40-bit export encryption algorithms. +.It Ar 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 Ar 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 Ar kRSA , RSA +Cipher suites using RSA key exchange. +.It Ar kEDH +Cipher suites using ephemeral DH key agreement. +.It Ar aRSA +Cipher suites using RSA authentication, i.e. the certificates carry RSA keys. +.It Ar aDSS , DSS +Cipher suites using DSS authentication, i.e. the certificates carry DSS keys. +.It Ar TLSv1 , SSLv3 +TLS v1.0 or SSL v3.0 cipher suites, respectively. +.It Ar DH +Cipher suites using DH, including anonymous DH. +.It Ar ADH +Anonymous DH cipher suites. +.It Ar AES +Cipher suites using AES. +.It Ar 3DES +Cipher suites using triple DES. +.It Ar DES +Cipher suites using DES +.Pq not triple DES . +.It Ar RC4 +Cipher suites using RC4. +.It Ar RC2 +Cipher suites using RC2. +.It Ar MD5 +Cipher suites using MD5. +.It Ar SHA1 , SHA +Cipher suites using SHA1. +.El +.Sh CIPHERS SUITE NAMES +The following lists give the SSL or TLS cipher suites names from the +relevant specification and their +.Nm OpenSSL +equivalents. +It should be noted that several cipher suite names do not include the +authentication used, e.g. DES-CBC3-SHA. +In these cases, RSA authentication is used. +.Ss SSL v3.0 cipher suites +.Bd -unfilled -offset indent +SSL_RSA_WITH_NULL_MD5 NULL-MD5 +SSL_RSA_WITH_NULL_SHA NULL-SHA +SSL_RSA_EXPORT_WITH_RC4_40_MD5 EXP-RC4-MD5 +SSL_RSA_WITH_RC4_128_MD5 RC4-MD5 +SSL_RSA_WITH_RC4_128_SHA RC4-SHA +SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5 EXP-RC2-CBC-MD5 +SSL_RSA_WITH_IDEA_CBC_SHA IDEA-CBC-SHA +SSL_RSA_EXPORT_WITH_DES40_CBC_SHA EXP-DES-CBC-SHA +SSL_RSA_WITH_DES_CBC_SHA DES-CBC-SHA +SSL_RSA_WITH_3DES_EDE_CBC_SHA DES-CBC3-SHA + +SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA Not implemented. +SSL_DH_DSS_WITH_DES_CBC_SHA Not implemented. +SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA Not implemented. +SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA Not implemented. +SSL_DH_RSA_WITH_DES_CBC_SHA Not implemented. +SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA Not implemented. +SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA EXP-EDH-DSS-DES-CBC-SHA +SSL_DHE_DSS_WITH_DES_CBC_SHA EDH-DSS-CBC-SHA +SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA EDH-DSS-DES-CBC3-SHA +SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA EXP-EDH-RSA-DES-CBC-SHA +SSL_DHE_RSA_WITH_DES_CBC_SHA EDH-RSA-DES-CBC-SHA +SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA EDH-RSA-DES-CBC3-SHA + +SSL_DH_anon_EXPORT_WITH_RC4_40_MD5 EXP-ADH-RC4-MD5 +SSL_DH_anon_WITH_RC4_128_MD5 ADH-RC4-MD5 +SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA EXP-ADH-DES-CBC-SHA +SSL_DH_anon_WITH_DES_CBC_SHA ADH-DES-CBC-SHA +SSL_DH_anon_WITH_3DES_EDE_CBC_SHA ADH-DES-CBC3-SHA + +SSL_FORTEZZA_KEA_WITH_NULL_SHA Not implemented. +SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA Not implemented. +SSL_FORTEZZA_KEA_WITH_RC4_128_SHA Not implemented. +.Ed +.Ss TLS v1.0 cipher suites +.Bd -unfilled -offset indent +TLS_RSA_WITH_NULL_MD5 NULL-MD5 +TLS_RSA_WITH_NULL_SHA NULL-SHA +TLS_RSA_EXPORT_WITH_RC4_40_MD5 EXP-RC4-MD5 +TLS_RSA_WITH_RC4_128_MD5 RC4-MD5 +TLS_RSA_WITH_RC4_128_SHA RC4-SHA +TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 EXP-RC2-CBC-MD5 +TLS_RSA_WITH_IDEA_CBC_SHA IDEA-CBC-SHA +TLS_RSA_EXPORT_WITH_DES40_CBC_SHA EXP-DES-CBC-SHA +TLS_RSA_WITH_DES_CBC_SHA DES-CBC-SHA +TLS_RSA_WITH_3DES_EDE_CBC_SHA DES-CBC3-SHA + +TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA Not implemented. +TLS_DH_DSS_WITH_DES_CBC_SHA Not implemented. +TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA Not implemented. +TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA Not implemented. +TLS_DH_RSA_WITH_DES_CBC_SHA Not implemented. +TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA Not implemented. +TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA EXP-EDH-DSS-DES-CBC-SHA +TLS_DHE_DSS_WITH_DES_CBC_SHA EDH-DSS-CBC-SHA +TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA EDH-DSS-DES-CBC3-SHA +TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA EXP-EDH-RSA-DES-CBC-SHA +TLS_DHE_RSA_WITH_DES_CBC_SHA EDH-RSA-DES-CBC-SHA +TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA EDH-RSA-DES-CBC3-SHA + +TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 EXP-ADH-RC4-MD5 +TLS_DH_anon_WITH_RC4_128_MD5 ADH-RC4-MD5 +TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA EXP-ADH-DES-CBC-SHA +TLS_DH_anon_WITH_DES_CBC_SHA ADH-DES-CBC-SHA +TLS_DH_anon_WITH_3DES_EDE_CBC_SHA ADH-DES-CBC3-SHA +.Ed +.Ss AES ciphersuites from RFC 3268, extending TLS v1.0 +.Bd -unfilled -offset indent +TLS_RSA_WITH_AES_128_CBC_SHA AES128-SHA +TLS_RSA_WITH_AES_256_CBC_SHA AES256-SHA + +TLS_DH_DSS_WITH_AES_128_CBC_SHA Not implemented. +TLS_DH_DSS_WITH_AES_256_CBC_SHA Not implemented. +TLS_DH_RSA_WITH_AES_128_CBC_SHA Not implemented. +TLS_DH_RSA_WITH_AES_256_CBC_SHA Not implemented. + +TLS_DHE_DSS_WITH_AES_128_CBC_SHA DHE-DSS-AES128-SHA +TLS_DHE_DSS_WITH_AES_256_CBC_SHA DHE-DSS-AES256-SHA +TLS_DHE_RSA_WITH_AES_128_CBC_SHA DHE-RSA-AES128-SHA +TLS_DHE_RSA_WITH_AES_256_CBC_SHA DHE-RSA-AES256-SHA + +TLS_DH_anon_WITH_AES_128_CBC_SHA ADH-AES128-SHA +TLS_DH_anon_WITH_AES_256_CBC_SHA ADH-AES256-SHA +.Ed +.Ss GOST ciphersuites from draft-chudov-cryptopro-cptls, extending TLS v1.0 +.Sy Note : +These ciphers require an engine which includes GOST cryptographic +algorithms, such as the +.Dq ccgost +engine, included in the OpenSSL distribution. +.Bd -unfilled -offset indent +TLS_GOSTR341094_WITH_28147_CNT_IMIT GOST94-GOST89-GOST89 +TLS_GOSTR341001_WITH_28147_CNT_IMIT GOST2001-GOST89-GOST89 +TLS_GOSTR341094_WITH_NULL_GOSTR3411 GOST94-NULL-GOST94 +TLS_GOSTR341001_WITH_NULL_GOSTR3411 GOST2001-NULL-GOST94 +.Ed +.Ss Additional Export 1024 and other cipher suites +.Sy Note : +These ciphers can also be used in SSL v3. +.Bd -unfilled -offset indent +TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA EXP1024-DES-CBC-SHA +TLS_RSA_EXPORT1024_WITH_RC4_56_SHA EXP1024-RC4-SHA +TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA EXP1024-DHE-DSS-DES-CBC-SHA +TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA EXP1024-DHE-DSS-RC4-SHA +TLS_DHE_DSS_WITH_RC4_128_SHA DHE-DSS-RC4-SHA +.Ed +.Sh CIPHERS NOTES +The non-ephemeral DH modes are currently unimplemented in +.Nm OpenSSL +because there is no support for DH certificates. +.Pp +Some compiled versions of +.Nm OpenSSL +may not include all the ciphers +listed here because some ciphers were excluded at compile time. +.Sh CIPHERS EXAMPLES +Verbose listing of all +.Nm OpenSSL +ciphers including NULL ciphers: +.Pp +.Dl $ openssl ciphers -v 'ALL:eNULL' +.Pp +Include all ciphers except NULL and anonymous DH then sort by +strength: +.Pp +.Dl $ openssl ciphers -v 'ALL:!ADH:@STRENGTH' +.Pp +Include only 3DES ciphers and then place RSA ciphers last: +.Pp +.Dl $ openssl ciphers -v '3DES:+RSA' +.Pp +Include all RC4 ciphers but leave out those without authentication: +.Pp +.Dl $ openssl ciphers -v 'RC4:!COMPLEMENTOFDEFAULT' +.Pp +Include all ciphers with RSA authentication but leave out ciphers without +encryption: +.Pp +.Dl $ openssl ciphers -v 'RSA:!COMPLEMENTOFALL' +.Sh CIPHERS HISTORY +The +.Ar COMPLEMENTOFALL +and +.Ar COMPLEMENTOFDEFAULT +selection options were added in +.Nm OpenSSL +0.9.7. +.Pp +The +.Fl V +option of the +.Nm ciphers +command was added in +.Nm OpenSSL +1.0.0. +.\" +.\" CRL +.\" +.Sh CRL +.nr nS 1 +.Nm "openssl crl" +.Bk -words +.Op Fl CAfile Ar file +.Op Fl CApath Ar dir +.Op Fl fingerprint +.Op Fl hash +.Op Fl in Ar file +.Op Fl inform Ar DER | PEM +.Op Fl issuer +.Op Fl lastupdate +.Op Fl nextupdate +.Op Fl noout +.Op Fl out Ar file +.Op Fl outform Ar DER | PEM +.Op Fl text +.Ek +.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 +This specifies the input file to read from, or standard input if this +option is not specified. +.It Fl inform Ar DER | PEM +This specifies the input format. +.Ar DER +format is a DER-encoded CRL structure. +.Ar PEM +.Pq the default +is a base64-encoded version of the DER form with header and footer lines. +.It Fl issuer +Output the issuer name. +.It Fl lastupdate +Output the +.Ar lastUpdate +field. +.It Fl nextupdate +Output the +.Ar nextUpdate +field. +.It Fl noout +Don't output the encoded version of the CRL. +.It Fl out Ar file +Specifies the output file to write to, or standard output by +default. +.It Fl outform Ar DER | PEM +This specifies the output format; the options have the same meaning as the +.Fl inform +option. +.It Fl text +Print out the CRL in text form. +.El +.Sh CRL NOTES +The PEM CRL format uses the header and footer lines: +.Bd -unfilled -offset indent +-----BEGIN X509 CRL----- +-----END X509 CRL----- +.Ed +.Sh CRL EXAMPLES +Convert a CRL file from PEM to DER: +.Pp +.Dl $ openssl crl -in crl.pem -outform DER -out crl.der +.Pp +Output the text form of a DER-encoded certificate: +.Pp +.Dl $ openssl crl -in crl.der -inform DER -text -noout +.Sh CRL BUGS +Ideally, it should be possible to create a CRL using appropriate options +and files too. +.\" +.\" CRL2PKCS7 +.\" +.Sh CRL2PKCS7 +.nr nS 1 +.Nm "openssl crl2pkcs7" +.Bk -words +.Op Fl certfile Ar file +.Op Fl in Ar file +.Op Fl inform Ar DER | PEM +.Op Fl nocrl +.Op Fl out Ar file +.Op Fl outform Ar DER | PEM +.Ek +.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 +Specifies a +.Ar file +containing one or more certificates in PEM format. +All certificates in the file will be added to the PKCS#7 structure. +This option can be used more than once to read certificates from multiple +files. +.It Fl in Ar file +This specifies the input +.Ar file +to read a CRL from, or standard input if this option is not specified. +.It Fl inform Ar DER | PEM +This specifies the CRL input format. +.Ar DER +format is a DER-encoded CRL structure. +.Ar PEM +.Pq the default +is a base64-encoded version of the DER form with header and footer lines. +.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 +Specifies the output +.Ar file +to write the PKCS#7 structure to, or standard output by default. +.It Fl outform Ar DER | PEM +This specifies the PKCS#7 structure output format. +.Ar DER +format is a DER-encoded PKCS#7 structure. +.Ar PEM +.Pq the default +is a base64-encoded version of the DER form with header and footer lines. +.El +.Sh CRL2PKCS7 EXAMPLES +Create a PKCS#7 structure from a certificate and CRL: +.Pp +.Dl $ openssl crl2pkcs7 -in crl.pem -certfile cert.pem -out p7.pem +.Pp +Create a PKCS#7 structure in DER format with no CRL from several +different certificates: +.Bd -literal -offset indent +$ openssl crl2pkcs7 -nocrl -certfile newcert.pem \e + -certfile demoCA/cacert.pem -outform DER -out p7.der +.Ed +.Sh CRL2PKCS7 NOTES +The output file is a PKCS#7 signed data structure containing no signers and +just certificates and an optional CRL. +.Pp +This utility can be used to send certificates and CAs to Netscape as part of +the certificate enrollment process. +This involves sending the DER-encoded output +as MIME type +.Em application/x-x509-user-cert . +.Pp +The PEM-encoded form with the header and footer lines removed can be used to +install user certificates and CAs in MSIE using the Xenroll control. +.\" +.\" DGST +.\" +.Sh DGST +.nr nS 1 +.Nm "openssl dgst" +.Bk -words +.Oo +.Fl dss1 | md2 | md4 | md5 | +.Fl ripemd160 | sha | sha1 +.Oc +.Op Fl binary +.Op Fl cd +.Op Fl engine Ar id +.Op Fl hex +.Op Fl hmac Ar key +.Op Fl keyform Ar ENGINE | 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 +.Ek +.nr nS 0 +.Pp +.Nm openssl +.Cm md2 | md4 | md5 | +.Cm ripemd160 | sha | sha1 +.Op Fl c +.Op Fl d +.Op Ar +.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 out the digest in two-digit groups separated by colons; only relevant if +.Em hex +format output is used. +.It Fl d +Print out BIO debugging information. +.It Fl engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm dgst +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +This engine is not used as a source for digest algorithms +unless it is also specified in the configuration file. +.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 Ar ENGINE | 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 Ar 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 Ar 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 file to output to, or standard output by default. +.It Fl passin Ar arg +The key password source. +For more information about the format of +.Ar arg , +see the +.Sx PASS PHRASE ARGUMENTS +section above. +.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 DGST NOTES +The digest of choice for all new applications is SHA1. +Other digests are, however, still widely used. +.Pp +If you wish to sign or verify data using the DSA algorithm, the dss1 +digest must be used. +.Pp +A source of random numbers is required for certain signing algorithms, in +particular DSA. +.Pp +The signing and verify options should only be used if a single file is +being signed or verified. +.\" +.\" DH +.\" +.Sh DH +Diffie-Hellman Parameter Management. +The +.Nm dh +command has been replaced by +.Nm dhparam . +See +.Sx DHPARAM +below. +.\" +.\" DHPARAM +.\" +.Sh DHPARAM +.nr nS 1 +.Nm "openssl dhparam" +.Bk -words +.Op Fl 2 | 5 +.Op Fl C +.Op Fl check +.Op Fl dsaparam +.Op Fl engine Ar id +.Op Fl in Ar file +.Op Fl inform Ar DER | PEM +.Op Fl noout +.Op Fl out Ar file +.Op Fl outform Ar DER | PEM +.Op Fl text +.Op Ar numbits +.Ek +.nr nS 0 +.Pp +The +.Nm dhparam +command is used to manipulate DH parameter files. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl 2 , 5 +The generator to use, either 2 or 5. +2 is the default. +If present, the input file is ignored and parameters are generated instead. +.It Fl C +This option converts the parameters into C code. +The parameters can then be loaded by calling the +.Cm get_dh Ns Ar numbits Ns Li () +function. +.It Fl check +Check the DH parameters. +.It Fl dsaparam +If this option is used, DSA rather than DH parameters are read or created; +they are converted to DH format. +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 engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm dhparam +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.It Fl in Ar file +This specifies the input +.Ar file +to read parameters from, or standard input if this option is not specified. +.It Fl inform Ar DER | PEM +This specifies the input format. +The argument +.Ar DER +uses an ASN1 DER-encoded form compatible with the PKCS#3 DHparameter +structure. +The +.Ar PEM +form is the default format: +it consists of the DER format base64-encoded with +additional header and footer lines. +.It Fl noout +This option inhibits the output of the encoded version of the parameters. +.It Ar numbits +This argument specifies that a parameter set should be generated of size +.Ar numbits . +It must be the last option. +If not present, a value of 512 is used. +If this value is present, the input file is ignored and +parameters are generated instead. +.It Fl out Ar file +This specifies the output +.Ar file +to write parameters to. +Standard output is used if this option is not present. +The output filename should +.Em not +be the same as the input filename. +.It Fl outform Ar DER | PEM +This specifies the output format; the options have the same meaning as the +.Fl inform +option. +.It Fl text +This option prints out the DH parameters in human readable form. +.El +.Sh DHPARAM WARNINGS +The program +.Nm dhparam +combines the functionality of the programs +.Nm dh +and +.Nm gendh +in previous versions of +.Nm OpenSSL +and +.Nm SSLeay . +The +.Nm dh +and +.Nm gendh +programs are retained for now, but may have different purposes in future +versions of +.Nm OpenSSL . +.Sh DHPARAM NOTES +PEM format DH parameters use the header and footer lines: +.Bd -unfilled -offset indent +-----BEGIN DH PARAMETERS----- +-----END DH PARAMETERS----- +.Ed +.Pp +.Nm OpenSSL +currently only supports the older PKCS#3 DH, +not the newer X9.42 DH. +.Pp +This program manipulates DH parameters not keys. +.Sh DHPARAM BUGS +There should be a way to generate and manipulate DH keys. +.Sh DHPARAM HISTORY +The +.Nm dhparam +command was added in +.Nm OpenSSL +0.9.5. +The +.Fl dsaparam +option was added in +.Nm OpenSSL +0.9.6. +.\" +.\" DSA +.\" +.Sh DSA +.nr nS 1 +.Nm "openssl dsa" +.Bk -words +.Oo +.Fl aes128 | aes192 | aes256 | +.Fl des | des3 +.Oc +.Op Fl engine Ar id +.Op Fl in Ar file +.Op Fl inform Ar DER | PEM +.Op Fl modulus +.Op Fl noout +.Op Fl out Ar file +.Op Fl outform Ar DER | PEM +.Op Fl passin Ar arg +.Op Fl passout Ar arg +.Op Fl pubin +.Op Fl pubout +.Op Fl text +.Ek +.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 +These options 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 is specified, the key is written in plain text. +This means that using the +.Nm dsa +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 use to add or change +the pass phrase. +These options can only be used with PEM format output files. +.It Fl engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm dsa +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.It Fl in Ar file +This specifies the input +.Ar file +to read a key from, or standard input if this option is not specified. +If the key is encrypted, a pass phrase will be prompted for. +.It Fl inform Ar DER | PEM +This specifies the input format. +The +.Ar DER +argument with a private key uses an ASN1 DER-encoded form of an ASN.1 +SEQUENCE consisting of the values of version +.Pq currently zero , +P, Q, G, +and the public and private key components, respectively, as ASN.1 INTEGERs. +When used with a public key it uses a +.Em SubjectPublicKeyInfo +structure: it is an error if the key is not DSA. +.Pp +The +.Ar PEM +form is the default format: +it consists of the DER format base64-encoded with additional header and footer +lines. +In the case of a private key, PKCS#8 format is also accepted. +.It Fl modulus +This option prints out the value of the public key component of the key. +.It Fl noout +This option prevents output of the encoded version of the key. +.It Fl out Ar file +This specifies the output +.Ar file +to write a key to, or standard output if not specified. +If any encryption options are set then a pass phrase will be +prompted for. +The output filename should +.Em not +be the same as the input filename. +.It Fl outform Ar DER | PEM +This specifies the output format; the options have the same meaning as the +.Fl inform +option. +.It Fl passin Ar arg +The key password source. +For more information about the format of +.Ar arg , +see the +.Sx PASS PHRASE ARGUMENTS +section above. +.It Fl passout Ar arg +The output file password source. +For more information about the format of +.Ar arg , +see the +.Sx PASS PHRASE ARGUMENTS +section above. +.It Fl pubin +By default, a private key is read from the input file. +With this option a public key is read instead. +.It Fl pubout +By default, a private key is output. +With this option a public key will be output instead. +This option is automatically set if the input is a public key. +.It Fl text +Prints out the public/private key components and parameters. +.El +.Sh DSA NOTES +The PEM private key format uses the header and footer lines: +.Bd -unfilled -offset indent +-----BEGIN DSA PRIVATE KEY----- +-----END DSA PRIVATE KEY----- +.Ed +.Pp +The PEM public key format uses the header and footer lines: +.Bd -unfilled -offset indent +-----BEGIN PUBLIC KEY----- +-----END PUBLIC KEY----- +.Ed +.Sh DSA EXAMPLES +To remove the pass phrase on a DSA private key: +.Pp +.Dl $ openssl dsa -in key.pem -out keyout.pem +.Pp +To encrypt a private key using triple DES: +.Pp +.Dl $ openssl dsa -in key.pem -des3 -out keyout.pem +.Pp +To convert a private key from PEM to DER format: +.Pp +.Dl $ openssl dsa -in key.pem -outform DER -out keyout.der +.Pp +To print out the components of a private key to standard output: +.Pp +.Dl $ openssl dsa -in key.pem -text -noout +.Pp +To just output the public part of a private key: +.Pp +.Dl $ openssl dsa -in key.pem -pubout -out pubkey.pem +.\" +.\" DSAPARAM +.\" +.Sh DSAPARAM +.nr nS 1 +.Nm "openssl dsaparam" +.Bk -words +.Op Fl C +.Op Fl engine Ar id +.Op Fl genkey +.Op Fl in Ar file +.Op Fl inform Ar DER | PEM +.Op Fl noout +.Op Fl out Ar file +.Op Fl outform Ar DER | PEM +.Op Fl text +.Op Ar numbits +.Ek +.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 +This option converts the parameters into C code. +The parameters can then be loaded by calling the +.Cm get_dsa Ns Ar XXX Ns Li () +function. +.It Fl engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm dsaparam +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.It Fl genkey +This option will generate a DSA either using the specified or generated +parameters. +.It Fl in Ar file +This specifies the input +.Ar file +to read parameters from, or standard input if this option is not specified. +If the +.Ar numbits +parameter is included, then this option will be ignored. +.It Fl inform Ar DER | PEM +This specifies the input format. +The +.Ar DER +argument uses an ASN1 DER-encoded form compatible with RFC 2459 +.Pq PKIX +DSS-Parms that is a SEQUENCE consisting of p, q and g, respectively. +The +.Ar PEM +form is the default format: +it consists of the DER format base64-encoded with additional header +and footer lines. +.It Fl noout +This option inhibits the output of the encoded version of the parameters. +.It Ar numbits +This option specifies that a parameter set should be generated of size +.Ar numbits . +If this option is included, the input file +.Pq if any +is ignored. +.It Fl out Ar file +This specifies the output +.Ar file +to write parameters to. +Standard output is used if this option is not present. +The output filename should +.Em not +be the same as the input filename. +.It Fl outform Ar DER | PEM +This specifies the output format; the options have the same meaning as the +.Fl inform +option. +.It Fl text +This option prints out the DSA parameters in human readable form. +.El +.Sh DSAPARAM NOTES +PEM format DSA parameters use the header and footer lines: +.Bd -unfilled -offset indent +-----BEGIN DSA PARAMETERS----- +-----END DSA PARAMETERS----- +.Ed +.Pp +DSA parameter generation is a slow process and as a result the same set of +DSA parameters is often used to generate several distinct keys. +.\" +.\" EC +.\" +.Sh EC +.nr nS 1 +.Nm "openssl ec" +.Bk -words +.Op Fl conv_form Ar arg +.Op Fl des +.Op Fl des3 +.Op Fl engine Ar id +.Op Fl in Ar file +.Op Fl inform Ar DER | PEM +.Op Fl noout +.Op Fl out Ar file +.Op Fl outform Ar 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 +.Ek +.nr nS 0 +.Pp +The +.Nm ec +command processes EC keys. +They can be converted between various +forms and their components printed out. +Note: +.Nm OpenSSL +uses the private key format specified in +.Dq SEC 1: Elliptic Curve Cryptography +.Pq Lk http://www.secg.org/ . +To convert an +.Nm OpenSSL +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 +This specifies how the points on the elliptic curve are converted +into octet strings. +Possible values are: +.Cm compressed +(the default value), +.Cm uncompressed , +and +.Cm hybrid . +For more information regarding +the point conversion forms please read 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 +.Ar OPENSSL_EC_BIN_PT_COMP +at compile time. +.It Fl des | des3 +These options encrypt the private key with the DES, triple DES, or +any other cipher supported by +.Nm OpenSSL +before outputting it. +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 use to add or change the pass phrase. +These options can only be used with PEM format output files. +.It Fl engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm ec +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.It Fl in Ar file +This specifies the input filename to read a key from, +or standard input if this option is not specified. +If the key is encrypted a pass phrase will be prompted for. +.It Fl inform Ar DER | PEM +This specifies the input format. +DER with a private key uses +an ASN.1 DER-encoded SEC1 private key. +When used with a public key it +uses the SubjectPublicKeyInfo structure as specified in RFC 3280. +PEM is the default format: +it consists of the DER format base64 +encoded with additional header and footer lines. +In the case of a private key +PKCS#8 format is also accepted. +.It Fl noout +Prevents output of the encoded version of the key. +.It Fl out Ar file +Specifies the output filename to write a key to, +or standard output if none is specified. +If any encryption options are set then a pass phrase will be prompted for. +The output filename should +.Em not +be the same as the input filename. +.It Fl outform Ar DER | PEM +This specifies the output format. +The options have the same meaning as the +.Fl inform +option. +.It Fl param_enc Ar arg +This specifies 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 in +.Nm OpenSSL . +.It Fl passin Ar arg +The key password source. +For more information about the format of +.Ar arg , +see the +.Sx PASS PHRASE ARGUMENTS +section above. +.It Fl passout Ar arg +The output file password source. +For more information about the format of +.Ar arg , +see the +.Sx PASS PHRASE ARGUMENTS +section above. +.It Fl pubin +By default a private key is read from the input file; +with this option a public key is read instead. +.It Fl pubout +By default a private key is output; +with this option a public key is output instead. +This option is automatically set if the input is a public key. +.It Fl text +Prints out the public/private key components and parameters. +.El +.Sh EC NOTES +The PEM private key format uses the header and footer lines: +.Bd -literal -offset indent +-----BEGIN EC PRIVATE KEY----- +-----END EC PRIVATE KEY----- +.Ed +.Pp +The PEM public key format uses the header and footer lines: +.Bd -literal -offset indent +-----BEGIN PUBLIC KEY----- +-----END PUBLIC KEY----- +.Ed +.Sh EC EXAMPLES +To encrypt a private key using triple DES: +.Bd -literal -offset indent +$ openssl ec -in key.pem -des3 -out keyout.pem +.Ed +.Pp +To convert a private key from PEM to DER format: +.Bd -literal -offset indent +$ openssl ec -in key.pem -outform DER -out keyout.der +.Ed +.Pp +To print out the components of a private key to standard output: +.Bd -literal -offset indent +$ openssl ec -in key.pem -text -noout +.Ed +.Pp +To just output the public part of a private key: +.Bd -literal -offset indent +$ openssl ec -in key.pem -pubout -out pubkey.pem +.Ed +.Pp +To change the parameter encoding to +.Cm explicit : +.Bd -literal -offset indent +$ openssl ec -in key.pem -param_enc explicit -out keyout.pem +.Ed +.Pp +To change the point conversion form to +.Cm compressed : +.Bd -literal -offset indent +$ openssl ec -in key.pem -conv_form compressed -out keyout.pem +.Ed +.Sh EC HISTORY +The +.Nm ec +command was first introduced in +.Nm OpenSSL +0.9.8. +.Sh EC AUTHORS +.An Nils Larsch . +.\" +.\" ECPARAM +.\" +.Sh ECPARAM +.nr nS 1 +.Nm "openssl ecparam" +.Bk -words +.Op Fl C +.Op Fl check +.Op Fl conv_form Ar arg +.Op Fl engine Ar id +.Op Fl genkey +.Op Fl in Ar file +.Op Fl inform Ar 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 Ar DER | PEM +.Op Fl param_enc Ar arg +.Op Fl text +.Ek +.nr nS 0 +.Pp +This command is used to manipulate or generate EC parameter files. +.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 +.Fn get_ec_group_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 value), +.Cm uncompressed , +and +.Cm hybrid . +For more information regarding +the point conversion forms please read 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 +.Ar OPENSSL_EC_BIN_PT_COMP +at compile time. +.It Fl engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm ecparam +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.It Fl genkey +Generate an EC private key using the specified parameters. +.It Fl in Ar file +Specify the input filename to read parameters from or standard input if +this option is not specified. +.It Fl inform Ar DER | PEM +Specify the input format. +DER uses an ASN.1 DER-encoded +form compatible with RFC 3279 EcpkParameters. +PEM is the default format: +it consists of the DER format base64 encoded with additional +header and footer lines. +.It Fl list_curves +Print out 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. +Use +.Fl list_curves +to get a list of all currently implemented EC parameters. +.It Fl no_seed +Inhibit that the 'seed' for the parameter generation +is included in the ECParameters structure (see RFC 3279). +.It Fl noout +Inhibit the output of the encoded version of the parameters. +.It Fl out Ar file +Specify the output filename parameters are written to. +Standard output is used if this option is not present. +The output filename should +.Em not +be the same as the input filename. +.It Fl outform Ar DER | PEM +Specify the output format; +the parameters have the same meaning as the +.Fl inform +option. +.It Fl param_enc Ar arg +This specifies 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 in +.Nm OpenSSL . +.It Fl text +Print out the EC parameters in human readable form. +.El +.Sh ECPARAM NOTES +PEM format EC parameters use the header and footer lines: +.Bd -literal -offset indent +-----BEGIN EC PARAMETERS----- +-----END EC PARAMETERS----- +.Ed +.Pp +.Nm OpenSSL +is currently not able to generate new groups and therefore +.Nm ecparam +can only create EC parameters from known (named) curves. +.Sh ECPARAM EXAMPLES +To create EC parameters with the group 'prime192v1': +.Bd -literal -offset indent +$ openssl ecparam -out ec_param.pem -name prime192v1 +.Ed +.Pp +To create EC parameters with explicit parameters: +.Bd -literal -offset indent +$ openssl ecparam -out ec_param.pem -name prime192v1 \e + -param_enc explicit +.Ed +.Pp +To validate given EC parameters: +.Bd -literal -offset indent +$ openssl ecparam -in ec_param.pem -check +.Ed +.Pp +To create EC parameters and a private key: +.Bd -literal -offset indent +$ openssl ecparam -out ec_key.pem -name prime192v1 -genkey +.Ed +.Pp +To change the point encoding to 'compressed': +.Bd -literal -offset indent +$ openssl ecparam -in ec_in.pem -out ec_out.pem \e + -conv_form compressed +.Ed +.Pp +To print out the EC parameters to standard output: +.Bd -literal -offset indent +$ openssl ecparam -in ec_param.pem -noout -text +.Ed +.Sh ECPARAM HISTORY +The +.Nm ecparam +command was first introduced in +.Nm OpenSSL +0.9.8. +.Sh ECPARAM AUTHORS +.An Nils Larsch . +.\" +.\" ENC +.\" +.Sh ENC +.nr nS 1 +.Nm "openssl enc" +.Bk -words +.Fl ciphername +.Op Fl AadePp +.Op Fl base64 +.Op Fl bufsize Ar number +.Op Fl debug +.Op Fl engine Ar id +.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 +.Ek +.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. +.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 engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm enc +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.It Fl in Ar file +The input +.Ar file ; +standard input by default. +.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 +.Ar IV +must explicitly be defined. +When a password is being specified using one of the other options, +the +.Ar 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 +.Ar IV +must be additionally 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 +.Ar 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. +This is for compatibility with previous versions of +.Nm OpenSSL . +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 . +This is for compatibility with previous versions of +.Nm OpenSSL . +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 +.Dq md2 , +.Dq md5 , +.Dq sha , +or +.Dq 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 +.Ar salt +in the key derivation routines. +This option should +.Em NEVER +be used unless compatibility with previous versions of +.Nm OpenSSL +or +.Nm SSLeay +is required. +.It Fl out Ar file +The output +.Ar file , +standard output by default. +.It Fl P +Print out the +.Ar salt , +.Ar key , +and +.Ar IV +used, then immediately exit; +don't do any encryption or decryption. +.It Fl p +Print out the +.Ar salt , +.Ar key , +and +.Ar IV +used. +.It Fl pass Ar arg +The password source. +For more information about the format of +.Ar arg , +see the +.Sx PASS PHRASE ARGUMENTS +section above. +.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 +.Ar salt +in the key derivation routines. +This is the default. +.El +.Sh ENC NOTES +The program can be called either as +.Nm openssl ciphername +or +.Nm openssl enc -ciphername . +But the first form doesn't work with engine-provided ciphers, +because this form is processed before the +configuration file is read and any engines loaded. +.Pp +Engines which provide entirely new encryption algorithms +should be configured in the configuration file. +Engines, specified on the command line using the +.Fl engine +option, +can only be used for hardware-assisted implementations of ciphers, +supported by +.Nm OpenSSL +core, or by other engines specified in the configuration file. +.Pp +When +.Nm enc +lists supported ciphers, +ciphers provided by engines specified in the configuration files +are listed too. +.Pp +A password will be prompted for to derive the +.Ar key +and +.Ar IV +if necessary. +.Pp +The +.Fl nosalt +option should +.Em NEVER +be used unless compatibility with previous versions of +.Nm OpenSSL +or +.Nm SSLeay +is required. +.Pp +With the +.Fl nosalt +option it is possible to perform efficient dictionary +attacks on the password and to attack stream cipher encrypted data. +The reason for this is that without the salt +the same password always generates the same encryption key. +When the salt +is being used the first eight bytes of the encrypted data are reserved +for the salt: +it is generated at random when encrypting a file and read from the +encrypted file when it is decrypted. +.Pp +Some of the ciphers do not have large keys and others have security +implications if not used correctly. +A beginner is advised to just use a strong block cipher in CBC mode +such as bf or des3. +.Pp +All the block ciphers normally use PKCS#5 padding also known as standard block +padding: +this allows a rudimentary integrity or password check to be performed. +However, since the chance of random data passing the test is +better than 1 in 256, it isn't a very good test. +.Pp +If padding is disabled, the input data must be a multiple of the cipher +block length. +.Pp +All RC2 ciphers have the same key and effective key length. +.Pp +Blowfish and RC5 algorithms use a 128-bit key. +.Sh ENC SUPPORTED CIPHERS +.Bd -unfilled -offset indent +aes-[128|192|256]-cbc 128/192/256 bit AES in CBC mode +aes-[128|192|256] Alias for aes-[128|192|256]-cbc +aes-[128|192|256]-cfb 128/192/256 bit AES in 128 bit CFB mode +aes-[128|192|256]-cfb1 128/192/256 bit AES in 1 bit CFB mode +aes-[128|192|256]-cfb8 128/192/256 bit AES in 8 bit CFB mode +aes-[128|192|256]-ecb 128/192/256 bit AES in ECB mode +aes-[128|192|256]-ofb 128/192/256 bit AES in OFB mode + +base64 Base 64 + +bf Alias for bf-cbc +bf-cbc Blowfish in CBC mode +bf-cfb Blowfish in CFB mode +bf-ecb Blowfish in ECB mode +bf-ofb Blowfish in OFB mode + +cast Alias for cast-cbc +cast-cbc CAST in CBC mode +cast5-cbc CAST5 in CBC mode +cast5-cfb CAST5 in CFB mode +cast5-ecb CAST5 in ECB mode +cast5-ofb CAST5 in OFB mode + +des Alias for des-cbc +des-cbc DES in CBC mode +des-cfb DES in CBC mode +des-ecb DES in ECB mode +des-ofb DES in OFB mode + +des-ede Two key triple DES EDE in ECB mode +des-ede-cbc Two key triple DES EDE in CBC mode +des-ede-cfb Two key triple DES EDE in CFB mode +des-ede-ofb Two key triple DES EDE in OFB mode + +des3 Alias for des-ede3-cbc +des-ede3 Three key triple DES EDE in ECB mode +des-ede3-cbc Three key triple DES EDE in CBC mode +des-ede3-cfb Three key triple DES EDE CFB mode +des-ede3-ofb Three key triple DES EDE in OFB mode + +desx DESX algorithm + +rc2 Alias for rc2-cbc +rc2-cbc 128-bit RC2 in CBC mode +rc2-cfb 128-bit RC2 in CFB mode +rc2-ecb 128-bit RC2 in ECB mode +rc2-ofb 128-bit RC2 in OFB mode +rc2-64-cbc 64-bit RC2 in CBC mode +rc2-40-cbc 40-bit RC2 in CBC mode + +rc4 128-bit RC4 +rc4-40 40-bit RC4 +.Ed +.Sh ENC EXAMPLES +Just base64 encode a binary file: +.Pp +.Dl $ openssl base64 -in file.bin -out file.b64 +.Pp +Decode the same file: +.Pp +.Dl $ openssl base64 -d -in file.b64 -out file.bin +.Pp +Encrypt a file using triple DES in CBC mode using a prompted password: +.Pp +.Dl $ openssl des3 -salt -in file.txt -out file.des3 +.Pp +Decrypt a file using a supplied password: +.Pp +.Dl "$ openssl des3 -d -in file.des3 -out file.txt -k mypassword" +.Pp +Encrypt a file then base64 encode it +(so it can be sent via mail for example) +using Blowfish in CBC mode: +.Pp +.Dl $ openssl bf -a -salt -in file.txt -out file.bf +.Pp +Base64 decode a file then decrypt it: +.Pp +.Dl "$ openssl bf -d -a -in file.bf -out file.txt" +.Sh ENC BUGS +The +.Fl A +option when used with large files doesn't work properly. +.Pp +There should be an option to allow an iteration count to be included. +.Pp +The +.Nm enc +program only supports a fixed number of algorithms with certain parameters. +Therefore it is not possible to use RC2 with a 76-bit key +or RC4 with an 84-bit key with this program. +.\" +.\" ENGINE +.\" +.Sh ENGINE +.Nm openssl engine +.Op Fl ctv +.Op Fl post Ar cmd +.Op Fl pre Ar cmd +.Op Ar engine ... +.Pp +The +.Nm engine +command provides loadable module information and manipulation +of various engines. +Any options are applied to all engines supplied on the command line, +or all supported engines if none are specified. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl c +For each engine, also list the capabilities. +.It Fl post Ar cmd +Run command +.Ar cmd +against the engine after loading it +(only used if +.Fl t +is also provided). +.It Fl pre Ar cmd +Run command +.Ar cmd +against the engine before any attempts +to load it +(only used if +.Fl t +is also provided). +.It Fl t +For each engine, check that they are really available. +.Fl tt +will display an error trace for unavailable engines. +.It Fl v +Verbose mode. +For each engine, list its 'control commands'. +.Fl vv +will additionally display each command's description. +.Fl vvv +will also add the input flags for each command. +.Fl vvvv +will also show internal input flags. +.El +.\" +.\" ERRSTR +.\" +.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 ERRSTR EXAMPLES +The following error code: +.Pp +.Dl 27594:error:2006D080:lib(32):func(109):reason(128):bss_file.c:107: +.Pp +\&...can be displayed with: +.Pp +.Dl $ openssl errstr 2006D080 +.Pp +\&...to produce the error message: +.Pp +.Dl error:2006D080:BIO routines:BIO_new_file:no such file +.\" +.\" GENDH +.\" +.Sh GENDH +Generation of Diffie-Hellman Parameters. +Replaced by +.Nm dhparam . +See +.Sx DHPARAM +above. +.\" +.\" GENDSA +.\" +.Sh GENDSA +.nr nS 1 +.Nm "openssl gendsa" +.Bk -words +.Oo +.Fl aes128 | aes192 | aes256 | +.Fl des | des3 +.Oc +.Op Fl engine Ar id +.Op Fl out Ar file +.Op Ar paramfile +.Ek +.nr nS 0 +.Pp +The +.Nm gendsa +command generates a DSA private key from a DSA parameter file +(which will typically be generated by the +.Nm openssl dsaparam +command). +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Xo +.Fl aes128 | aes192 | aes256 | +.Fl des | des3 +.Xc +These options 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 engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm gendsa +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.It Fl out Ar file +The output +.Ar file . +If this argument is not specified, standard output is used. +.It Ar paramfile +This option specifies the DSA parameter file to use. +The parameters in this file determine the size of the private key. +DSA parameters can be generated and examined using the +.Nm openssl dsaparam +command. +.El +.Sh GENDSA NOTES +DSA key generation is little more than random number generation so it is +much quicker than RSA key generation, for example. +.\" +.\" GENPKEY +.\" +.Sh GENPKEY +.nr nS 1 +.Nm "openssl genpkey" +.Bk -words +.Op Fl algorithm Ar alg +.Op Ar cipher +.Op Fl engine Ar id +.Op Fl genparam +.Op Fl out Ar file +.Op Fl outform Ar DER | PEM +.Op Fl paramfile Ar file +.Op Fl pass Ar arg +.Op Fl pkeyopt Ar opt : Ns Ar value +.Op Fl text +.Ek +.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 +and engine-provided algorithms 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. +If used 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 +.Fn EVP_get_cipherbyname +is acceptable, such as +.Cm des3 . +.It Fl engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm genpkey +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.It Fl genparam +Generate a set of parameters instead of a private key. +If used this option must precede any +.Fl algorithm , +.Fl paramfile , +or +.Fl pkeyopt +options. +.It Fl out Ar file +The output filename. +If this argument is not specified then standard output is used. +.It Fl outform Ar DER | PEM +This specifies the output format, DER or PEM. +.It Fl paramfile Ar file +Some public key algorithms generate a private key based on a set of parameters. +They can be supplied using this option. +If this option is used the public key +algorithm used is determined by the parameters. +If used 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. +For more information about the format of +.Ar arg , +see the +.Sx PASS PHRASE ARGUMENTS +section above. +.It Fl pkeyopt Ar opt : Ns Ar value +Set the public key algorithm option +.Ar opt +to +.Ar value . +The precise set of options supported +depends on the public key algorithm used and its implementation. +See +.Sx GENPKEY KEY GENERATION OPTIONS +below for more details. +.It Fl text +Print an (unencrypted) text representation of private and public keys and +parameters along with the DER or PEM structure. +.El +.Sh GENPKEY KEY GENERATION OPTIONS +The options supported by each algorithm +and indeed each implementation of an algorithm can vary. +The options for the +.Nm OpenSSL +implementations are detailed below. +.Bl -tag -width Ds -offset indent +.It rsa_keygen_bits : Ns Ar numbits +(RSA) +The number of bits in the generated key. +If not specified 2048 is used. +.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 value is 65537. +.It dsa_paramgen_bits : Ns Ar numbits +(DSA) +The number of bits in the generated parameters. +If not specified 1024 is used. +.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 +.Sh GENPKEY EXAMPLES +Generate an RSA private key using default parameters: +.Bd -literal -offset indent +$ openssl genpkey -algorithm RSA -out key.pem +.Ed +.Pp +Encrypt and output a private key using 128-bit AES and the passphrase "hello": +.Bd -literal -offset indent +$ openssl genpkey -algorithm RSA -out key.pem \e + -aes-128-cbc -pass pass:hello +.Ed +.Pp +Generate a 2048-bit RSA key using 3 as the public exponent: +.Bd -literal -offset indent +$ openssl genpkey -algorithm RSA -out key.pem \e + -pkeyopt rsa_keygen_bits:2048 -pkeyopt rsa_keygen_pubexp:3 +.Ed +.Pp +Generate 1024-bit DSA parameters: +.Bd -literal -offset indent +$ openssl genpkey -genparam -algorithm DSA \e + -out dsap.pem -pkeyopt dsa_paramgen_bits:1024 +.Ed +.Pp +Generate a DSA key from parameters: +.Bd -literal -offset indent +$ openssl genpkey -paramfile dsap.pem -out dsakey.pem +.Ed +.Pp +Generate 1024-bit DH parameters: +.Bd -literal -offset indent +$ openssl genpkey -genparam -algorithm DH \e + -out dhp.pem -pkeyopt dh_paramgen_prime_len:1024 +.Ed +.Pp +Generate a DH key from parameters: +.Bd -literal -offset indent +$ openssl genpkey -paramfile dhp.pem -out dhkey.pem +.Ed +.\" +.\" GENRSA +.\" +.Sh GENRSA +.nr nS 1 +.Nm "openssl genrsa" +.Bk -words +.Op Fl 3 | f4 +.Oo +.Fl aes128 | aes192 | aes256 | +.Fl des | des3 +.Oc +.Op Fl engine Ar id +.Op Fl out Ar file +.Op Fl passout Ar arg +.Op Ar numbits +.Ek +.nr nS 0 +.Pp +The +.Nm genrsa +command generates an RSA private key. +.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 Xo +.Fl aes128 | aes192 | aes256 | +.Fl des | des3 +.Xc +These options 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 engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm genrsa +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.It Fl out Ar file +The output +.Ar file . +If this argument is not specified, standard output is used. +.It Fl passout Ar arg +The output file password source. +For more information about the format of +.Ar arg , +see the +.Sx PASS PHRASE ARGUMENTS +section above. +.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 GENRSA NOTES +RSA private key generation essentially involves the generation of two prime +numbers. +When generating a private 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 +.Pq the actual number depends on the key size . +.Pp +Because key generation is a random process, +the time taken to generate a key may vary somewhat. +.Sh GENRSA BUGS +A quirk of the prime generation algorithm is that it cannot generate small +primes. +Therefore the number of bits should not be less that 64. +For typical private keys this will not matter because for security reasons +they will be much larger +.Pq typically 2048 bits . +.\" +.\" NSEQ +.\" +.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 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 +This specifies the input +.Ar file +to read, or standard input if this option is not specified. +.It Fl out Ar file +Specifies the output +.Ar file , +or standard output by default. +.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 NSEQ EXAMPLES +Output the certificates in a Netscape certificate sequence: +.Bd -literal -offset indent +$ openssl nseq -in nseq.pem -out certs.pem +.Ed +.Pp +Create a Netscape certificate sequence: +.Bd -literal -offset indent +$ openssl nseq -in certs.pem -toseq -out nseq.pem +.Ed +.Sh NSEQ NOTES +The PEM-encoded form uses the same headers and footers as a certificate: +.Bd -unfilled -offset indent +-----BEGIN CERTIFICATE----- +-----END CERTIFICATE----- +.Ed +.Pp +A Netscape certificate sequence is a Netscape specific form that can be sent +to browsers as an alternative to the standard PKCS#7 format when several +certificates are sent to the browser: +for example during certificate enrollment. +It is used by the Netscape certificate server, for example. +.Sh NSEQ BUGS +This program needs a few more options, +like allowing DER or PEM input and output files +and allowing multiple certificate files to be used. +.\" +.\" OCSP +.\" +.Sh OCSP +.nr nS 1 +.Nm "openssl ocsp" +.Bk -words +.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 +.Oo +.Fl host +.Ar hostname : Ns Ar port +.Oc +.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 +.Ek +.nr nS 0 +.Pp +The Online Certificate Status Protocol +.Pq OCSP +enables applications to determine the +.Pq revocation +state of an identified certificate +.Pq 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 +.Ar file +or +.Ar path +containing trusted CA certificates. +These are 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 +Sets the digest algorithm to use 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 +If the +.Fl host +option is present, then the OCSP request is sent to the host +.Ar hostname +on port +.Ar port . +.Fl path +specifies the HTTP path name to use, or +.Sq / +by default. +.It Fl issuer Ar file +This specifies the current issuer certificate. +This option can be used multiple times. +The certificate specified in +.Ar file +must be in PEM format. +This option +.Em 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 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. +With this option, 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 +.Em nonce +extension to a request or disable an OCSP +.Em nonce +addition. +Normally, if an OCSP request is input using the +.Fl respin +option no +.Em nonce +is added: +using the +.Fl nonce +option will force addition of a +.Em nonce . +If an OCSP request is being created (using the +.Fl cert +and +.Fl serial +options) +a +.Em nonce +is automatically added; specifying +.Fl no_nonce +overrides this. +.It Fl noverify +Don't attempt to verify the OCSP response signature or the +.Em nonce +values. +This option will normally only be used for debugging +since it disables all verification of the responder's certificate. +.It Fl out Ar file +Specify output +.Ar file ; +default is standard output. +.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 +.Sq - +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 +.Ar 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 +These options specify the range of times, in seconds, which will be tolerated +in an OCSP response. +Each certificate status response includes a +.Em notBefore +time and an optional +.Em 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 is 5 minutes. +.Pp +If the +.Em notAfter +time is omitted from a response, then this means that new status +information is immediately available. +In this case the age of the +.Em 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 +.Ar 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; +this option can be used to supply the necessary certificate in such cases. +.El +.Sh OCSP SERVER OPTIONS +.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 +.Nm ca +format containing certificate revocation information. +.Pp +If the +.Fl index +option is specified, the +.Nm ocsp +utility is in +.Em responder +mode, otherwise it is in +.Em client +mode. +The request(s) 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 the +.Fl index +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 +.Ar nextUpdate +field. +If neither option is present, the +.Em nextUpdate +field is omitted, meaning fresh revocation information is immediately available. +.It Fl nrequest Ar number +The OCSP server will exit after receiving +.Ar number +requests, default unlimited. +.It Fl port Ar portnum +Port to listen for OCSP requests on. +The port may also be specified using the +.Fl url +option. +.It Fl resp_key_id +Identify the signer certificate using the key ID; +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 +.Sh OCSP RESPONSE VERIFICATION +OCSP Response follows the rules specified in RFC 2560. +.Pp +Initially the OCSP responder certificate is located and the signature on +the OCSP request checked using the responder certificate's public key. +.Pp +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. +.Pp +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. +.Pp +What this effectively means is that if the OCSP responder certificate is +authorised directly by the CA it is issuing revocation information about +.Pq and it is correctly configured , +then verification will succeed. +.Pp +If the OCSP responder is a +.Em 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. +For example: +.Bd -literal -offset indent +$ openssl x509 -in ocspCA.pem -addtrust OCSPSigning \e + -out trustedCA.pem +.Ed +.Pp +Alternatively, the responder certificate itself can be explicitly trusted +with the +.Fl VAfile +option. +.Sh OCSP NOTES +As noted, most of the verify options are for testing or debugging purposes. +Normally, only the +.Fl CApath , CAfile +and +.Pq if the responder is a `global VA' +.Fl VAfile +options need to be used. +.Pp +The OCSP server is only useful for test and demonstration purposes: +it is not really usable as a full OCSP responder. +It contains only a very simple HTTP request handling and can only handle +the POST form of OCSP queries. +It also handles requests serially, meaning it cannot respond to +new requests until it has processed the current one. +The text index file format of revocation is also inefficient for large +quantities of revocation data. +.Pp +It is possible to run the +.Nm ocsp +application in +.Em responder +mode via a CGI script using the +.Fl respin +and +.Fl respout +options. +.Sh OCSP EXAMPLES +Create an OCSP request and write it to a file: +.Bd -literal -offset indent +$ openssl ocsp -issuer issuer.pem -cert c1.pem -cert c2.pem \e + -reqout req.der +.Ed +.Pp +Send a query to an OCSP responder with URL +.Pa http://ocsp.myhost.com/ , +save the response to a file and print it out in text form: +.Bd -literal -offset indent +$ openssl ocsp -issuer issuer.pem -cert c1.pem -cert c2.pem \e + -url http://ocsp.myhost.com/ -resp_text -respout resp.der +.Ed +.Pp +Read in an OCSP response and print out in text form: +.Pp +.Dl $ openssl ocsp -respin resp.der -text +.Pp +OCSP server on port 8888 using a standard +.Nm ca +configuration, and a separate responder certificate. +All requests and responses are printed to a file: +.Bd -literal -offset indent +$ openssl ocsp -index demoCA/index.txt -port 8888 -rsigner \e + rcert.pem -CA demoCA/cacert.pem -text -out log.txt +.Ed +.Pp +As above, but exit after processing one request: +.Bd -literal -offset indent +$ openssl ocsp -index demoCA/index.txt -port 8888 -rsigner \e + rcert.pem -CA demoCA/cacert.pem -nrequest 1 +.Ed +.Pp +Query status information using internally generated request: +.Bd -literal -offset indent +$ openssl ocsp -index demoCA/index.txt -rsigner rcert.pem -CA \e + demoCA/cacert.pem -issuer demoCA/cacert.pem -serial 1 +.Ed +.Pp +Query status information using request read from a file and write +the response to a second file: +.Bd -literal -offset indent +$ openssl ocsp -index demoCA/index.txt -rsigner rcert.pem -CA \e + demoCA/cacert.pem -reqin req.der -respout resp.der +.Ed +.\" +.\" PASSWD +.\" +.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 typed at run-time +or the hash of each password in a list. +The password list is taken from the named +.Ar file +for option +.Fl in , +from stdin for option +.Fl stdin , +or from the command line, or from the terminal otherwise. +The +.Ux +standard algorithm +.Em crypt +and the MD5-based +.Bx +password algorithm +.Em 1 +and its Apache variant +.Em apr1 +are available. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl 1 +Use the MD5 based +.Bx +password algorithm +.Em 1 . +.It Fl apr1 +Use the +.Em apr1 +algorithm +.Pq Apache variant of the +.Bx +algorithm. +.It Fl crypt +Use the +.Em crypt +algorithm +.Pq 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 specified +.Ar salt . +When reading a password from the terminal, this implies +.Fl noverify . +.It Fl stdin +Read passwords from +.Em stdin . +.It Fl table +In the output list, prepend the cleartext password and a TAB character +to each password hash. +.El +.Sh PASSWD EXAMPLES +.Dl $ openssl passwd -crypt -salt xx password +prints +.Qq xxj31ZMTZzkVA . +.Pp +.Dl $ openssl passwd -1 -salt xxxxxxxx password +prints +.Qq $1$xxxxxxxx$UYCIxa628.9qXjpQCjM4a. . +.Pp +.Dl $ openssl passwd -apr1 -salt xxxxxxxx password +prints +.Qq $apr1$xxxxxxxx$dxHfLAsjHkDRmG83UXe8K0 . +.\" +.\" PKCS7 +.\" +.Sh PKCS7 +.nr nS 1 +.Nm "openssl pkcs7" +.Bk -words +.Op Fl engine Ar id +.Op Fl in Ar file +.Op Fl inform Ar DER | PEM +.Op Fl noout +.Op Fl out Ar file +.Op Fl outform Ar DER | PEM +.Op Fl print_certs +.Op Fl text +.Ek +.nr nS 0 +.Pp +The +.Nm pkcs7 +command processes PKCS#7 files in DER or PEM format. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm pkcs7 +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.It Fl in Ar file +This specifies the input +.Ar file +to read from, or standard input if this option is not specified. +.It Fl inform Ar DER | PEM +This specifies the input format. +.Ar DER +format is a DER-encoded PKCS#7 v1.5 structure. +.Ar PEM +.Pq the default +is a base64-encoded version of the DER form with header and footer lines. +.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 +Specifies the output +.Ar file +to write to, or standard output by default. +.It Fl outform Ar DER | PEM +This specifies the output format; the options have the same meaning as the +.Fl inform +option. +.It Fl print_certs +Prints out any certificates or CRLs contained in the file. +They are preceded by their subject and issuer names in a one-line format. +.It Fl text +Prints out certificate details in full rather than just subject and +issuer names. +.El +.Sh PKCS7 EXAMPLES +Convert a PKCS#7 file from PEM to DER: +.Pp +.Dl $ openssl pkcs7 -in file.pem -outform DER -out file.der +.Pp +Output all certificates in a file: +.Pp +.Dl $ openssl pkcs7 -in file.pem -print_certs -out certs.pem +.Sh PKCS7 NOTES +The PEM PKCS#7 format uses the header and footer lines: +.Bd -unfilled -offset indent +-----BEGIN PKCS7----- +-----END PKCS7----- +.Ed +.Pp +For compatibility with some CAs it will also accept: +.Bd -unfilled -offset indent +-----BEGIN CERTIFICATE----- +-----END CERTIFICATE----- +.Ed +.Sh PKCS7 RESTRICTIONS +There is no option to print out all the fields of a PKCS#7 file. +.Pp +The PKCS#7 routines only understand PKCS#7 v 1.5 as specified in RFC 2315. +They cannot currently parse, for example, the new CMS as described in RFC 2630. +.\" +.\" PKCS8 +.\" +.Sh PKCS8 +.nr nS 1 +.Nm "openssl pkcs8" +.Bk -words +.Op Fl embed +.Op Fl engine Ar id +.Op Fl in Ar file +.Op Fl inform Ar DER | PEM +.Op Fl nocrypt +.Op Fl noiter +.Op Fl nooct +.Op Fl nsdb +.Op Fl out Ar file +.Op Fl outform Ar 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 +.Ek +.nr nS 0 +.Pp +The +.Nm pkcs8 +command processes private keys in PKCS#8 format. +It can handle both unencrypted PKCS#8 PrivateKeyInfo format +and EncryptedPrivateKeyInfo format with a variety of PKCS#5 +.Pq v1.5 and v2.0 +and PKCS#12 algorithms. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl embed +This option generates DSA keys in a broken format. +The DSA parameters are embedded inside the +.Em PrivateKey +structure. +In this form the OCTET STRING contains an ASN1 SEQUENCE consisting of +two structures: +a SEQUENCE containing the parameters and an ASN1 INTEGER containing +the private key. +.It Fl engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm pkcs8 +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.It Fl in Ar file +This specifies the input +.Ar file +to read a key from, or standard input if this option is not specified. +If the key is encrypted, a pass phrase will be prompted for. +.It Fl inform Ar DER | PEM +This specifies the input format. +If a PKCS#8 format key is expected on input, +then either a +DER- or PEM-encoded version of a PKCS#8 key will be expected. +Otherwise the DER or PEM format of the traditional format private key is used. +.It Fl nocrypt +PKCS#8 keys generated or input are normally PKCS#8 +.Em EncryptedPrivateKeyInfo +structures using an appropriate password-based encryption algorithm. +With this option, an unencrypted +.Em PrivateKeyInfo +structure is expected or output. +This option does not encrypt private keys at all and should only be used +when absolutely necessary. +Certain software such as some versions of Java code signing software use +unencrypted private keys. +.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 +This option generates 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 +This option generates DSA keys in a broken format compatible with Netscape +private key databases. +The +.Em PrivateKey +contains a SEQUENCE consisting of the public and private keys, respectively. +.It Fl out Ar file +This specifies the output +.Ar file +to write a key to, or standard output by default. +If any encryption options are set, a pass phrase will be prompted for. +The output filename should +.Em not +be the same as the input filename. +.It Fl outform Ar DER | PEM +This specifies the output format; the options have the same meaning as the +.Fl inform +option. +.It Fl passin Ar arg +The key password source. +For more information about the format of +.Ar arg , +see the +.Sx PASS PHRASE ARGUMENTS +section above. +.It Fl passout Ar arg +The output file password source. +For more information about the format of +.Ar arg , +see the +.Sx PASS PHRASE ARGUMENTS +section above. +.It Fl topk8 +Normally, a PKCS#8 private key is expected on input and a traditional format +private key will be written. +With the +.Fl topk8 +option the situation is reversed: +it reads a traditional format private key and writes a PKCS#8 format key. +.It Fl v1 Ar alg +This option specifies a PKCS#5 v1.5 or PKCS#12 algorithm to use. +A complete list of possible algorithms is included below. +.It Fl v2 Ar alg +This option enables the use of PKCS#5 v2.0 algorithms. +Normally, PKCS#8 private keys are encrypted with the password-based +encryption algorithm called +.Em pbeWithMD5AndDES-CBC ; +this uses 56-bit DES encryption but it was the strongest encryption +algorithm supported in PKCS#5 v1.5. +Using the +.Fl v2 +option PKCS#5 v2.0 algorithms are used which can use any +encryption algorithm 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 +then this doesn't matter. +.Pp +The +.Ar alg +argument is the encryption algorithm to use; valid values include +.Ar des , des3 , +and +.Ar rc2 . +It is recommended that +.Ar des3 +is used. +.El +.Sh PKCS8 NOTES +The encrypted form of a PEM-encoded PKCS#8 file uses the following +headers and footers: +.Bd -unfilled -offset indent +-----BEGIN ENCRYPTED PRIVATE KEY----- +-----END ENCRYPTED PRIVATE KEY----- +.Ed +.Pp +The unencrypted form uses: +.Bd -unfilled -offset indent +-----BEGIN PRIVATE KEY----- +-----END PRIVATE KEY----- +.Ed +.Pp +Private keys encrypted using PKCS#5 v2.0 algorithms and high iteration +counts are more secure than those encrypted using the traditional +.Nm SSLeay +compatible formats. +So if additional security is considered important, the keys should be converted. +.Pp +The default encryption is only 56 bits because this is the encryption +that most current implementations of PKCS#8 support. +.Pp +Some software may use PKCS#12 password-based encryption algorithms +with PKCS#8 format private keys: these are handled automatically +but there is no option to produce them. +.Pp +It is possible to write out +DER-encoded encrypted private keys in PKCS#8 format because the encryption +details are included at an ASN1 +level whereas the traditional format includes them at a PEM level. +.Sh PKCS#5 V1.5 AND PKCS#12 ALGORITHMS +Various algorithms can be used with the +.Fl v1 +command line option, including PKCS#5 v1.5 and PKCS#12. +These are described in more detail below. +.Pp +.Bl -tag -width "XXXX" -compact +.It Ar PBE-MD2-DES | PBE-MD5-DES +These algorithms were included in the original PKCS#5 v1.5 specification. +They only offer 56 bits of protection since they both use DES. +.Pp +.It Ar PBE-SHA1-RC2-64 | PBE-MD2-RC2-64 | PBE-MD5-RC2-64 | PBE-SHA1-DES +These algorithms are not mentioned in the original PKCS#5 v1.5 specification +but they use the same key derivation algorithm and are supported by some +software. +They are mentioned in PKCS#5 v2.0. +They use either 64-bit RC2 or 56-bit DES. +.Pp +.It Ar PBE-SHA1-RC4-128 | PBE-SHA1-RC4-40 | PBE-SHA1-3DES | PBE-SHA1-2DES +.It Ar PBE-SHA1-RC2-128 | PBE-SHA1-RC2-40 +These algorithms use the PKCS#12 password-based encryption algorithm and +allow strong encryption algorithms like triple DES or 128-bit RC2 to be used. +.El +.Sh PKCS8 EXAMPLES +Convert a private key from traditional to PKCS#5 v2.0 format using triple DES: +.Pp +.Dl "$ openssl pkcs8 -in key.pem -topk8 -v2 des3 -out enckey.pem" +.Pp +Convert a private key to PKCS#8 using a PKCS#5 1.5 compatible algorithm +.Pq DES : +.Pp +.Dl $ openssl pkcs8 -in key.pem -topk8 -out enckey.pem +.Pp +Convert a private key to PKCS#8 using a PKCS#12 compatible algorithm +.Pq 3DES : +.Bd -literal -offset indent +$ openssl pkcs8 -in key.pem -topk8 -out enckey.pem \e + -v1 PBE-SHA1-3DES +.Ed +.Pp +Read a DER-unencrypted PKCS#8 format private key: +.Pp +.Dl "$ openssl pkcs8 -inform DER -nocrypt -in key.der -out key.pem" +.Pp +Convert a private key from any PKCS#8 format to traditional format: +.Pp +.Dl $ openssl pkcs8 -in pk8.pem -out key.pem +.Sh PKCS8 STANDARDS +Test vectors from this PKCS#5 v2.0 implementation were posted to the +pkcs-tng mailing list using triple DES, DES and RC2 with high iteration counts; +several people confirmed that they could decrypt the private +keys produced and therefore it can be assumed that the PKCS#5 v2.0 +implementation is reasonably accurate at least as far as these +algorithms are concerned. +.Pp +The format of PKCS#8 DSA +.Pq and other +private keys is not well documented: +it is hidden away in PKCS#11 v2.01, section 11.9; +.Nm OpenSSL Ns Li 's +default DSA PKCS#8 private key format complies with this standard. +.Sh PKCS8 BUGS +There should be an option that prints out the encryption algorithm +in use and other details such as the iteration count. +.Pp +PKCS#8 using triple DES and PKCS#5 v2.0 should be the default private +key format; for +.Nm OpenSSL +compatibility, several of the utilities use the old format at present. +.\" +.\" PKCS12 +.\" +.Sh PKCS12 +.nr nS 1 +.Nm "openssl pkcs12" +.Bk -words +.Oo +.Fl aes128 | aes192 | aes256 | +.Fl des | des3 +.Oc +.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 engine Ar id +.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 +.Ek +.nr nS 0 +.Pp +The +.Nm pkcs12 +command allows PKCS#12 files +.Pq sometimes referred to as PFX files +to be created and parsed. +PKCS#12 files are used by several programs including Netscape, MSIE +and MS Outlook. +.Pp +There are a lot of options; the meaning of some depends on whether a +PKCS#12 file is being created or parsed. +By default, a PKCS#12 file is parsed; +a PKCS#12 file can be created by using the +.Fl export +option +.Pq see below . +.Sh PKCS12 PARSING OPTIONS +.Bl -tag -width "XXXX" +.It Xo +.Fl aes128 | aes192 | aes256 | +.Fl des | des3 +.Xc +Use AES, DES, or triple DES, respectively, +to encrypt private keys before outputting. +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 +This specifies the +.Ar file +of the PKCS#12 file to be parsed. +Standard input is used by default. +.It Fl info +Output additional information about the PKCS#12 file structure, +algorithms used, and iteration counts. +.It Fl nocerts +No certificates at all will be output. +.It Fl nodes +Don't encrypt the private keys at all. +.It Fl nokeys +No private keys will be output. +.It Fl nomacver +Don't attempt to verify the integrity MAC before reading the file. +.It Fl noout +This option inhibits output of the keys and certificates to the output file +version of the PKCS#12 file. +.It Fl out Ar file +The +.Ar file +to write certificates and private keys to, standard output by default. +They are all written in PEM format. +.It Fl passin Ar arg +The key password source. +For more information about the format of +.Ar arg , +see the +.Sx PASS PHRASE ARGUMENTS +section above. +.It Fl passout Ar arg +The output file password source. +For more information about the format of +.Ar arg , +see the +.Sx PASS PHRASE ARGUMENTS +section above. +.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 +.Sh PKCS12 FILE CREATION OPTIONS +.Bl -tag -width "XXXX" +.It Fl CAfile Ar file +CA storage as a file. +.It Fl CApath Ar directory +CA storage as a directory. +This directory must be a standard certificate directory: +that is, a hash of each subject name (using +.Cm x509 -hash ) +should be linked to each certificate. +.It Fl caname Ar name +This specifies the +.Qq friendly name +for other certificates. +This option may be used multiple times to specify names for all certificates +in the order they appear. +Netscape ignores friendly names on other certificates, +whereas MSIE displays them. +.It Fl certfile Ar file +A file to read additional certificates from. +.It Fl certpbe Ar alg , Fl keypbe Ar alg +These options allow 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 (see the +.Sx PKCS12 NOTES +section for more information). +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 +If this option is present, an attempt is made to 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 engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm pkcs12 +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.It Fl export +This option specifies that a PKCS#12 file will be created rather than +parsed. +.It Fl in Ar file +The +.Ar file +to read certificates and private keys from, standard input by default. +They must all be in PEM format. +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 private key from. +If not present, a private key must be present in the input file. +.It Fl keyex | keysig +Specifies that the private key is to be used for key exchange or just signing. +This option is only interpreted by MSIE and similar MS software. +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 +.Pq ActiveX control signing +and SSL client authentication; +however, due to a bug only MSIE 5.0 and later support +the use of signing only keys for SSL client authentication. +.It Fl macalg Ar alg +Specify the MAC digest algorithm. +If not included then SHA1 is used. +.It Fl maciter +This option is included for compatibility with previous versions; it used +to be needed to use MAC iterations counts but they are now used by default. +.It Fl name Ar name +This specifies 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 +These options affect the iteration counts on the MAC and key algorithms. +Unless you wish to produce files compatible with MSIE 4.0, you should leave +these options alone. +.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. +MSIE 4.0 doesn't support MAC iteration counts, so it needs the +.Fl nomaciter +option. +.It Fl out Ar file +This specifies +.Ar file +to write the PKCS#12 file to. +Standard output is used by default. +.It Fl passin Ar arg +The key password source. +For more information about the format of +.Ar arg , +see the +.Sx PASS PHRASE ARGUMENTS +section above. +.It Fl passout Ar arg +The output file password source. +For more information about the format of +.Ar arg , +see the +.Sx PASS PHRASE ARGUMENTS +section above. +.El +.Sh PKCS12 NOTES +Although there are a large number of options, +most of them are very rarely used. +For PKCS#12 file parsing, only +.Fl in +and +.Fl out +need to be used for PKCS#12 file creation. +.Fl export +and +.Fl name +are also used. +.Pp +If none of the +.Fl clcerts , cacerts , +or +.Fl nocerts +options are present, then all certificates will be output in the order +they appear in the input PKCS#12 files. +There is no guarantee that the first certificate present is +the one corresponding to the private key. +Certain software which requires a private key and certificate and assumes +the first certificate in the file is the one corresponding to the private key: +this may not always be the case. +Using the +.Fl clcerts +option will solve this problem by only outputting the certificate +corresponding to the private key. +If the CA certificates are required, they can be output to a separate +file using the +.Fl nokeys +and +.Fl cacerts +options to just output CA certificates. +.Pp +The +.Fl keypbe +and +.Fl certpbe +algorithms allow the precise encryption algorithms for private keys +and certificates to be specified. +Normally, the defaults are fine but occasionally software can't handle +triple DES encrypted private keys; +then the option +.Fl keypbe Ar PBE-SHA1-RC2-40 +can be used to reduce the private key encryption to 40-bit RC2. +A complete description of all algorithms is contained in the +.Sx PKCS8 +section above. +.Sh PKCS12 EXAMPLES +Parse a PKCS#12 file and output it to a file: +.Pp +.Dl $ openssl pkcs12 -in file.p12 -out file.pem +.Pp +Output only client certificates to a file: +.Pp +.Dl $ openssl pkcs12 -in file.p12 -clcerts -out file.pem +.Pp +Don't encrypt the private key: +.Pp +.Dl $ openssl pkcs12 -in file.p12 -out file.pem -nodes +.Pp +Print some info about a PKCS#12 file: +.Pp +.Dl $ openssl pkcs12 -in file.p12 -info -noout +.Pp +Create a PKCS#12 file: +.Bd -literal -offset indent +$ openssl pkcs12 -export -in file.pem -out file.p12 \e + -name "My Certificate" +.Ed +.Pp +Include some extra certificates: +.Bd -literal -offset indent +$ openssl pkcs12 -export -in file.pem -out file.p12 \e + -name "My Certificate" -certfile othercerts.pem +.Ed +.Sh PKCS12 BUGS +Some would argue that the PKCS#12 standard is one big bug :\-) +.Pp +Versions of +.Nm OpenSSL +before 0.9.6a had a bug in the PKCS#12 key generation routines. +Under rare circumstances this could produce a PKCS#12 file encrypted +with an invalid key. +As a result some PKCS#12 files which triggered this bug +from other implementations +.Pq MSIE or Netscape +could not be decrypted by +.Nm OpenSSL +and similarly +.Nm OpenSSL +could produce PKCS#12 files which could not be decrypted by other +implementations. +The chances of producing such a file are relatively small: less than 1 in 256. +.Pp +A side effect of fixing this bug is that any old invalidly encrypted PKCS#12 +files can no longer be parsed by the fixed version. +Under such circumstances the +.Nm pkcs12 +utility will report that the MAC is OK but fail with a decryption +error when extracting private keys. +.Pp +This problem can be resolved by extracting the private keys and certificates +from the PKCS#12 file using an older version of +.Nm OpenSSL +and recreating +the PKCS#12 file from the keys and certificates using a newer version of +.Nm OpenSSL . +For example: +.Bd -literal -offset indent +$ old-openssl -in bad.p12 -out keycerts.pem +$ openssl -in keycerts.pem -export -name "My PKCS#12 file" \e + -out fixed.p12 +.Ed +.\" +.\" PKEY +.\" +.Sh PKEY +.nr nS 1 +.Nm "openssl pkey" +.Bk -words +.Op Ar cipher +.Op Fl engine Ar id +.Op Fl in Ar file +.Op Fl inform Ar DER | PEM +.Op Fl noout +.Op Fl out Ar file +.Op Fl outform Ar 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 +.Ek +.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 +These options encrypt the private key with the supplied cipher. +Any algorithm name accepted by +.Fn EVP_get_cipherbyname +is acceptable, such as +.Cm des3 . +.It Fl engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm pkey +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.It Fl in Ar file +This specifies the input filename to read a key from, +or standard input if this option is not specified. +If the key is encrypted a pass phrase will be prompted for. +.It Fl inform Ar DER | PEM +This specifies the input format, DER or PEM. +.It Fl noout +Do not output the encoded version of the key. +.It Fl out Ar file +This specifies the output filename to write a key to, +or standard output if this option is not specified. +If any encryption options are set then a pass phrase +will be prompted for. +The output filename should +.Em not +be the same as the input filename. +.It Fl outform Ar DER | PEM +This specifies the output format; +the options have the same meaning as the +.Fl inform +option. +.It Fl passin Ar arg +The key password source. +For more information about the format of +.Ar arg , +see the +.Sx PASS PHRASE ARGUMENTS +section above. +.It Fl passout Ar arg +The output file password source. +For more information about the format of +.Ar arg +see the +.Sx PASS PHRASE ARGUMENTS +section above. +.It Fl pubin +By default a private key is read from the input file: +with this option a public key is read instead. +.It Fl pubout +By default a private key is output: +with this option a public key will be output instead. +This option is automatically set if +the input is a public key. +.It Fl text +Print out the various public or private key components in +plain text in addition to the encoded version. +.It Fl text_pub +Print out only public key components +even if a private key is being processed. +.El +.Sh PKEY EXAMPLES +To remove the pass phrase on an RSA private key: +.Bd -literal -offset indent +$ openssl pkey -in key.pem -out keyout.pem +.Ed +.Pp +To encrypt a private key using triple DES: +.Bd -literal -offset indent +$ openssl pkey -in key.pem -des3 -out keyout.pem +.Ed +.Pp +To convert a private key from PEM to DER format: +.Bd -literal -offset indent +$ openssl pkey -in key.pem -outform DER -out keyout.der +.Ed +.Pp +To print the components of a private key to standard output: +.Bd -literal -offset indent +$ openssl pkey -in key.pem -text -noout +.Ed +.Pp +To print the public components of a private key to standard output: +.Bd -literal -offset indent +$ openssl pkey -in key.pem -text_pub -noout +.Ed +.Pp +To just output the public part of a private key: +.Bd -literal -offset indent +$ openssl pkey -in key.pem -pubout -out pubkey.pem +.Ed +.\" +.\" PKEYPARAM +.\" +.Sh PKEYPARAM +.Cm openssl pkeyparam +.Op Fl engine Ar id +.Op Fl in Ar file +.Op Fl noout +.Op Fl out Ar file +.Op Fl text +.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 Fl engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm pkeyparam +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.It Fl in Ar file +This specifies the input filename to read parameters from, +or standard input if this option is not specified. +.It Fl noout +Do not output the encoded version of the parameters. +.It Fl out Ar file +This specifies the output filename to write parameters to, +or standard output if this option is not specified. +.It Fl text +Prints out the parameters in plain text in addition to the encoded version. +.El +.Sh PKEYPARAM EXAMPLES +Print out text version of parameters: +.Bd -literal -offset indent +$ openssl pkeyparam -in param.pem -text +.Ed +.Sh PKEYPARAM NOTES +There are no +.Fl inform +or +.Fl outform +options for this command because only PEM format is supported +because the key type is determined by the PEM headers. +.\" +.\" PKEYUTL +.\" +.Sh PKEYUTL +.nr nS 1 +.Nm "openssl pkeyutl" +.Bk -words +.Op Fl asn1parse +.Op Fl certin +.Op Fl decrypt +.Op Fl derive +.Op Fl encrypt +.Op Fl engine Ar id +.Op Fl hexdump +.Op Fl in Ar file +.Op Fl inkey Ar file +.Op Fl keyform Ar DER | ENGINE | PEM +.Op Fl out Ar file +.Op Fl passin Ar arg +.Op Fl peerform Ar DER | ENGINE | 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 +.Ek +.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 +ASN1parse the output data. +This is useful when combined with the +.Fl verifyrecover +option when an ASN1 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 engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm pkeyutl +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.It Fl hexdump +Hex dump the output data. +.It Fl in Ar file +Specify the input filename to read data from, +or standard input if this option is not specified. +.It Fl inkey Ar file +The input key file. +By default it should be a private key. +.It Fl keyform Ar DER | ENGINE | PEM +The key format DER, ENGINE, or PEM. +.It Fl out Ar file +Specify the output filename to write to, +or standard output by default. +.It Fl passin Ar arg +The key password source. +For more information about the format of +.Ar arg , +see the +.Sx PASS PHRASE ARGUMENTS +section above. +.It Fl peerform Ar DER | ENGINE | PEM +The peer key format DER, ENGINE, or PEM. +.It Fl peerkey Ar file +The peer key file, used by key derivation (agreement) operations. +.It Fl pkeyopt Ar opt : Ns Ar value +Public key options. +.It Fl pubin +The input file is a public key. +.It Fl rev +Reverse the order of the input buffer. +This is useful for some libraries (such as CryptoAPI) +which represent the buffer in little endian format. +.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 PKEYUTL NOTES +The operations and options supported vary according to the key algorithm +and its implementation. +The +.Nm OpenSSL +operations and options are indicated below. +.Pp +Unless otherwise mentioned all algorithms support the +.Ar digest : Ns Ar alg +option which specifies the digest in use +for sign, verify, and verifyrecover operations. +The value +.Ar alg +should represent a digest name as used in the +.Fn EVP_get_digestbyname +function, for example +.Cm sha1 . +.Ss RSA algorithm +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 sslv3 +for SSLv3 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. +.Pp +For oeap mode only encryption and decryption is supported. +.Pp +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. +.Pp +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 +.Ss DSA algorithm +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. +.Ss DH algorithm +The DH algorithm supports the derive operation +and no additional options. +.Ss EC algorithm +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. +.Sh PKEYUTL EXAMPLES +Sign some data using a private key: +.Bd -literal -offset indent +$ openssl pkeyutl -sign -in file -inkey key.pem -out sig +.Ed +.Pp +Recover the signed data (e.g. if an RSA key is used): +.Bd -literal -offset indent +$ openssl pkeyutl -verifyrecover -in sig -inkey key.pem +.Ed +.Pp +Verify the signature (e.g. a DSA key): +.Bd -literal -offset indent +$ openssl pkeyutl -verify -in file -sigfile sig \e + -inkey key.pem +.Ed +.Pp +Sign data using a message digest value (this is currently only valid for RSA): +.Bd -literal -offset indent +$ openssl pkeyutl -sign -in file -inkey key.pem \e + -out sig -pkeyopt digest:sha256 +.Ed +.Pp +Derive a shared secret value: +.Bd -literal -offset indent +$ openssl pkeyutl -derive -inkey key.pem \e + -peerkey pubkey.pem -out secret +.Ed +.\" +.\" PRIME +.\" +.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 +.\" +.\" RAND +.\" +.Sh RAND +.nr nS 1 +.Nm "openssl rand" +.Op Fl base64 +.Op Fl engine Ar id +.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 +.Em base64 +encoding on the output. +.It Fl engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm rand +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.It Fl hex +Specify hexadecimal output. +.It Fl out Ar file +Write to +.Ar file +instead of standard output. +.El +.\" +.\" REQ +.\" +.Sh REQ +.nr nS 1 +.Nm "openssl req" +.Bk -words +.Op Fl asn1-kludge +.Op Fl batch +.Op Fl config Ar file +.Op Fl days Ar n +.Op Fl engine Ar id +.Op Fl extensions Ar section +.Op Fl in Ar file +.Op Fl inform Ar DER | PEM +.Op Fl key Ar keyfile +.Op Fl keyform Ar 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 Ar 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 +.Ek +.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 +By default, the +.Nm req +command outputs certificate requests containing +no attributes in the correct PKCS#10 format. +However certain CAs will only +accept requests containing no attributes in an invalid form: this +option produces this invalid format. +.Pp +More precisely, the +.Em Attributes +in a PKCS#10 certificate request are defined as a SET OF Attribute. +They are +.Em not +optional, so if no attributes are present then they should be encoded as an +empty SET OF. +The invalid form does not include the empty +SET OF, whereas the correct form does. +.Pp +It should be noted that very few CAs still require the use of this option. +.It Fl batch +Non-interactive mode. +.It Fl config Ar file +This allows an alternative configuration file to be specified; +this overrides the compile time filename or any specified in +the +.Ev OPENSSL_CONF +environment variable. +.It Fl days Ar n +When the +.Fl x509 +option is being used, this specifies the number of +days to certify the certificate for. +The default is 30 days. +.It Fl engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm req +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.It Fl extensions Ar section , Fl reqexts Ar section +These options specify alternative sections to include certificate +extensions (if the +.Fl x509 +option is present) or certificate request extensions. +This allows several different sections to +be used in the same configuration file to specify requests for +a variety of purposes. +.It Fl in Ar file +This specifies the input +.Ar file +to read a request from, or standard input +if this option is not specified. +A request is only read if the creation options +.Fl new +and +.Fl newkey +are not specified. +.It Fl inform Ar DER | PEM +This specifies the input format. +The +.Ar DER +argument uses an ASN1 DER-encoded form compatible with the PKCS#10. +The +.Ar PEM +form is the default format: +it consists of the DER format base64-encoded with additional header and +footer lines. +.It Fl key Ar keyfile +This specifies the file to read the private key from. +It also accepts PKCS#8 format private keys for PEM format files. +.It Fl keyform Ar DER | PEM +The format of the private key file specified in the +.Fl key +argument. +.Ar PEM +is the default. +.It Fl keyout Ar file +This gives the +.Ar 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 md4 | md5 | sha1 +This specifies 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 +This option prints out the value of the modulus of the public key +contained in the request. +.It Fl nameopt Ar option , Fl reqopt Ar option +These options determine how the subject or issuer names are displayed. +The +.Ar option +argument 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 +This option generates a new certificate request. +It will prompt the user 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 +Adds the word NEW to the PEM file header and footer lines +on the outputed request. +Some software +.Pq Netscape certificate server +and some CAs need this. +.It Fl newkey Ar arg +This option creates a new certificate request and a new private key. +The argument takes one of several forms. +.Ar rsa : Ns Ar nbits , +where +.Ar nbits +is the number of bits, generates an RSA key +.Ar nbits +in size. +If +.Ar nbits +is omitted, i.e.\& +.Cm -newkey rsa +specified, +the default key size, specified in the configuration file, is used. +.Pp +All other algorithms support the +.Ar alg : Ns Ar file +form, +where file may be an algorithm parameter file, +created by the +.Cm genpkey -genparam +command or an X.509 certificate for a key with approriate algorithm. +.Pp +.Ar param : Ns Ar file +generates a key using the parameter file or certificate +.Ar file ; +the algorithm is determined by the parameters. +.Ar algname : Ns Ar file +use algorithm +.Ar algname +and parameter file +.Ar file : +the two algorithms must match or an error occurs. +.Ar algname +just uses algorithm +.Ar algname , +and parameters, if necessary, +should be specified via the +.Fl pkeyopt +option. +.Pp +.Ar dsa : Ns Ar file +generates a DSA key using the parameters in the file +.Ar file . +.It Fl no-asn1-kludge +Reverses the effect of +.Fl asn1-kludge . +.It Fl nodes +If this option is specified and a private key is created, it +will not be encrypted. +.It Fl noout +This option prevents output of the encoded version of the request. +.It Fl out Ar file +This specifies the output +.Ar file +to write to, or standard output by default. +.It Fl outform Ar DER | PEM +This specifies the output format; the options have the same meaning as the +.Fl inform +option. +.It Fl passin Ar arg +The key password source. +For more information about the format of +.Ar arg , +see the +.Sx PASS PHRASE ARGUMENTS +section above. +.It Fl passout Ar arg +The output file password source. +For more information about the format of +.Ar arg , +see the +.Sx PASS PHRASE ARGUMENTS +section above. +.It Fl pubkey +Outputs 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. +.Pp +See the discussion of the +.Fl certopt +option 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 subject field of input request with specified data and outputs +modified request. +The arg must be formatted as +.Em /type0=value0/type1=value1/type2=... ; +characters may be escaped by +.Sq \e +.Pq backslash ; +no spaces are skipped. +.It Fl subject +Prints out the request subject (or certificate subject if +.Fl x509 +is specified. +.It Fl text +Prints out the certificate request in text form. +.It Fl utf8 +This option causes field values to be interpreted as UTF8 strings; +by default they are interpreted as ASCII. +This means that the field values, whether prompted from a terminal or +obtained from a configuration file, must be valid UTF8 strings. +.It Fl verbose +Print extra details about the operations being performed. +.It Fl verify +Verifies the signature on the request. +.It Fl x509 +This option outputs 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 +.Pq if any +are specified in the configuration file. +Unless specified using the +.Fl set_serial +option, 0 will be used for the serial number. +.El +.Sh REQ CONFIGURATION FILE FORMAT +The configuration options are specified in the +.Em req +section of the configuration file. +As with all configuration files, if no value is specified in the specific +section (i.e.\& +.Em req ) +then the initial unnamed or +.Em default +section is searched too. +.Pp +The options available are described in detail below. +.Bl -tag -width "XXXX" +.It Ar attributes +This specifies the section containing any request attributes: its format +is the same as +.Ar distinguished_name . +Typically these may contain the +.Em challengePassword +or +.Em unstructuredName +types. +They are currently ignored by +.Nm OpenSSL Ns Li 's +request signing utilities, but some CAs might want them. +.It Ar default_bits +This specifies the default key size in bits. +If not specified, 512 is used. +It is used if the +.Fl new +option is used. +It can be overridden by using the +.Fl newkey +option. +.It Ar default_keyfile +This is the default file to write a private key to. +If not specified, the key is written to standard output. +This can be overridden by the +.Fl keyout +option. +.It Ar default_md +This option specifies the digest algorithm to use. +Possible values include +.Ar md5 +and +.Ar sha1 . +If not present, MD5 is used. +This option can be overridden on the command line. +.It Ar distinguished_name +This specifies the section containing the distinguished name fields to +prompt for when generating a certificate or certificate request. +The format is described in the next section. +.It Ar encrypt_key +If this is set to +.Em no +and a private key is generated, it is +.Em not +encrypted. +This is equivalent to the +.Fl nodes +command line option. +For compatibility, +.Ar encrypt_rsa_key +is an equivalent option. +.It Ar input_password | output_password +The passwords for the input private key file +.Pq if present +and the output private key file +.Pq if one will be created . +The command line options +.Fl passin +and +.Fl passout +override the configuration file values. +.It Ar 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 Ar 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 Ar prompt +If set to the value +.Em no , +this disables prompting of certificate fields +and just takes values from the config file directly. +It also changes the expected format of the +.Em distinguished_name +and +.Em attributes +sections. +.It Ar req_extensions +This specifies the configuration file section containing a list of +extensions to add to the certificate request. +It can be overridden by the +.Fl reqexts +command line switch. +.It Ar string_mask +This option limits 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 Ar utf8only +.Em UTF8String. +This is the default, as recommended by PKIX in RFC 2459. +.It Ar default +.Em PrintableString , IA5String , T61String , BMPString , UTF8String . +.It Ar pkix +.Em PrintableString , IA5String , BMPString , UTF8String . +This was inspired by the PKIX recommendation in RFC 2459 for certificates +generated before 2004, but differs by also permitting +.Em IA5String . +.It Ar nombstr +.Em PrintableString , IA5String , T61String , UniversalString . +This was a workaround for some ancient software that had problems +with the variable-sized +.Em BMPString +and +.Em UTF8String +types. +.It Cm MASK : Ns Ar number +This is 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 Ar utf8 +If set to the value +.Em yes , +then field values are interpreted as UTF8 strings; +by default they are interpreted as ASCII. +This means that the field values, whether prompted from a terminal or +obtained from a configuration file, must be valid UTF8 strings. +.It Ar x509_extensions +This specifies 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 +.Sh REQ DISTINGUISHED NAME AND ATTRIBUTE SECTION FORMAT +There are two separate formats for the distinguished name and attribute +sections. +If the +.Fl prompt +option is set to +.Em no , +then these sections just consist of field names and values: for example, +.Bd -unfilled -offset indent +CN=My Name +OU=My Organization +emailAddress=someone@somewhere.org +.Ed +.Pp +This allows external programs +.Pq e.g. GUI based +to generate a template file with all the field names and values +and just pass it to +.Nm req . +An example of this kind of configuration file is contained in the +.Sx REQ EXAMPLES +section. +.Pp +Alternatively if the +.Fl prompt +option is absent or not set to +.Em no , +then the file contains field prompting information. +It consists of lines 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 +.Em commonName +.Pq 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 +.Em fieldName_min +and +.Em fieldName_max +limits: +there may be additional restrictions based on the field being used +(for example +.Em countryName +can only ever be two characters long and must fit in a +.Em PrintableString ) . +.Pp +Some fields (such as +.Em 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 +.Em fieldName +contains some characters followed by a full stop, they will be ignored. +So, for example, a second +.Em 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 +.Em commonName , countryName , localityName , organizationName , +.Em organizationUnitName , stateOrProvinceName . +Additionally, +.Em emailAddress +is included as well as +.Em name , surname , givenName initials +and +.Em dnQualifier . +.Pp +Additional object identifiers can be defined with the +.Ar oid_file +or +.Ar oid_section +options in the configuration file. +Any additional fields will be treated as though they were a +.Em DirectoryString . +.Sh REQ EXAMPLES +Examine and verify a certificate request: +.Pp +.Dl $ openssl req -in req.pem -text -verify -noout +.Pp +Create a private key and then generate a certificate request from it: +.Bd -literal -offset indent +$ openssl genrsa -out key.pem 2048 +$ openssl req -new -key key.pem -out req.pem +.Ed +.Pp +The same but just using req: +.Pp +.Dl $ openssl req -newkey rsa:2048 -keyout key.pem -out req.pem +.Pp +Generate a self-signed root certificate: +.Pp +.Dl "$ openssl req -x509 -newkey rsa:2048 -keyout key.pem -out req.pem" +.Pp +Example of a file pointed to by the +.Ar oid_file +option: +.Bd -unfilled -offset indent +1.2.3.4 shortName A longer Name +1.2.3.6 otherName Other longer Name +.Ed +.Pp +Example of a section pointed to by +.Ar oid_section +making use of variable expansion: +.Bd -unfilled -offset indent +testoid1=1.2.3.5 +testoid2=${testoid1}.6 +.Ed +.Pp +Sample configuration file prompting for field values: +.Bd -literal +\& [ req ] +\& default_bits = 1024 +\& default_keyfile = privkey.pem +\& distinguished_name = req_distinguished_name +\& attributes = req_attributes +\& x509_extensions = v3_ca + +\& dirstring_type = nobmp + +\& [ req_distinguished_name ] +\& countryName = Country Name (2 letter code) +\& countryName_default = AU +\& countryName_min = 2 +\& countryName_max = 2 + +\& localityName = Locality Name (eg, city) + +\& organizationalUnitName = Organizational Unit Name (eg, section) + +\& commonName = Common Name (eg, YOUR name) +\& commonName_max = 64 + +\& emailAddress = Email Address +\& emailAddress_max = 40 + +\& [ req_attributes ] +\& challengePassword = A challenge password +\& challengePassword_min = 4 +\& challengePassword_max = 20 + +\& [ v3_ca ] + +\& subjectKeyIdentifier=hash +\& authorityKeyIdentifier=keyid:always,issuer:always +\& basicConstraints = CA:true +.Ed +.Pp +Sample configuration containing all field values: +.Bd -literal + +\& [ req ] +\& default_bits = 1024 +\& default_keyfile = keyfile.pem +\& distinguished_name = req_distinguished_name +\& attributes = req_attributes +\& prompt = no +\& output_password = mypass + +\& [ req_distinguished_name ] +\& C = GB +\& ST = Test State or Province +\& L = Test Locality +\& O = Organization Name +\& OU = Organizational Unit Name +\& CN = Common Name +\& emailAddress = test@email.address + +\& [ req_attributes ] +\& challengePassword = A challenge password +.Ed +.Sh REQ NOTES +The header and footer lines in the PEM format are normally: +.Bd -unfilled -offset indent +-----BEGIN CERTIFICATE REQUEST----- +-----END CERTIFICATE REQUEST----- +.Ed +.Pp +Some software +.Pq some versions of Netscape certificate server +instead needs: +.Bd -unfilled -offset indent +-----BEGIN NEW CERTIFICATE REQUEST----- +-----END NEW CERTIFICATE REQUEST----- +.Ed +.Pp +which is produced with the +.Fl newhdr +option but is otherwise compatible. +Either form is accepted transparently on input. +.Pp +The certificate requests generated by Xenroll with MSIE have extensions added. +It includes the +.Em keyUsage +extension which determines the type of key +.Pq signature only or general purpose +and any additional OIDs entered by the script in an +.Em extendedKeyUsage +extension. +.Sh REQ DIAGNOSTICS +The following messages are frequently asked about: +.Bd -unfilled -offset indent +Using configuration from /some/path/openssl.cnf +Unable to load config info +.Ed +.Pp +This is followed some time later by... +.Bd -unfilled -offset indent +unable to find 'distinguished_name' in config +problems making Certificate Request +.Ed +.Pp +The first error message is the clue: it can't find the configuration +file! +Certain operations +.Pq like examining a certificate request +don't need a configuration file so its use isn't enforced. +Generation of certificates or requests, however, do need a configuration file. +This could be regarded as a bug. +.Pp +Another puzzling message is this: +.Bd -unfilled -offset indent +Attributes: + a0:00 +.Ed +.Pp +This is displayed when no attributes are present and the request includes +the correct empty SET OF structure +.Pq the DER encoding of which is 0xa0 0x00 . +If you just see: +.Pp +.D1 Attributes: +.Pp +then the SET OF is missing and the encoding is technically invalid +.Pq but it is tolerated . +See the description of the command line option +.Fl asn1-kludge +for more information. +.Sh REQ ENVIRONMENT VARIABLES +The variable +.Ev OPENSSL_CONF , +if defined, allows an alternative configuration +file location to be specified; it will be overridden by the +.Fl config +command line switch if it is present. +For compatibility reasons the +.Ev SSLEAY_CONF +environment variable serves the same purpose but its use is discouraged. +.Sh REQ BUGS +.Nm OpenSSL Ns Li 's +handling of T61Strings +.Pq aka TeletexStrings +is broken: it effectively treats them as ISO 8859-1 +.Pq Latin 1 ; +Netscape and MSIE have similar behaviour. +This can cause problems if you need characters that aren't available in +.Em PrintableStrings +and you don't want to or can't use +.Em BMPStrings . +.Pp +As a consequence of the T61String handling, the only correct way to represent +accented characters in +.Nm OpenSSL +is to use a +.Em BMPString : +unfortunately Netscape currently chokes on these. +If you have to use accented characters with Netscape +and MSIE then you currently need to use the invalid T61String form. +.Pp +The current prompting is not very friendly. +It doesn't allow you to confirm what you've just entered. +Other things, like extensions in certificate requests, are +statically defined in the configuration file. +Some of these, like an email address in +.Em subjectAltName , +should be input by the user. +.\" +.\" RSA +.\" +.Sh RSA +.nr nS 1 +.Nm "openssl rsa" +.Bk -words +.Oo +.Fl aes128 | aes192 | aes256 | +.Fl des | des3 +.Oc +.Op Fl check +.Op Fl engine Ar id +.Op Fl in Ar file +.Op Fl inform Ar DER | NET | PEM +.Op Fl modulus +.Op Fl noout +.Op Fl out Ar file +.Op Fl outform Ar 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 +.Ek +.Pp +The +.Nm rsa +command processes RSA 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 +utility. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Xo +.Fl aes128 | aes192 | aes256 | +.Fl des | des3 +.Xc +These options 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 +This option checks the consistency of an RSA private key. +.It Fl engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm rsa +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.It Fl in Ar file +This specifies the input +.Ar file +to read a key from, or standard input if this +option is not specified. +If the key is encrypted, a pass phrase will be prompted for. +.It Fl inform Ar DER | NET | PEM +This specifies the input format. +The +.Ar DER +argument +uses an ASN1 DER-encoded form compatible with the PKCS#1 +RSAPrivateKey or SubjectPublicKeyInfo format. +The +.Ar PEM +form is the default format: it consists of the DER format base64-encoded with +additional header and footer lines. +On input PKCS#8 format private keys are also accepted. +The +.Ar NET +form is a format described in the +.Sx RSA NOTES +section. +.It Fl noout +This option prevents output of the encoded version of the key. +.It Fl modulus +This option prints out the value of the modulus of the key. +.It Fl out Ar file +This specifies the output +.Ar file +to write a key to, or standard output if this option is not specified. +If any encryption options are set, a pass phrase will be prompted for. +The output filename should +.Em not +be the same as the input filename. +.It Fl outform Ar DER | NET | PEM +This specifies the output format; the options have the same meaning as the +.Fl inform +option. +.It Fl passin Ar arg +The key password source. +For more information about the format of +.Ar arg , +see the +.Sx PASS PHRASE ARGUMENTS +section above. +.It Fl passout Ar arg +The output file password source. +For more information about the format of +.Ar arg , +see the +.Sx PASS PHRASE ARGUMENTS +section above. +.It Fl pubin +By default, a private key is read from the input file; with this +option a public key is read instead. +.It Fl pubout +By default, a private key is output; +with this option a public key will be output instead. +This option is automatically set if the input is a public key. +.It Fl sgckey +Use the modified +.Em NET +algorithm used with some versions of Microsoft IIS and SGC keys. +.It Fl text +Prints out the various public or private key components in +plain text, in addition to the encoded version. +.El +.Sh RSA NOTES +The PEM private key format uses the header and footer lines: +.Bd -unfilled -offset indent +-----BEGIN RSA PRIVATE KEY----- +-----END RSA PRIVATE KEY----- +.Ed +.Pp +The PEM public key format uses the header and footer lines: +.Bd -unfilled -offset indent +-----BEGIN PUBLIC KEY----- +-----END PUBLIC KEY----- +.Ed +.Pp +The +.Em NET +form is a format compatible with older Netscape servers +and Microsoft IIS .key files; this uses unsalted RC4 for its encryption. +It is not very secure and so should only be used when necessary. +.Pp +Some newer version of IIS have additional data in the exported .key files. +To use these with the +.Nm rsa +utility, view the file with a binary editor +and look for the string +.Qq private-key , +then trace back to the byte sequence 0x30, 0x82 +.Pq this is an ASN1 SEQUENCE . +Copy all the data from this point onwards to another file and use that as +the input to the +.Nm rsa +utility with the +.Fl inform Ar NET +option. +If there is an error after entering the password, try the +.Fl sgckey +option. +.Sh RSA EXAMPLES +To remove the pass phrase on an RSA private key: +.Pp +.Dl $ openssl rsa -in key.pem -out keyout.pem +.Pp +To encrypt a private key using triple DES: +.Pp +.Dl $ openssl rsa -in key.pem -des3 -out keyout.pem +.Pp +To convert a private key from PEM to DER format: +.Pp +.Dl $ openssl rsa -in key.pem -outform DER -out keyout.der +.Pp +To print out the components of a private key to standard output: +.Pp +.Dl $ openssl rsa -in key.pem -text -noout +.Pp +To just output the public part of a private key: +.Pp +.Dl $ openssl rsa -in key.pem -pubout -out pubkey.pem +.Sh RSA BUGS +The command line password arguments don't currently work with +.Em NET +format. +.Pp +There should be an option that automatically handles .key files, +without having to manually edit them. +.\" +.\" RSAUTL +.\" +.Sh RSAUTL +.nr nS 1 +.Nm "openssl rsautl" +.Bk -words +.Op Fl asn1parse +.Op Fl certin +.Op Fl decrypt +.Op Fl encrypt +.Op Fl engine Ar id +.Op Fl hexdump +.Op Fl in Ar file +.Op Fl inkey Ar file +.Op Fl keyform Ar DER | PEM +.Op Fl oaep | pkcs | raw | ssl +.Op Fl out Ar file +.Op Fl pubin +.Op Fl sign +.Op Fl verify +.Ek +.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 engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm rsautl +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.It Fl hexdump +Hex dump the output data. +.It Fl in Ar file +This specifies the input +.Ar file +to read data from, or standard input +if this option is not specified. +.It Fl inkey Ar file +The input key file, by default it should be an RSA private key. +.It Fl keyform Ar DER | PEM +Private ket format. +Default is +.Ar PEM . +.It Fl oaep | pkcs | raw | ssl +The padding to use: +PKCS#1 OAEP, PKCS#1 v1.5 +.Pq the default , +or no padding, respectively. +For signatures, only +.Fl pkcs +and +.Fl raw +can be used. +.It Fl out Ar file +Specifies the output +.Ar file +to write to, or standard output by +default. +.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 RSAUTL NOTES +.Nm rsautl , +because it uses the RSA algorithm directly, can only be +used to sign or verify small pieces of data. +.Sh RSAUTL EXAMPLES +Sign some data using a private key: +.Pp +.Dl "$ openssl rsautl -sign -in file -inkey key.pem -out sig" +.Pp +Recover the signed data: +.Pp +.Dl $ openssl rsautl -verify -in sig -inkey key.pem +.Pp +Examine the raw signed data: +.Pp +.Li "\ \&$ openssl rsautl -verify -in file -inkey key.pem -raw -hexdump" +.Bd -unfilled +\& 0000 - 00 01 ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ +\& 0010 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ +\& 0020 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ +\& 0030 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ +\& 0040 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ +\& 0050 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ +\& 0060 - ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff ................ +\& 0070 - ff ff ff ff 00 68 65 6c-6c 6f 20 77 6f 72 6c 64 .....hello world +.Ed +.Pp +The PKCS#1 block formatting is evident from this. +If this was done using encrypt and decrypt, the block would have been of type 2 +.Pq the second byte +and random padding data visible instead of the 0xff bytes. +.Pp +It is possible to analyse the signature of certificates using this +utility in conjunction with +.Nm asn1parse . +Consider the self-signed example in +.Pa certs/pca-cert.pem : +running +.Nm asn1parse +as follows yields: +.Pp +.Li "\ \&$ openssl asn1parse -in pca-cert.pem" +.Bd -unfilled +\& 0:d=0 hl=4 l= 742 cons: SEQUENCE +\& 4:d=1 hl=4 l= 591 cons: SEQUENCE +\& 8:d=2 hl=2 l= 3 cons: cont [ 0 ] +\& 10:d=3 hl=2 l= 1 prim: INTEGER :02 +\& 13:d=2 hl=2 l= 1 prim: INTEGER :00 +\& 16:d=2 hl=2 l= 13 cons: SEQUENCE +\& 18:d=3 hl=2 l= 9 prim: OBJECT :md5WithRSAEncryption +\& 29:d=3 hl=2 l= 0 prim: NULL +\& 31:d=2 hl=2 l= 92 cons: SEQUENCE +\& 33:d=3 hl=2 l= 11 cons: SET +\& 35:d=4 hl=2 l= 9 cons: SEQUENCE +\& 37:d=5 hl=2 l= 3 prim: OBJECT :countryName +\& 42:d=5 hl=2 l= 2 prim: PRINTABLESTRING :AU +\& .... +\& 599:d=1 hl=2 l= 13 cons: SEQUENCE +\& 601:d=2 hl=2 l= 9 prim: OBJECT :md5WithRSAEncryption +\& 612:d=2 hl=2 l= 0 prim: NULL +\& 614:d=1 hl=3 l= 129 prim: BIT STRING +.Ed +.Pp +The final BIT STRING contains the actual signature. +It can be extracted with: +.Pp +.Dl "$ openssl asn1parse -in pca-cert.pem -out sig -noout -strparse 614" +.Pp +The certificate public key can be extracted with: +.Pp +.Dl $ openssl x509 -in test/testx509.pem -pubkey -noout \*(Gtpubkey.pem +.Pp +The signature can be analysed with: +.Pp +.Li "\ \&$ openssl rsautl -in sig -verify -asn1parse -inkey pubkey.pem -pubin" +.Bd -unfilled +\& 0:d=0 hl=2 l= 32 cons: SEQUENCE +\& 2:d=1 hl=2 l= 12 cons: SEQUENCE +\& 4:d=2 hl=2 l= 8 prim: OBJECT :md5 +\& 14:d=2 hl=2 l= 0 prim: NULL +\& 16:d=1 hl=2 l= 16 prim: OCTET STRING +\& 0000 - f3 46 9e aa 1a 4a 73 c9-37 ea 93 00 48 25 08 b5 .F...Js.7...H%.. +.Ed +.Pp +This is the parsed version of an ASN1 +.Em DigestInfo +structure. +It can be seen that the digest used was MD5. +The actual part of the certificate that was signed can be extracted with: +.Pp +.Dl "$ openssl asn1parse -in pca-cert.pem -out tbs -noout -strparse 4" +.Pp +and its digest computed with: +.Pp +.Dl $ openssl md5 -c tbs +.D1 MD5(tbs)= f3:46:9e:aa:1a:4a:73:c9:37:ea:93:00:48:25:08:b5 +.Pp +which it can be seen agrees with the recovered value above. +.\" +.\" S_CLIENT +.\" +.Sh S_CLIENT +.nr nS 1 +.Nm "openssl s_client" +.Bk -words +.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 +.Oo +.Fl connect Ar host : Ns Ar port | +.Ar host Ns / Ns Ar port +.Oc +.Op Fl crl_check +.Op Fl crl_check_all +.Op Fl crlf +.Op Fl debug +.Op Fl engine Ar id +.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_ssl3 +.Op Fl no_ticket +.Op Fl no_tls1 +.Op Fl pause +.Op Fl policy_check +.Op Fl prexit +.Op Fl psk Ar key +.Op Fl psk_identity Ar identity +.Op Fl quiet +.Op Fl reconnect +.Op Fl showcerts +.Op Fl ssl3 +.Op Fl starttls Ar protocol +.Op Fl state +.Op Fl tls1 +.Op Fl tlsextdebug +.Op Fl verify Ar depth +.Op Fl x509_strict +.Ek +.nr nS 0 +.Pp +The +.Nm s_client +command implements a generic SSL/TLS client which connects +to a remote host using SSL/TLS. +It is a +.Em very +useful diagnostic tool for SSL servers. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl 4 +Specify that +.Nm s_client +should attempt connections using IPv4 only. +.It Fl 6 +Specify that +.Nm s_client +should attempt connections using IPv6 only. +.It Fl bugs +There are several known bugs in SSL and TLS implementations. +Adding this option enables various workarounds. +.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 +This allows the cipher list sent by the client to be modified. +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 +.Sx CIPHERS +section above for more information. +.It Xo +.Fl connect Ar host : Ns Ar port | +.Ar host Ns / Ns Ar port +.Xc +This specifies the +.Ar host +and optional +.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. +This form is useful for numeric IPv6 addresses. +.It Fl crlf +This option translates 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 engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm s_client +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.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 +Turns on non-blocking I/O. +.It Fl nbio_test +Tests non-blocking I/O. +.It Xo +.Fl no_ssl3 | no_tls1 | +.Fl ssl3 | tls1 +.Xc +These options disable the use of certain SSL or TLS protocols. +By default, the initial handshake uses a method which should be compatible +with all servers and permit them to use SSL v3 or TLS as appropriate. +.Pp +Unfortunately there are a lot of ancient and broken servers in use which +cannot handle this technique and will fail to connect. +Some servers only work if TLS is turned off with the +.Fl no_tls +option. +.It Fl no_ticket +Disable RFC 4507 session ticket support. +.It Fl pause +Pauses 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. +.Sy Note : +the output produced by this option is not always accurate because a +connection might never have been established. +.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 identity +.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 +Reconnects 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 showcerts +Display the whole server certificate chain: normally only the server +certificate itself is displayed. +.It Fl starttls Ar protocol +Send the protocol-specific message(s) 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 +Prints out the SSL session states. +.It Fl tlsextdebug +Print out a hex dump of any TLS extensions received from the server. +.It Fl verify Ar depth +The verify +.Ar depth +to use. +This specifies the maximum length of the +server certificate chain and turns on server certificate verification. +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. +.El +.Sh S_CLIENT CONNECTED COMMANDS +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 +.Em R ; +if the line begins with a +.Em Q +or if end of file is reached, the connection will be closed down. +.Sh S_CLIENT NOTES +.Nm s_client +can be used to debug SSL servers. +To connect to an SSL HTTP server the command: +.Pp +.Dl $ openssl s_client -connect servername:443 +.Pp +would typically be used +.Pq HTTPS uses port 443 . +If the connection succeeds, an HTTP command can be given such as +.Qq GET +to retrieve a web page. +.Pp +If the handshake fails, there are several possible causes; if it is +nothing obvious like no client certificate, then the +.Fl bugs , ssl3 , tls1 , no_ssl3 , +and +.Fl no_tls1 +options can be tried in case it is a buggy server. +In particular these options should be tried +.Em before +submitting a bug report to an +.Nm OpenSSL +mailing list. +.Pp +A frequent problem when attempting to get client certificates working +is that a web client complains it has no certificates or gives an empty +list to choose from. +This is normally because the server is not sending the client's certificate +authority in its +.Qq acceptable CA list +when it requests a certificate. +By using +.Nm s_client +the CA list can be viewed and checked. +However some servers only request client authentication +after a specific URL is requested. +To obtain the list in this case it is necessary to use the +.Fl prexit +option and send an HTTP request for an appropriate page. +.Pp +If a certificate is specified on the command line using the +.Fl cert +option, it will not be used unless the server specifically requests +a client certificate. +Therefore merely including a client certificate +on the command line is no guarantee that the certificate works. +.Pp +If there are problems verifying a server certificate, the +.Fl showcerts +option can be used to show the whole chain. +.Pp +Compression methods are only supported for +.Fl tls1 . +.Sh S_CLIENT BUGS +Because this program has a lot of options and also because some of +the techniques used are rather old, the C source of +.Nm s_client +is rather hard to read and not a model of how things should be done. +A typical SSL client program would be much simpler. +.Pp +The +.Fl verify +option should really exit if the server verification fails. +.Pp +The +.Fl prexit +option is a bit of a hack. +We should really report information whenever a session is renegotiated. +.\" +.\" S_SERVER +.\" +.Sh S_SERVER +.nr nS 1 +.Nm "openssl s_server" +.Bk -words +.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 engine Ar id +.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_ssl3 +.Op Fl no_tls1 +.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 ssl3 +.Op Fl state +.Op Fl tls1 +.Op Fl Verify Ar depth +.Op Fl verify Ar depth +.Op Fl WWW +.Op Fl www +.Ek +.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 +The options are as follows: +.Bl -tag -width Ds +.It Fl accept Ar port +The TCP +.Ar port +to listen on for connections. +If not specified, 4433 is used. +.It Fl bugs +There are several known bugs in SSL and TLS implementations. +Adding this option enables various workarounds. +.It Fl CAfile Ar file +A 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 +.Pq DSA +key. +If not specified, the file +.Pa server.pem +will be used. +.It Fl cipher Ar cipherlist +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 +.Sx CIPHERS +section for more information. +.It Fl context Ar id +Sets the SSL context ID. +It can be given any string value. +If this option is not present, a default value will be used. +.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. +With the +.Fl crl_check_all +option, all CRLs of all CAs in the chain are checked. +.It Fl crlf +This option translates 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 +.Pq no additional certificate or key is used . +As noted above some cipher suites require a certificate containing a key of +a certain type. +Some cipher suites need a certificate carrying an RSA key +and some a DSS +.Pq DSA +key. +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 engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm s_server +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.It Fl hack +This option enables a further workaround for some early Netscape +SSL code +.Pq \&? . +.It Fl HTTP +Emulates a simple web server. +Pages will be 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 +.Pq e.g. proxies +that wish to deal with multiple servers, when each of which might be +generating a unique range of session IDs +.Pq e.g. with a certain prefix . +.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 +Turns on non-blocking I/O. +.It Fl nbio_test +Tests non-blocking I/O. +.It Fl no_dhe +If this option is set, no DH parameters will be loaded, effectively +disabling the ephemeral DH cipher suites. +.It Xo +.Fl no_ssl3 | no_tls1 | +.Fl ssl3 | tls1 +.Xc +These options disable the use of certain SSL or TLS protocols. +By default, the initial handshake uses a method which should be compatible +with all servers and permit them to use SSL v3 or TLS as appropriate. +.It Fl no_tmp_rsa +Certain export cipher suites sometimes use a temporary RSA key; this option +disables temporary RSA key generation. +.It Fl nocert +If this option is set, no certificate is used. +This restricts the cipher suites available to the anonymous ones +.Pq 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 +Prints out the SSL session states. +.It Fl WWW +Emulates a simple web server. +Pages will be 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 +Sends a status message back to the client when it connects. +This includes lots of 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 +The verify +.Ar depth +to use. +This specifies the maximum length of the client certificate chain +and makes the server request a certificate from the client. +With the +.Fl Verify +option, the client must supply a certificate or an error occurs. +With the +.Fl verify +option, a certificate is requested but the client does not have to send one. +.El +.Sh S_SERVER CONNECTED COMMANDS +If a connection request is established with an SSL client and neither the +.Fl www +nor the +.Fl WWW +option has been used, then normally any data received +from the client is displayed and any key presses will be sent to the client. +.Pp +Certain single letter commands are also recognized which perform special +operations: these are listed below. +.Bl -tag -width "XXXX" +.It Ar P +Send some plain text down the underlying TCP connection: this should +cause the client to disconnect due to a protocol violation. +.It Ar Q +End the current SSL connection and exit. +.It Ar q +End the current SSL connection, but still accept new connections. +.It Ar R +Renegotiate the SSL session and request a client certificate. +.It Ar r +Renegotiate the SSL session. +.It Ar S +Print out some session cache status information. +.El +.Sh S_SERVER NOTES +.Nm s_server +can be used to debug SSL clients. +To accept connections from a web browser the command: +.Pp +.Dl $ openssl s_server -accept 443 -www +.Pp +can be used, for example. +.Pp +Most web browsers +.Pq in particular Netscape and MSIE +only support RSA cipher suites, so they cannot connect to servers +which don't use a certificate carrying an RSA key or a version of +.Nm OpenSSL +with RSA disabled. +.Pp +Although specifying an empty list of CAs when requesting a client certificate +is strictly speaking a protocol violation, some SSL +clients interpret this to mean any CA is acceptable. +This is useful for debugging purposes. +.Pp +The session parameters can printed out using the +.Nm sess_id +program. +.Sh S_SERVER BUGS +Because this program has a lot of options and also because some of +the techniques used are rather old, the C source of +.Nm s_server +is rather hard to read and not a model of how things should be done. +A typical SSL server program would be much simpler. +.Pp +The output of common ciphers is wrong: it just gives the list of ciphers that +.Nm OpenSSL +recognizes and the client supports. +.Pp +There should be a way for the +.Nm s_server +program to print out details of any +unknown cipher suites a client says it supports. +.\" +.\" S_TIME +.\" +.Sh S_TIME +.nr nS 1 +.Nm "openssl s_time" +.Bk -words +.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 Ar port +.Op Fl key Ar keyfile +.Op Fl nbio +.Op Fl new +.Op Fl reuse +.Op Fl ssl3 +.Op Fl time Ar seconds +.Op Fl verify Ar depth +.Op Fl www Ar page +.Ek +.nr nS 0 +.Pp +The +.Nm s_client +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 +There are several known bugs in SSL and TLS implementations. +Adding this option enables various workarounds. +.It Fl CAfile Ar file +A 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. +The file is in PEM format. +.It Fl cipher Ar cipherlist +This allows the cipher list sent by the client to be modified. +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 Ar port +This specifies the host and optional port to connect to. +.It Fl key Ar keyfile +The private key to use. +If not specified, the certificate file will be used. +The file is in PEM format. +.It Fl nbio +Turns on non-blocking I/O. +.It Fl new +Performs 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 reuse +Performs the timing test using the same session ID; +this can be used as a test that session caching is working. +If neither +.Fl new +nor +.Fl reuse +are specified, +they are both on by default and executed in sequence. +.It Fl ssl3 +This option disables the use of certain SSL or TLS protocols. +By default, the initial handshake uses a method +which should be compatible with all servers and permit them to use +SSL v3 or TLS as appropriate. +The timing program is not as rich in options to turn protocols on and off as +the +.Nm s_client +program and may not connect to all servers. +.Pp +Unfortunately there are a lot of ancient and broken servers in use which +cannot handle this technique and will fail to connect. +Some servers only work if TLS is turned off with the +.Fl ssl3 +option. +.It Fl time Ar seconds +Specifies how long +.Pq in seconds +.Nm s_time +should establish connections and +optionally transfer payload data from a server. +The default is 30 seconds. +Server and client performance and the link speed +determine how many connections +.Nm s_time +can establish. +.It Fl verify Ar depth +The verify depth to use. +This specifies the maximum length of the server certificate chain +and turns on server certificate verification. +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 +This specifies 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 S_TIME NOTES +.Nm s_client +can be used to measure the performance of an SSL connection. +To connect to an SSL HTTP server and get the default page the command +.Bd -literal -offset indent +$ openssl s_time -connect servername:443 -www / -CApath yourdir \e + -CAfile yourfile.pem -cipher commoncipher [-ssl3] +.Ed +.Pp +would typically be used +.Pq HTTPS uses port 443 . +.Dq commoncipher +is a cipher to which both client and server can agree; +see the +.Nm ciphers +command for details. +.Pp +If the handshake fails, there are several possible causes: +if it is nothing obvious like no client certificate, the +.Fl bugs +and +.Fl ssl3 +options can be tried in case it is a buggy server. +In particular you should play with these options +.Em before +submitting a bug report to an OpenSSL mailing list. +.Pp +A frequent problem when attempting to get client certificates working +is that a web client complains it has no certificates or gives an empty +list to choose from. +This is normally because the server is not sending +the clients certificate authority in its +.Qq acceptable CA list +when it requests a certificate. +By using +.Nm s_client , +the CA list can be viewed and checked. +However some servers only request client authentication +after a specific URL is requested. +To obtain the list in this case, it is necessary to use the +.Fl prexit +option of +.Nm s_client +and send an HTTP request for an appropriate page. +.Pp +If a certificate is specified on the command line using the +.Fl cert +option, +it will not be used unless the server specifically requests +a client certificate. +Therefore merely including a client certificate +on the command line is no guarantee that the certificate works. +.Sh S_TIME BUGS +Because this program does not have all the options of the +.Nm s_client +program to turn protocols on and off, +you may not be able to measure the performance +of all protocols with all servers. +.Pp +The +.Fl verify +option should really exit if the server verification fails. +.\" +.\" SESS_ID +.\" +.Sh SESS_ID +.nr nS 1 +.Nm "openssl sess_id" +.Bk -words +.Op Fl cert +.Op Fl context Ar ID +.Op Fl in Ar file +.Op Fl inform Ar DER | PEM +.Op Fl noout +.Op Fl out Ar file +.Op Fl outform Ar DER | PEM +.Op Fl text +.Ek +.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 +.Pq for example the SSL session master key +in human readable format. +Since this is a diagnostic tool that needs some knowledge of the SSL +protocol to use properly, most users will not need to use it. +.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 +This option can set the session ID so the output session information uses the +supplied +.Ar ID . +The +.Ar ID +can be any string of characters. +This option won't normally be used. +.It Fl in Ar file +This specifies the input +.Ar file +to read session information from, or standard input by default. +.It Fl inform Ar DER | PEM +This specifies the input format. +The +.Ar DER +argument uses an ASN1 DER-encoded +format containing session details. +The precise format can vary from one version to the next. +The +.Ar PEM +form is the default format: it consists of the DER +format base64-encoded with additional header and footer lines. +.It Fl noout +This option prevents output of the encoded version of the session. +.It Fl out Ar file +This specifies the output +.Ar file +to write session information to, or standard +output if this option is not specified. +.It Fl outform Ar DER | PEM +This specifies the output format; the options have the same meaning as the +.Fl inform +option. +.It Fl text +Prints out the various public or private key components in +plain text in addition to the encoded version. +.El +.Sh SESS_ID OUTPUT +Typical output: +.Bd -literal +SSL-Session: + Protocol : TLSv1 + Cipher : 0016 + Session-ID: 871E62626C554CE95488823752CBD5F3673A3EF3DCE9C67BD916C809914B40ED + Session-ID-ctx: 01000000 + Master-Key: A7CEFC571974BE02CAC305269DC59F76EA9F0B180CB6642697A68251F2D2BB57E51DBBB4C7885573192AE9AEE220FACD + Key-Arg : None + Start Time: 948459261 + Timeout : 300 (sec) + Verify return code 0 (ok) +.Ed +.Pp +These are described below in more detail. +.Pp +.Bl -tag -width "Verify return code " -compact +.It Ar Protocol +This is the protocol in use: TLSv1 or SSLv3. +.It Ar Cipher +The cipher used is the actual raw SSL or TLS cipher code; +see the SSL or TLS specifications for more information. +.It Ar Session-ID +The SSL session ID in hex format. +.It Ar Session-ID-ctx +The session ID context in hex format. +.It Ar Master-Key +This is the SSL session master key. +.It Ar Key-Arg +The key argument; this is only used in SSL v2. +.It Ar Start Time +This is the session start time, represented as an integer in standard +.Ux +format. +.It Ar Timeout +The timeout in seconds. +.It Ar Verify return code +This is the return code when an SSL client certificate is verified. +.El +.Sh SESS_ID NOTES +The PEM-encoded session format uses the header and footer lines: +.Bd -unfilled -offset indent +-----BEGIN SSL SESSION PARAMETERS----- +-----END SSL SESSION PARAMETERS----- +.Ed +.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 SESS_ID BUGS +The cipher and start time should be printed out in human readable form. +.\" +.\" SMIME +.\" +.Sh SMIME +.nr nS 1 +.Nm "openssl smime" +.Bk -words +.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 engine Ar id +.Op Fl extended_crl +.Op Fl from Ar addr +.Op Fl ignore_critical +.Op Fl in Ar file +.Op Fl indef +.Op Fl inform Ar DER | PEM | SMIME +.Op Fl inkey Ar file +.Op Fl issuer_checks +.Op Fl keyform Ar ENGINE | 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 Ar 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 ... +.Ek +.nr nS 0 +.Pp +The +.Nm smime +command handles +.Em S/MIME +mail. +It can encrypt, decrypt, sign, and verify +.Em S/MIME +messages. +.Pp +There are six operation options that set the type of operation to be performed. +The meaning of the other options varies according to the operation type. +.Pp +The six operation options are as follows: +.Bl -tag -width "XXXX" +.It Fl decrypt +Decrypt mail using the supplied certificate and private key. +Expects an encrypted mail message in +.Em MIME +format for the input file. +The decrypted mail is written to the output file. +.It Fl encrypt +Encrypt mail for the given recipient certificates. +Input file is the message to be encrypted. +The output file is the encrypted mail in +.Em MIME +format. +.It Fl pk7out +Takes an input message and writes 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. +Input file is the message to be signed. +The signed message in +.Em MIME +format is written to the output file. +.It Fl verify +Verify signed mail. +Expects a signed mail message on input and outputs the signed data. +Both clear text and opaque signing is supported. +.El +.Pp +The reamaining 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 +.Pq 56 bits , +triple DES +.Pq 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 is effectively using CR and LF as end of line \- +as required by the +.Em S/MIME +specification. +When this option is present no translation occurs. +This is useful when handling binary data which may not be in +.Em 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 +This specifies a file containing the detached content. +This is only useful with the +.Fl verify +command. +This is 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 +.Em S/MIME +and it uses the multipart/signed +.Em MIME +content type. +.It Fl engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm smime +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.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 +.Em S/MIME +mail clients check that the signer's certificate email +address matches the From: address. +.It Fl in Ar file +The input message to be encrypted or signed or the +.Em MIME +message to +be decrypted or verified. +.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 Ar DER | PEM | SMIME +This specifies the input format for the PKCS#7 structure. +The default is +.Em SMIME , +which reads an +.Em S/MIME +format message. +.Ar PEM +and +.Ar DER +format change this to expect PEM and DER format PKCS#7 structures +instead. +This currently only affects the input format of the PKCS#7 +structure; if no PKCS#7 structure is being input (for example with +.Fl encrypt +or +.Fl sign ) , +this option has no effect. +.It Fl inkey Ar file +The private key to use when signing or decrypting. +This 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 Ar ENGINE | 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 +Normally, when a message is signed a set of attributes are included which +include the signing time and supported symmetric algorithms. +With this option they are not included. +.It Fl nocerts +When signing a message, the signer's certificate is normally included; +with this option it is excluded. +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 +.Em S/MIME . +Without this option cleartext signing with the +.Em MIME +type multipart/signed is used. +.It Fl noindef +Disable streaming I/O where it would produce an encoding of indefinite length. +This option currently has no effect. +In future streaming will be enabled by default on all relevant operations +and this option will disable it. +.It Fl nointern +When verifying a message, normally certificates +.Pq if any +included in the message are searched for the signing certificate. +With this option, only the certificates specified in the +.Fl certfile +option are used. +The supplied certificates can still be used as untrusted CAs however. +.It Fl nosigs +Don't 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 message text that has been decrypted or verified, or the output +.Em MIME +format message that has been signed or verified. +.It Fl outform Ar DER | PEM | SMIME +This specifies the output format for the PKCS#7 structure. +The default is +.Em SMIME , +which writes an +.Em S/MIME +format message. +.Ar PEM +and +.Ar DER +format 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. +For more information about the format of +.Ar arg , +see the +.Sx PASS PHRASE ARGUMENTS +section above. +.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 +This option adds plain text +.Pq text/plain +.Em 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 +.Em MIME +type text/plain then an error occurs. +.El +.Sh SMIME NOTES +The +.Em 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 sendmail is one way to +achieve the correct format. +.Pp +The supplied message to be signed or encrypted must include the +necessary +.Em MIME +headers or many +.Em S/MIME +clients won't display it properly +.Pq if at all . +You can 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: +see the +.Sx SMIME EXAMPLES +section. +.Pp +This version of the program only allows one signer per message, but it +will verify multiple signers on received messages. +Some +.Em S/MIME +clients choke if a message contains multiple signers. +It is possible to sign messages +.Qq in parallel +by signing an already signed message. +.Pp +The options +.Fl encrypt +and +.Fl decrypt +reflect common usage in +.Em S/MIME +clients. +Strictly speaking these process PKCS#7 enveloped data: PKCS#7 +encrypted data is used for other purposes. +.Pp +The +.Fl resign +option uses an existing message digest when adding a new signer. +This means that attributes must be present in at least one existing +signer using the same message digest or this operation will fail. +.Pp +The +.Fl stream +and +.Fl indef +options enable experimental streaming I/O support. +As a result the encoding is BER using indefinite length constructed encoding +and no longer DER. +Streaming is supported for the +.Fl encrypt +and +.Fl sign +operations if the content is not detached. +.Pp +Streaming is always used for the +.Fl sign +operation with detached data +but since the content is no longer part of the PKCS#7 structure +the encoding remains DER. +.Sh SMIME EXIT CODES +.Bl -tag -width "XXXX" +.It Ar 0 +The operation was completely successful. +.It Ar 1 +An error occurred parsing the command options. +.It Ar 2 +One of the input files could not be read. +.It Ar 3 +An error occurred creating the PKCS#7 file or when reading the +.Em MIME +message. +.It Ar 4 +An error occurred decrypting or verifying the message. +.It Ar 5 +The message was verified correctly, but an error occurred writing out +the signer's certificates. +.El +.Sh SMIME EXAMPLES +Create a cleartext signed message: +.Bd -literal -offset indent +$ openssl smime -sign -in message.txt -text -out mail.msg \e + -signer mycert.pem +.Ed +.Pp +Create an opaque signed message: +.Bd -literal -offset indent +$ openssl smime -sign -in message.txt -text -out mail.msg \e + -nodetach -signer mycert.pem +.Ed +.Pp +Create a signed message, include some additional certificates and +read the private key from another file: +.Bd -literal -offset indent +$ openssl smime -sign -in in.txt -text -out mail.msg \e + -signer mycert.pem -inkey mykey.pem -certfile mycerts.pem +.Ed +.Pp +Create a signed message with two signers: +.Bd -literal -offset indent +openssl smime -sign -in message.txt -text -out mail.msg \e + -signer mycert.pem -signer othercert.pem +.Ed +.Pp +Send a signed message under +.Ux +directly to +.Xr sendmail 8 , +including headers: +.Bd -literal -offset indent +$ openssl smime -sign -in in.txt -text -signer mycert.pem \e + -from steve@openssl.org -to someone@somewhere \e + -subject "Signed message" | sendmail someone@somewhere +.Ed +.Pp +Verify a message and extract the signer's certificate if successful: +.Bd -literal -offset indent +$ openssl smime -verify -in mail.msg -signer user.pem \e + -out signedtext.txt +.Ed +.Pp +Send encrypted mail using triple DES: +.Bd -literal -offset indent +$ openssl smime -encrypt -in in.txt -from steve@openssl.org \e + -to someone@somewhere -subject "Encrypted message" \e + -des3 -out mail.msg user.pem +.Ed +.Pp +Sign and encrypt mail: +.Bd -literal -offset indent +$ openssl smime -sign -in ml.txt -signer my.pem -text | \e + openssl smime -encrypt -out mail.msg \e + -from steve@openssl.org -to someone@somewhere \e + -subject "Signed and Encrypted message" -des3 user.pem +.Ed +.Pp +.Sy Note : +The encryption command does not include the +.Fl text +option because the message being encrypted already has +.Em MIME +headers. +.Pp +Decrypt mail: +.Bd -literal -offset indent +$ openssl smime -decrypt -in mail.msg -recip mycert.pem \e + -inkey key.pem" +.Ed +.Pp +The output from Netscape form signing is a PKCS#7 structure with the +detached signature format. +You can use this program to verify the signature by line wrapping the +base64-encoded structure and surrounding it with: +.Bd -unfilled -offset indent +-----BEGIN PKCS7----- +-----END PKCS7----- +.Ed +.Pp +and using the command: +.Bd -literal -offset indent +$ openssl smime -verify -inform PEM -in signature.pem \e + -content content.txt +.Ed +.Pp +Alternatively, you can base64 decode the signature and use: +.Bd -literal -offset indent +$ openssl smime -verify -inform DER -in signature.der \e + -content content.txt +.Ed +.Pp +Create an encrypted message using 128-bit AES: +.Bd -literal -offset indent +openssl smime -encrypt -in plain.txt -aes128 \e + -out mail.msg cert.pem +.Ed +.Pp +Add a signer to an existing message: +.Bd -literal -offset indent +openssl smime -resign -in mail.msg -signer newsign.pem \e + -out mail2.msg +.Ed +.Sh SMIME BUGS +The +.Em MIME +parser isn't very clever: it seems to handle most messages that I've thrown +at it, but it may choke on others. +.Pp +The code currently will only write out the signer's certificate to a file: +if the signer has a separate encryption certificate this must be manually +extracted. +There should be some heuristic that determines the correct encryption +certificate. +.Pp +Ideally, a database should be maintained of a certificate for each email +address. +.Pp +The code doesn't currently take note of the permitted symmetric encryption +algorithms as supplied in the +.Em SMIMECapabilities +signed attribute. +This means the user has to manually include the correct encryption algorithm. +It should store the list of permitted ciphers in a database and only use those. +.Pp +No revocation checking is done on the signer's certificate. +.Pp +The current code can only handle +.Em S/MIME +v2 messages; the more complex +.Em S/MIME +v3 structures may cause parsing errors. +.Sh SMIME HISTORY +The use of multiple +.Fl signer +options and the +.Fl resign +command were first added in +.Nm OpenSSL +1.0.0. +.\" +.\" SPEED +.\" +.Sh SPEED +.nr nS 1 +.Nm "openssl speed" +.Bk -words +.Op Cm aes +.Op Cm aes-128-cbc +.Op Cm aes-192-cbc +.Op Cm aes-256-cbc +.Op Cm blowfish +.Op Cm bf-cbc +.Op Cm cast +.Op Cm cast-cbc +.Op Cm des +.Op Cm des-cbc +.Op Cm des-ede3 +.Op Cm dsa +.Op Cm dsa512 +.Op Cm dsa1024 +.Op Cm dsa2048 +.Op Cm hmac +.Op Cm md2 +.Op Cm md4 +.Op Cm md5 +.Op Cm rc2 +.Op Cm rc2-cbc +.Op Cm rc4 +.Op Cm rmd160 +.Op Cm rsa +.Op Cm rsa512 +.Op Cm rsa1024 +.Op Cm rsa2048 +.Op Cm rsa4096 +.Op Cm sha1 +.Op Fl decrypt +.Op Fl elapsed +.Op Fl engine Ar id +.Op Fl evp Ar e +.Op Fl mr +.Op Fl multi Ar number +.Ek +.nr nS 0 +.Pp +The +.Nm speed +command is used to test the performance of cryptographic algorithms. +.Bl -tag -width "XXXX" +.It Bq Cm zero or more test algorithms +If any options are given, +.Nm speed +tests those algorithms, otherwise all of the above are tested. +.It Fl decrypt +Time decryption instead of encryption +.Pq only EVP . +.It Fl engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm speed +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.It Fl elapsed +Measure time in real time instead of CPU user time. +.It Fl evp Ar e +Use EVP +.Ar e . +.It Fl mr +Produce machine readable output. +.It Fl multi Ar number +Run +.Ar number +benchmarks in parallel. +.El +.\" +.\" TS +.\" +.Sh TS +.nr nS 1 +.Nm "openssl ts" +.Bk -words +.Fl query +.Op Fl md4 | md5 | ripemd160 | sha | 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 +.Ek +.nr nS 0 +.Pp +.nr nS 1 +.Nm "openssl ts" +.Bk -words +.Fl reply +.Op Fl chain Ar certs_file.pem +.Op Fl config Ar configfile +.Op Fl engine Ar id +.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 +.Ek +.nr nS 0 +.Pp +.nr nS 1 +.Nm "openssl ts" +.Bk -words +.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 +.Ek +.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 a certain datum before a particular time. +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 +The TSA is expected to include its signing certificate in the +response. +.It Fl config Ar configfile +The configuration file to use. +This option overrides the +.Ev OPENSSL_CONF +environment variable. +Only the OID section of the config file is used with the +.Fl query +command. +.It Fl data Ar file_to_hash +The data file for which the time stamp request needs to be created. +stdin is the default if neither the +.Fl data +nor the +.Fl digest +option is specified. +.It Fl digest Ar digest_bytes +It is possible to 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 (e.g. 1A:F6:01:... or 1AF601...). +The number of bytes must match the message digest algorithm in use. +.It Fl in Ar request.tsq +This option specifies a previously created time stamp request in DER +format that will be printed into the output file. +Useful when you need to examine 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 +No nonce is specified in the request if this option is given. +Otherwise a 64-bit long pseudo-random none is +included in the request. +It is recommended to use nonce to protect against replay-attacks. +.It Fl out Ar request.tsq +Name of the output file to which the request will be written. +The default is stdout. +.It Fl policy Ar object_id +The policy that the client expects the TSA to use for creating the +time stamp token. +Either the dotted OID notation or OID names defined +in the config file can be used. +If no policy is requested the TSA will +use its own default policy. +.It Fl text +If this option is specified the output is 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 certificates, in PEM format, +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 +The configuration file to use. +This option overrides the +.Ev OPENSSL_CONF +environment variable. +See +.Sx TS CONFIGURATION FILE OPTIONS +for configurable variables. +.It Fl engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm ts +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.It Fl in Ar response.tsr +Specifies 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, +when you need to examine the content of a response or token +or you want 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 +.Dq 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. +For more information about the format of +.Ar arg , +see the +.Sx PASS PHRASE ARGUMENTS +section above. +.It Fl policy Ar object_id +The default policy to use for the response unless the client +explicitly requires a particular TSA policy. +The OID can be specified either in dotted notation or with its name. +Overrides the +.Cm default_policy +config file option. +.It Fl queryfile Ar request.tsq +The name of the file containing a DER-encoded time stamp request. +.It Fl section Ar tsa_section +The name of the config file section containing the settings for the +response generation. +If not specified the default TSA section is used; see +.Sx TS CONFIGURATION FILE OPTIONS +for details. +.It Fl signer Ar tsa_cert.pem +The signer certificate of the TSA in PEM format. +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 +If this option is specified the output is human-readable text format +instead of DER. +.It Fl token_in +This flag can be used together with the +.Fl in +option and indicates that 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 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 name of the file containing a set of trusted self-signed CA +certificates in PEM format. +See the similar option of +.Nm verify +for additional details. +Either this option or +.Fl CApath +must be specified. +.It Fl CApath Ar trusted_cert_path +The name of the directory containing the trused CA certificates of the +client. +See the similar option of +.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 +This flag can be used together with the +.Fl in +option and indicates that the input is a DER-encoded time stamp token +(ContentInfo) instead of a time stamp response (TimeStampResp). +.It Fl untrusted Ar cert_file.pem +Set of additional untrusted certificates in PEM format 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 +.Sh TS CONFIGURATION FILE OPTIONS +The +.Fl query +and +.Fl reply +options make use of a configuration file defined by the +.Ev OPENSSL_CONF +environment variable. +The +.Fl query +option uses only the symbolic OID names section +and it can work without it. +However, the +.Fl reply +option needs the config file for its operation. +.Pp +When there is a command line switch equivalent of a variable the +switch always overrides 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 default 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 name of 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 crypto_device +Specifies the +.Nm OpenSSL +engine that will be set as the default for +all available algorithms. +.It Cm signer_cert +TSA signing certificate, in PEM format. +The same as the +.Fl signer +command line option. +.It Cm certs +A file containing 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 +Specifies 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 TS ENVIRONMENT VARIABLES +.Ev OPENSSL_CONF +contains the path of the configuration file and can be +overridden by the +.Fl config +command line option. +.Sh TS EXAMPLES +All the examples below presume that +.Ev OPENSSL_CONF +is set to a proper configuration file, +e.g. the example configuration file +.Pa openssl/apps/openssl.cnf +will do. +.Pp +To create a time stamp request for design1.txt with SHA-1 +without nonce and policy and no certificate is required in the response: +.Bd -literal -offset indent +$ openssl ts -query -data design1.txt -no_nonce \e + -out design1.tsq +.Ed +.Pp +To create a similar time stamp request but specifying the message imprint +explicitly: +.Bd -literal -offset indent +$ openssl ts -query \e + -digest b7e5d3f93198b38379852f2c04e78d73abdd0f4b \e + -no_nonce -out design1.tsq +.Ed +.Pp +To print the content of the previous request in human readable format: +.Bd -literal -offset indent +$ openssl ts -query -in design1.tsq -text +.Ed +.Pp +To create a time stamp request which includes the MD5 digest +of design2.txt, requests the signer certificate and nonce, +specifies a policy ID +(assuming the tsa_policy1 name is defined in the +OID section of the config file): +.Bd -literal -offset indent +$ openssl ts -query -data design2.txt -md5 \e + -policy tsa_policy1 -cert -out design2.tsq +.Ed +.Pp +Before generating a response, +a signing certificate must be created for the TSA that contains the +.Cm timeStamping +critical extended key usage extension +without any other key usage extensions. +You can add the +.Dq extendedKeyUsage = critical,timeStamping +line to the user certificate section +of the config file to generate a proper certificate. +See the +.Nm req , +.Nm ca , +and +.Nm x509 +commands for instructions. +The examples below assume that cacert.pem contains the certificate of the CA, +tsacert.pem is the signing certificate issued by cacert.pem and +tsakey.pem is the private key of the TSA. +.Pp +To create a time stamp response for a request: +.Bd -literal -offset indent +$ openssl ts -reply -queryfile design1.tsq -inkey tsakey.pem \e + -signer tsacert.pem -out design1.tsr +.Ed +.Pp +If you want to use the settings in the config file you could just write: +.Bd -literal -offset indent +$ openssl ts -reply -queryfile design1.tsq -out design1.tsr +.Ed +.Pp +To print a time stamp reply to stdout in human readable format: +.Bd -literal -offset indent +$ openssl ts -reply -in design1.tsr -text +.Ed +.Pp +To create a time stamp token instead of time stamp response: +.Bd -literal -offset indent +$ openssl ts -reply -queryfile design1.tsq \e + -out design1_token.der -token_out +.Ed +.Pp +To print a time stamp token to stdout in human readable format: +.Bd -literal -offset indent +$ openssl ts -reply -in design1_token.der -token_in \e + -text -token_out +.Ed +.Pp +To extract the time stamp token from a response: +.Bd -literal -offset indent +$ openssl ts -reply -in design1.tsr -out design1_token.der \e + -token_out +.Ed +.Pp +To add +.Dq granted +status info to a time stamp token thereby creating a valid response: +.Bd -literal -offset indent +$ openssl ts -reply -in design1_token.der \e + -token_in -out design1.tsr +.Ed +.Pp +To verify a time stamp reply against a request: +.Bd -literal -offset indent +$ openssl ts -verify -queryfile design1.tsq -in design1.tsr \e + -CAfile cacert.pem -untrusted tsacert.pem +.Ed +.Pp +To verify a time stamp reply that includes the certificate chain: +.Bd -literal -offset indent +$ openssl ts -verify -queryfile design2.tsq -in design2.tsr \e + -CAfile cacert.pem +.Ed +.Pp +To verify a time stamp token against the original data file: +.Bd -literal -offset indent +$ openssl ts -verify -data design2.txt -in design2.tsr \e + -CAfile cacert.pem +.Ed +.Pp +To verify a time stamp token against a message imprint: +.Bd -literal -offset indent +$ openssl ts -verify \e + -digest b7e5d3f93198b38379852f2c04e78d73abdd0f4b \e + -in design2.tsr -CAfile cacert.pem +.Ed +.Sh TS BUGS +No support for time stamps over SMTP, though it is quite easy +to implement an automatic email-based TSA with +.Xr procmail +and +.Xr perl 1 . +Pure TCP/IP is not supported. +.Pp +The file containing the last serial number of the TSA is not +locked when being read or written. +This is a problem if more than one instance of +.Nm OpenSSL +is trying to create a time stamp +response at the same time. +.Pp +Look for the FIXME word in the source files. +.Pp +The source code should really be reviewed by somebody else, too. +.Pp +More testing is needed. +.Sh TS AUTHORS +.An Zoltan Glozik Aq Mt zglozik@opentsa.org , +OpenTSA project +.Pq Lk http://www.opentsa.org . +.\" +.\" SPKAC +.\" +.Sh SPKAC +.nr nS 1 +.Nm "openssl spkac" +.Bk -words +.Op Fl challenge Ar string +.Op Fl engine Ar id +.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 +.Ek +.nr nS 0 +.Pp +The +.Nm spkac +command processes Netscape signed public key and challenge +.Pq 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 +Specifies the challenge string if an SPKAC is being created. +.It Fl engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm spkac +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.It Fl in Ar file +This specifies the input +.Ar file +to read from, or standard input if this option is 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 +Don't output the text version of the SPKAC +.Pq not used if an SPKAC is being created . +.It Fl out Ar file +Specifies the output +.Ar file +to write to, or standard output by default. +.It Fl passin Ar arg +The key password source. +For more information about the format of +.Ar arg , +see the +.Sx PASS PHRASE ARGUMENTS +section above. +.It Fl pubkey +Output the public key of an SPKAC +.Pq not used if an SPKAC is being created . +.It Fl spkac Ar spkacname +Allows 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 +Allows an alternative name for the +.Ar section +containing the SPKAC. +The default is the default section. +.It Fl verify +Verifies the digital signature on the supplied SPKAC. +.El +.Sh SPKAC EXAMPLES +Print out the contents of an SPKAC: +.Pp +.Dl $ openssl spkac -in spkac.cnf +.Pp +Verify the signature of an SPKAC: +.Pp +.Dl $ openssl spkac -in spkac.cnf -noout -verify +.Pp +Create an SPKAC using the challenge string +.Qq hello : +.Pp +.Dl $ openssl spkac -key key.pem -challenge hello -out spkac.cnf +.Pp +Example of an SPKAC, +.Pq long lines split up for clarity : +.Bd -unfilled -offset indent +SPKAC=MIG5MGUwXDANBgkqhkiG9w0BAQEFAANLADBIAkEA1cCoq2Wa3Ixs47uI7F\e +PVwHVIPDx5yso105Y6zpozam135a8R0CpoRvkkigIyXfcCjiVi5oWk+6FfPaD03u\e +PFoQIDAQABFgVoZWxsbzANBgkqhkiG9w0BAQQFAANBAFpQtY/FojdwkJh1bEIYuc\e +2EeM2KHTWPEepWYeawvHD0gQ3DngSC75YCWnnDdq+NQ3F+X4deMx9AaEglZtULwV\e +4= +.Ed +.Sh SPKAC NOTES +A created SPKAC with suitable DN components appended can be fed into +the +.Nm ca +utility. +.Pp +SPKACs are typically generated by Netscape when a form is submitted +containing the +.Em KEYGEN +tag as part of the certificate enrollment process. +.Pp +The challenge string permits a primitive form of proof of possession +of private key. +By checking the SPKAC signature and a random challenge +string, some guarantee is given that the user knows the private key +corresponding to the public key being certified. +This is important in some applications. +Without this it is possible for a previous SPKAC +to be used in a +.Qq replay attack . +.\" +.\" VERIFY +.\" +.Sh VERIFY +.nr nS 1 +.Nm "openssl verify" +.Bk -words +.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 engine Ar id +.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 Fl +.Op Ar certificates +.Ek +.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 should have names of the form +.Em hash.0 , +or have symbolic links to them of this form +("hash" is the hashed certificate subject name: see the +.Fl hash +option of the +.Nm x509 +utility). +The +.Nm c_rehash +script distributed with OpenSSL +will automatically create symbolic links to a directory of certificates. +.It Fl crl_check +Checks 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 +Checks the validity of all certificates in the chain by attempting +to look up valid CRLs. +.It Fl engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm verify +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.It Fl explicit_policy +Set policy variable require-explicit-policy (see RFC 3280 et al). +.It Fl extended_crl +Enable extended CRL features such as indirect CRLs and alternate CRL +signing keys. +.It Fl help +Prints out a usage message. +.It Fl ignore_critical +Normally if an unhandled critical extension is present which is not +supported by +.Nm OpenSSL , +the certificate is rejected (as required by RFC 3280 et al). +If this option is set, critical extensions are ignored. +.It Fl inhibit_any +Set policy variable inhibit-any-policy (see RFC 3280 et al). +.It Fl inhibit_map +Set policy variable inhibit-policy-mapping (see RFC 3280 et al). +.It Fl issuer_checks +Print out diagnostics relating to searches for the issuer certificate +of the current certificate. +This shows why each candidate issuer certificate was rejected. +However 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 +Enables 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 +.Ar sslclient , sslserver , +.Ar nssslserver , smimesign , +.Ar smimeencrypt , crlsign , +.Ar any , +and +.Ar ocsphelper . +See the +.Sx VERIFY OPERATION +section for more information. +.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 Fl +Marks the last option. +All arguments following this are assumed to be certificate files. +This is useful if the first certificate filename begins with a +.Sq - . +.It Ar certificates +One or more +.Ar certificates +to verify. +If no certificate files are included, an attempt is made to read +a certificate from standard input. +They should all be in PEM format. +.El +.Sh VERIFY OPERATION +The +.Nm verify +program uses the same functions as the internal SSL and S/MIME verification, +therefore this description applies to these verify operations too. +.Pp +There is one crucial difference between the verify operations performed +by the +.Nm verify +program: 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: +.Pp +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 +The process of +.Qq looking up the issuer's certificate +itself involves a number of steps. +In versions of +.Nm OpenSSL +before 0.9.5a the first certificate whose subject name matched the issuer +of the current certificate was assumed to be the issuer's certificate. +In +.Nm OpenSSL +0.9.6 and later 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 +.Pq if present +must match the subject key identifier +.Pq if present +and issuer and serial number of the candidate issuer; in addition the +.Em keyUsage +extension of the candidate issuer +.Pq 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 +.Sx X.509 CERTIFICATE EXTENSIONS +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. +For compatibility with previous versions of +.Nm SSLeay +and +.Nm OpenSSL , +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 +.Em notBefore +and +.Em 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. +.Sh VERIFY DIAGNOSTICS +When a verify operation fails, the output messages can be somewhat cryptic. +The general form of the error message is: +.Bd -unfilled +\& 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 +.Aq Pa 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 Ar "0 X509_V_OK: ok" +The operation was successful. +.It Ar 2 X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: unable to get issuer certificate +The issuer certificate could not be found: this occurs if the issuer certificate +of an untrusted certificate cannot be found. +.It Ar 3 X509_V_ERR_UNABLE_TO_GET_CRL: unable to get certificate CRL +The CRL of a certificate could not be found. +.It Ar 4 X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: unable to decrypt certificate's 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 Ar 5 X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: unable to decrypt CRL's 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 Ar 6 X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: unable to decode issuer public key +The public key in the certificate +.Em SubjectPublicKeyInfo +could not be read. +.It Ar 7 X509_V_ERR_CERT_SIGNATURE_FAILURE: certificate signature failure +The signature of the certificate is invalid. +.It Ar 8 X509_V_ERR_CRL_SIGNATURE_FAILURE: CRL signature failure +The signature of the certificate is invalid. +.It Ar 9 X509_V_ERR_CERT_NOT_YET_VALID: certificate is not yet valid +The certificate is not yet valid: the +.Em notBefore +date is after the current time. +.It Ar 10 X509_V_ERR_CERT_HAS_EXPIRED: certificate has expired +The certificate has expired; that is, the +.Em notAfter +date is before the current time. +.It Ar 11 X509_V_ERR_CRL_NOT_YET_VALID: CRL is not yet valid +The CRL is not yet valid. +.It Ar 12 X509_V_ERR_CRL_HAS_EXPIRED: CRL has expired +The CRL has expired. +.It Ar 13 X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: format error in certificate's notBefore field +The certificate +.Em notBefore +field contains an invalid time. +.It Ar 14 X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: format error in certificate's notAfter field +The certificate +.Em notAfter +field contains an invalid time. +.It Ar 15 X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: format error in CRL's lastUpdate field +The CRL +.Em lastUpdate +field contains an invalid time. +.It Ar 16 X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: format error in CRL's nextUpdate field +The CRL +.Em nextUpdate +field contains an invalid time. +.It Ar 17 X509_V_ERR_OUT_OF_MEM: out of memory +An error occurred trying to allocate memory. +This should never happen. +.It Ar 18 X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: self signed certificate +The passed certificate is self-signed and the same certificate cannot be +found in the list of trusted certificates. +.It Ar 19 X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: self signed certificate in certificate chain +The certificate chain could be built up using the untrusted certificates but +the root could not be found locally. +.It Ar 20 X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: unable to get local issuer certificate +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 Ar 21 X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: unable to verify the first certificate +No signatures could be verified because the chain contains only one +certificate and it is not self-signed. +.It Ar 22 X509_V_ERR_CERT_CHAIN_TOO_LONG: certificate chain too long +The certificate chain length is greater than the supplied maximum depth. +Unused. +.It Ar 23 X509_V_ERR_CERT_REVOKED: certificate revoked +The certificate has been revoked. +.It Ar 24 X509_V_ERR_INVALID_CA: invalid CA certificate +A CA certificate is invalid. +Either it is not a CA or its extensions are not consistent +with the supplied purpose. +.It Ar 25 X509_V_ERR_PATH_LENGTH_EXCEEDED: path length constraint exceeded +The +.Em basicConstraints +pathlength parameter has been exceeded. +.It Ar 26 X509_V_ERR_INVALID_PURPOSE: unsupported certificate purpose +The supplied certificate cannot be used for the specified purpose. +.It Ar 27 X509_V_ERR_CERT_UNTRUSTED: certificate not trusted +The root CA is not marked as trusted for the specified purpose. +.It Ar 28 X509_V_ERR_CERT_REJECTED: certificate rejected +The root CA is marked to reject the specified purpose. +.It Ar 29 X509_V_ERR_SUBJECT_ISSUER_MISMATCH: 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 Ar 30 X509_V_ERR_AKID_SKID_MISMATCH: authority and subject key identifier 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 Ar 31 X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: authority and issuer serial number 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 Ar 32 X509_V_ERR_KEYUSAGE_NO_CERTSIGN:key usage does not include certificate signing +The current candidate issuer certificate was rejected because its +.Em keyUsage +extension does not permit certificate signing. +.It Ar 50 X509_V_ERR_APPLICATION_VERIFICATION: application verification failure +An application specific error. +Unused. +.El +.Sh VERIFY BUGS +Although the issuer checks are a considerable improvement over the old +technique, they still suffer from limitations in the underlying +X509_LOOKUP API. +One consequence of this is that trusted certificates with matching subject +name must either appear in a file (as specified by the +.Fl CAfile +option) or a directory (as specified by +.Fl CApath ) . +If they occur in both, only the certificates in the file will +be recognised. +.Pp +Previous versions of +.Nm OpenSSL +assumed certificates with matching subject name were identical and +mishandled them. +.\" +.\" VERSION +.\" +.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 VERSION NOTES +The output of +.Nm openssl version -a +would typically be used when sending in a bug report. +.Sh VERSION HISTORY +The +.Fl d +option was added in +.Nm OpenSSL +0.9.7. +.\" +.\" X509 +.\" +.Sh X509 +.nr nS 1 +.Nm "openssl x509" +.Bk -words +.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 Ar DER | PEM +.Op Fl CAkey Ar file +.Op Fl CAkeyform Ar 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 engine Ar id +.Op Fl extensions Ar section +.Op Fl extfile Ar file +.Op Fl fingerprint +.Op Fl hash +.Op Fl in Ar file +.Op Fl inform Ar DER | NET | PEM +.Op Fl issuer +.Op Fl issuer_hash +.Op Fl issuer_hash_old +.Op Fl keyform Ar DER | PEM +.Op Fl md2 | 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 Ar 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 +.Ek +.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 +Since there are a large number of options, they are split up into +various sections. +.Sh X509 INPUT, OUTPUT, AND GENERAL PURPOSE OPTIONS +.Bl -tag -width "XXXX" +.It Fl engine Ar id +Specifying an engine (by its unique +.Ar id +string) will cause +.Nm x509 +to attempt to obtain a functional reference to the specified engine, +thus initialising it if needed. +The engine will then be set as the default for all available algorithms. +.It Fl in Ar file +This specifies the input +.Ar file +to read a certificate from, or standard input if this option is not specified. +.It Fl inform Ar DER | NET | PEM +This specifies 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. +The +.Ar DER +format is the DER encoding of the certificate and +.Ar PEM +is the base64 encoding of the DER encoding with header and footer lines added. +The +.Ar NET +option is an obscure Netscape server format that is now +obsolete. +.It Fl md2 | 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. +If the key being used to sign with is a DSA key, +this option has no effect: SHA1 is always used with DSA keys. +.It Fl out Ar file +This specifies the output +.Ar file +to write to, or standard output by default. +.It Fl outform Ar DER | NET | PEM +This specifies the output format; the options have the same meaning as the +.Fl inform +option. +.It Fl passin Ar arg +The key password source. +For more information about the format of +.Ar arg , +see the +.Sx PASS PHRASE ARGUMENTS +section above. +.El +.Sh X509 DISPLAY OPTIONS +.Sy Note : +The +.Fl alias +and +.Fl purpose +options are also display options but are described in the +.Sx X509 TRUST SETTINGS +section. +.Bl -tag -width "XXXX" +.It Fl C +This outputs the certificate in the form of a C source file. +.It Fl certopt 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. +The +.Fl certopt +switch may also be used more than once to set multiple options. +See the +.Sx X509 TEXT OPTIONS +section for more information. +.It Fl dates +Prints out the start and expiry dates of a certificate. +.It Fl email +Outputs the email address(es), if any. +.It Fl enddate +Prints out the expiry date of the certificate; that is, the +.Em notAfter +date. +.It Fl fingerprint +Prints out the digest of the DER-encoded version of the whole certificate +(see +.Sx DIGEST OPTIONS ) . +.It Fl hash +A synonym for +.Fl subject_hash , +for backwards compatibility. +.It Fl issuer +Outputs the issuer name. +.It Fl issuer_hash +Outputs the +.Qq hash +of the certificate issuer name. +.It Fl issuer_hash_old +Outputs the +.Qq hash +of the certificate issuer name using the older algorithm +as used by +.Nm OpenSSL +versions before 1.0.0. +.It Fl modulus +This option prints out the value of the modulus of the public key +contained in the certificate. +.It Fl nameopt Ar option +Option which determines how the subject or issuer names are displayed. +The +.Ar option +argument can be a single option or multiple options separated by commas. +Alternatively, the +.Fl nameopt +switch may be used more than once to set multiple options. +See the +.Sx X509 NAME OPTIONS +section for more information. +.It Fl noout +This option prevents output of the encoded version of the request. +.It Fl ocsp_uri +Outputs the OCSP responder addresses, if any. +.It Fl ocspid +Print OCSP hash values for the subject name and public key. +.It Fl pubkey +Output the public key. +.It Fl serial +Outputs the certificate serial number. +.It Fl startdate +Prints out the start date of the certificate; that is, the +.Em notBefore +date. +.It Fl subject +Outputs the subject name. +.It Fl subject_hash +Outputs the +.Qq 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 +Outputs the +.Qq hash +of the certificate subject name using the older algorithm +as used by +.Nm OpenSSL +versions before 1.0.0. +.It Fl text +Prints out the certificate in text form. +Full details are output including the public key, signature algorithms, +issuer and subject names, serial number, any extensions present, +and any trust settings. +.El +.Sh X509 TRUST SETTINGS +Please note these options are currently experimental and may well change. +.Pp +A +.Em trusted certificate +is an ordinary certificate which has several +additional pieces of information attached to it such as the permitted +and prohibited uses of the certificate and an +.Qq alias . +.Pp +Normally, when a certificate is being verified at least one certificate +must be +.Qq trusted . +By default, a trusted certificate must be stored +locally and must be a root CA: any certificate chain ending in this CA +is then usable for any purpose. +.Pp +Trust settings currently are only used with a root CA. +They allow a finer control over the purposes the root CA can be used for. +For example, a CA may be trusted for an SSL client but not for +SSL server use. +.Pp +See the description of the +.Nm verify +utility for more information on the meaning of trust settings. +.Pp +Future versions of +.Nm OpenSSL +will recognize trust settings on any certificate: not just root CAs. +.Bl -tag -width "XXXX" +.It Fl addreject Ar arg +Adds a prohibited use. +It accepts the same values as the +.Fl addtrust +option. +.It Fl addtrust Ar arg +Adds a trusted certificate use. +Any object name can be used here, but currently only +.Ar clientAuth +.Pq SSL client use , +.Ar serverAuth +.Pq SSL server use , +and +.Ar emailProtection +.Pq S/MIME email +are used. +Other +.Nm OpenSSL +applications may define additional uses. +.It Fl alias +Outputs the certificate alias, if any. +.It Fl clrreject +Clears all the prohibited or rejected uses of the certificate. +.It Fl clrtrust +Clears all the permitted or trusted uses of the certificate. +.It Fl purpose +This option performs tests on the certificate extensions and outputs +the results. +For a more complete description, see the +.Sx X.509 CERTIFICATE EXTENSIONS +section. +.It Fl setalias Ar arg +Sets the alias of the certificate. +This will allow the certificate to be referred to using a nickname, +for example +.Qq Steve's Certificate . +.It Fl trustout +This causes +.Nm x509 +to output a +.Em trusted certificate . +An ordinary or trusted certificate can be input, but by default an ordinary +certificate is output and any trust settings are discarded. +With the +.Fl trustout +option a trusted certificate is output. +A trusted certificate is automatically output if any trust settings +are modified. +.El +.Sh X509 SIGNING OPTIONS +The +.Nm x509 +utility can be used to sign certificates and requests: it +can thus behave like a +.Qq mini CA . +.Bl -tag -width "XXXX" +.It Fl CA Ar file +Specifies the CA certificate to be used for signing. +When this option is present, +.Nm x509 +behaves like a +.Qq 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 +With this option the CA serial number file is created if it does not exist: +it will contain the serial number +.Sq 02 +and the certificate being signed will have +.Sq 1 +as its serial number. +Normally, if the +.Fl CA +option is specified and the serial number file does not exist, it is an error. +.It Fl CAform Ar DER | PEM +The format of the CA certificate file. +The default is +.Ar PEM . +.It Fl CAkey Ar file +Sets the CA private key to sign a certificate with. +If this option is not specified, it is assumed that the CA private key +is present in the CA certificate file. +.It Fl CAkeyform Ar DER | PEM +The format of the CA private key. +The default is +.Ar PEM . +.It Fl CAserial Ar file +Sets the CA serial number file to use. +.Pp +When the +.Fl CA +option is used to sign a certificate, +it uses a serial number specified in a file. +This file consists 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 +Specifies 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 +.Pq 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 Ar DER | PEM +Specifies the format +.Pq DER or PEM +of the private key file used in the +.Fl signkey +option. +.It Fl req +By default, a certificate is expected on input. +With this option a certificate request is expected instead. +.It Fl set_serial Ar n +Specifies 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 +This option causes the input file to be self-signed using the supplied +private key. +.Pp +If the input file is a certificate, it sets the issuer name to the +subject name +.Pq 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 +Converts a certificate into a certificate request. +The +.Fl signkey +option is used to pass the required private key. +.El +.Sh X509 NAME OPTIONS +The +.Fl nameopt +command line switch determines how the subject and issuer +names are displayed. +If no +.Fl nameopt +switch is present, the default +.Qq oneline +format is used which is compatible with previous versions of +.Nm OpenSSL . +Each option is described in detail below; all options can be preceded by a +.Sq - +to turn the option off. +Only +.Ar compat , +.Ar RFC2253 , +.Ar oneline , +and +.Ar multiline +will normally be used. +.Bl -tag -width "XXXX" +.It Ar align +Align field values for a more readable output. +Only usable with +.Ar sep_multiline . +.It Ar compat +Use the old format. +This is equivalent to specifying no name options at all. +.It Ar dn_rev +Reverse the fields of the DN. +This is required by RFC 2253. +As a side effect, this also reverses the order of multiple AVAs but this is +permissible. +.It Ar dump_all +Dump all fields. +This option, when used with +.Ar dump_der , +allows the DER encoding of the structure to be unambiguously determined. +.It Ar dump_der +When this option is set, any fields that need to be hexdumped will +be 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 Ar dump_nostr +Dump non-character string types +.Pq for example OCTET STRING ; +if this option is not set, non-character string types will be displayed +as though each content octet represents a single character. +.It Ar dump_unknown +Dump any field whose OID is not recognised by +.Nm OpenSSL . +.It Ar esc_2253 +Escape the +.Qq special +characters required by RFC 2253 in a field that is +.Dq \& ,+"\*(Lt\*(Gt; . +Additionally, +.Sq # +is escaped at the beginning of a string +and a space character at the beginning or end of a string. +.It Ar esc_ctrl +Escape control characters. +That is, those with ASCII values less than 0x20 +.Pq space +and the delete +.Pq 0x7f +character. +They are escaped using the RFC 2253 \eXX notation (where XX are two hex +digits representing the character value). +.It Ar esc_msb +Escape characters with the MSB set; that is, with ASCII values larger than +127. +.It Ar multiline +A multiline format. +It is equivalent to +.Ar esc_ctrl , esc_msb , sep_multiline , +.Ar space_eq , lname , +and +.Ar align . +.It Ar no_type +This option does not attempt to interpret multibyte characters in any +way. +That is, their content octets are merely dumped as though one octet +represents each character. +This is useful for diagnostic purposes but will result in rather odd +looking output. +.It Ar nofname , sname , lname , oid +These options alter how the field name is displayed. +.Ar nofname +does not display the field at all. +.Ar sname +uses the +.Qq short name +form (CN for +.Ar commonName , +for example). +.Ar lname +uses the long form. +.Ar oid +represents the OID in numerical form and is useful for diagnostic purpose. +.It Ar oneline +A oneline format which is more readable than +.Ar RFC2253 . +It is equivalent to specifying the +.Ar esc_2253 , esc_ctrl , esc_msb , utf8 , +.Ar dump_nostr , dump_der , use_quote , sep_comma_plus_spc , +.Ar space_eq , +and +.Ar sname +options. +.It Ar RFC2253 +Displays names compatible with RFC 2253; equivalent to +.Ar esc_2253 , esc_ctrl , +.Ar esc_msb , utf8 , dump_nostr , dump_unknown , +.Ar dump_der , sep_comma_plus , dn_rev , +and +.Ar sname . +.It Ar sep_comma_plus , sep_comma_plus_space , sep_semi_plus_space , sep_multiline +These options 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. +The +.Ar sep_multiline +uses a linefeed character for the RDN separator and a spaced +.Sq + +for the AVA separator. +It also indents the fields by four characters. +.It Ar show_type +Show the type of the ASN1 character string. +The type precedes the field contents. +For example +.Qq BMPSTRING: Hello World . +.It Ar space_eq +Places spaces round the +.Sq = +character which follows the field name. +.It Ar use_quote +Escapes some characters by surrounding the whole string with +.Sq \&" +characters. +Without the option, all escaping is done with the +.Sq \e +character. +.It Ar utf8 +Convert all strings to UTF8 format first. +This is required by RFC 2253. +If you are lucky enough to have a UTF8 compatible terminal, +the use of this option (and +.Em not +setting +.Ar esc_msb ) +may result in the correct display of multibyte +.Pq international +characters. +If this option is not present, multibyte characters larger than 0xff +will be represented using the format \eUXXXX for 16 bits and \eWXXXXXXXX +for 32 bits. +Also, if this option is off, any UTF8Strings will be converted to their +character form first. +.El +.Sh X509 TEXT OPTIONS +As well as customising the name output format, it is also possible to +customise the actual fields printed using the +.Fl certopt +options when the +.Fl text +option is present. +The default behaviour is to print all fields. +.Bl -tag -width "XXXX" +.It Ar ca_default +The value used by the +.Nm ca +utility; equivalent to +.Ar no_issuer , no_pubkey , no_header , +.Ar no_version , no_sigdump , +and +.Ar no_signame . +.It Ar compatible +Use the old format. +This is equivalent to specifying no output options at all. +.It Ar ext_default +Retain default extension behaviour: attempt to print out unsupported +certificate extensions. +.It Ar ext_dump +Hex dump unsupported extensions. +.It Ar ext_error +Print an error message for unsupported certificate extensions. +.It Ar ext_parse +ASN1 parse unsupported extensions. +.It Ar no_aux +Don't print out certificate trust information. +.It Ar no_extensions +Don't print out any X509V3 extensions. +.It Ar no_header +Don't print header information: that is, the lines saying +.Qq Certificate +and +.Qq Data . +.It Ar no_issuer +Don't print out the issuer name. +.It Ar no_pubkey +Don't print out the public key. +.It Ar no_serial +Don't print out the serial number. +.It Ar no_sigdump +Don't give a hexadecimal dump of the certificate signature. +.It Ar no_signame +Don't print out the signature algorithm used. +.It Ar no_subject +Don't print out the subject name. +.It Ar no_validity +Don't print the validity; that is, the +.Em notBefore +and +.Em notAfter +fields. +.It Ar no_version +Don't print out the version number. +.El +.Sh X509 EXAMPLES +Display the contents of a certificate: +.Pp +.Dl $ openssl x509 -in cert.pem -noout -text +.Pp +Display the certificate serial number: +.Pp +.Dl $ openssl x509 -in cert.pem -noout -serial +.Pp +Display the certificate subject name: +.Pp +.Dl $ openssl x509 -in cert.pem -noout -subject +.Pp +Display the certificate subject name in RFC 2253 form: +.Pp +.Dl $ openssl x509 -in cert.pem -noout -subject -nameopt RFC2253 +.Pp +Display the certificate subject name in oneline form on a terminal +supporting UTF8: +.Bd -literal -offset indent +$ openssl x509 -in cert.pem -noout -subject \e + -nameopt oneline,-esc_msb +.Ed +.Pp +Display the certificate MD5 fingerprint: +.Pp +.Dl $ openssl x509 -in cert.pem -noout -fingerprint +.Pp +Display the certificate SHA1 fingerprint: +.Pp +.Dl $ openssl x509 -sha1 -in cert.pem -noout -fingerprint +.Pp +Convert a certificate from PEM to DER format: +.Pp +.Dl "$ openssl x509 -in cert.pem -inform PEM -out cert.der -outform DER" +.Pp +Convert a certificate to a certificate request: +.Bd -literal -offset indent +$ openssl x509 -x509toreq -in cert.pem -out req.pem \e + -signkey key.pem +.Ed +.Pp +Convert a certificate request into a self-signed certificate using +extensions for a CA: +.Bd -literal -offset indent +$ openssl x509 -req -in careq.pem -extfile openssl.cnf -extensions \e + v3_ca -signkey key.pem -out cacert.pem +.Ed +.Pp +Sign a certificate request using the CA certificate above and add user +certificate extensions: +.Bd -literal -offset indent +$ openssl x509 -req -in req.pem -extfile openssl.cnf -extensions \e + v3_usr -CA cacert.pem -CAkey key.pem -CAcreateserial +.Ed +.Pp +Set a certificate to be trusted for SSL +client use and set its alias to +.Qq Steve's Class 1 CA : +.Bd -literal -offset indent +$ openssl x509 -in cert.pem -addtrust clientAuth \e + -setalias "Steve's Class 1 CA" -out trust.pem +.Ed +.Sh X509 NOTES +The PEM format uses the header and footer lines: +.Bd -unfilled -offset indent +-----BEGIN CERTIFICATE----- +-----END CERTIFICATE----- +.Ed +.Pp +It will also handle files containing: +.Bd -unfilled -offset indent +-----BEGIN X509 CERTIFICATE----- +-----END X509 CERTIFICATE----- +.Ed +.Pp +Trusted certificates have the lines: +.Bd -unfilled -offset indent +-----BEGIN TRUSTED CERTIFICATE----- +-----END TRUSTED CERTIFICATE----- +.Ed +.Pp +The conversion to UTF8 format used with the name options assumes that +T61Strings use the ISO 8859-1 character set. +This is wrong, but Netscape and MSIE do this, as do many certificates. +So although this is incorrect +it is more likely to display the majority of certificates correctly. +.Pp +The +.Fl fingerprint +option takes the digest of the DER-encoded certificate. +This is commonly called a +.Qq fingerprint . +Because of the nature of message digests, the fingerprint of a certificate +is unique to that certificate and two certificates with the same fingerprint +can be considered to be the same. +.Pp +The Netscape fingerprint uses MD5, whereas MSIE uses SHA1. +.Pp +The +.Fl email +option searches the subject name and the subject alternative +name extension. +Only unique email addresses will be printed out: it will +not print the same address more than once. +.Sh X.509 CERTIFICATE EXTENSIONS +The +.Fl purpose +option checks the certificate extensions and determines +what the certificate can be used for. +The actual checks done are rather +complex and include various hacks and workarounds to handle broken +certificates and software. +.Pp +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 +.Em 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. +.Em All +CAs should have the CA flag set to true. +.Pp +If the +.Em basicConstraints +extension is absent, then the certificate is +considered to be a +.Qq 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 +.Pq 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 +.Em keyUsage +extension is present, then additional restraints are +made on the uses of the certificate. +A CA certificate +.Em must +have the +.Em keyCertSign +bit set if the +.Em keyUsage +extension is present. +.Pp +The extended key usage extension places additional restrictions on the +certificate uses. +If this extension is present +.Pq 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 +.Em basicConstraints +and +.Em keyUsage +and V1 certificates above apply to +.Em all +CA certificates. +.Bl -tag -width "XXXX" +.It Ar SSL Client +The extended key usage extension must be absent or include the +.Qq web client authentication +OID. +.Ar keyUsage +must be absent or it must have the +.Em digitalSignature +bit set. +Netscape certificate type must be absent or it must have the SSL +client bit set. +.It Ar SSL Client CA +The extended key usage extension must be absent or include the +.Qq web client authentication +OID. +Netscape certificate type must be absent or it must have the SSL CA +bit set: this is used as a work around if the +.Em basicConstraints +extension is absent. +.It Ar SSL Server +The extended key usage extension must be absent or include the +.Qq web server authentication +and/or one of the SGC OIDs. +.Em keyUsage +must be absent or it must have the +.Em digitalSignature +set, the +.Em keyEncipherment +set, or both bits set. +Netscape certificate type must be absent or have the SSL server bit set. +.It Ar SSL Server CA +The extended key usage extension must be absent or include the +.Qq web server authentication +and/or one of the SGC OIDs. +Netscape certificate type must be absent or the SSL CA +bit must be set: this is used as a work around if the +.Em basicConstraints +extension is absent. +.It Ar Netscape SSL Server +For Netscape SSL clients to connect to an SSL server; it must have the +.Em keyEncipherment +bit set if the +.Em 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 Ar Common S/MIME Client Tests +The extended key usage extension must be absent or include the +.Qq email protection +OID. +Netscape certificate type must be absent or should have the +.Em S/MIME +bit set. +If the +.Em 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 +.Em S/MIME +bit. +.It Ar S/MIME Signing +In addition to the common +.Em S/MIME +client tests, the +.Em digitalSignature +bit must be set if the +.Em keyUsage +extension is present. +.It Ar S/MIME Encryption +In addition to the common +.Em S/MIME +tests, the +.Em keyEncipherment +bit must be set if the +.Em keyUsage +extension is present. +.It Ar S/MIME CA +The extended key usage extension must be absent or include the +.Qq email protection +OID. +Netscape certificate type must be absent or must have the +.Em S/MIME CA +bit set: this is used as a work around if the +.Em basicConstraints +extension is absent. +.It Ar CRL Signing +The +.Em keyUsage +extension must be absent or it must have the +.Em CRL +signing bit set. +.It Ar CRL Signing CA +The normal CA tests apply. +Except in this case the +.Em basicConstraints +extension must be present. +.El +.Sh X509 BUGS +Extensions in certificates are not transferred to certificate requests and +vice versa. +.Pp +It is possible to produce invalid certificates or requests by specifying the +wrong private key or using inconsistent options in some cases: these should +be checked. +.Pp +There should be options to explicitly set such things as start and end dates, +rather than an offset from the current time. +.Pp +The code to implement the verify behaviour described in the +.Sx X509 TRUST SETTINGS +is currently being developed. +It thus describes the intended behaviour rather than the current behaviour. +It is hoped that it will represent reality in +.Nm OpenSSL +0.9.5 and later. +.Sh X509 HISTORY +Before +.Nm OpenSSL +0.9.8, +the default digest for RSA keys was MD5. +.Pp +The hash algorithm used in the +.Fl subject_hash +and +.Fl issuer_hash +options before +.Nm OpenSSL +1.0.0 was based on the deprecated MD5 algorithm and the encoding +of the distinguished name. +In +.Nm OpenSSL +1.0.0 and later it is based on a canonical version of the DN using SHA1. +This means that any directories using the old form +must have their links rebuilt using +.Ar c_rehash +or similar. +.\" +.\" FILES +.\" +.Sh FILES +.Bl -tag -width "/etc/ssl/openssl.cnf" -compact +.It /etc/ssl/ +Default config directory for +.Nm openssl . +.It /etc/ssl/lib/ +Unused. +.It /etc/ssl/private/ +Default private key directory. +.It /etc/ssl/openssl.cnf +Default configuration file for +.Nm openssl . +.It /etc/ssl/x509v3.cnf +Default configuration file for +.Nm x509 +certificates. +.El +.\" +.\" SEE ALSO +.\" +.Sh SEE ALSO +.Xr nginx 8 , +.Xr sendmail 8 , +.Xr ssl 8 , +.Xr starttls 8 +.Sh STANDARDS +.Rs +.%D February 1995 +.%Q Netscape Communications Corp. +.%T The SSL Protocol +.Re +.Pp +.Rs +.%D November 1996 +.%Q Netscape Communications Corp. +.%T The SSL 3.0 Protocol +.Re +.Pp +.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 +.\" +.\" OPENSSL HISTORY +.\" +.Sh HISTORY +The +.Xr openssl 1 +document appeared in +.Nm OpenSSL +0.9.2. +The +.Cm list- Ns XXX Ns Cm -commands +pseudo-commands were added in +.Nm OpenSSL +0.9.3; +the +.Cm no- Ns XXX +pseudo-commands were added in +.Nm OpenSSL +0.9.5a; +the +.Cm list- Ns XXX Ns Cm -algorithms +pseudo-commands were added in +.Nm OpenSSL +1.0.0. diff --git a/usr.bin/openssl/openssl.c b/usr.bin/openssl/openssl.c new file mode 100644 index 00000000000..bcb9b56b744 --- /dev/null +++ b/usr.bin/openssl/openssl.c @@ -0,0 +1,639 @@ +/* $OpenBSD: openssl.c,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.] + */ +/* ==================================================================== + * 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 <err.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "apps.h" + +#include <openssl/bio.h> +#include <openssl/conf.h> +#include <openssl/crypto.h> +#include <openssl/err.h> +#include <openssl/lhash.h> +#include <openssl/pem.h> +#include <openssl/rand.h> +#include <openssl/ssl.h> +#include <openssl/x509.h> + +#ifndef OPENSSL_NO_ENGINE +#include <openssl/engine.h> +#endif + +#include "progs.h" +#include "s_apps.h" + +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); + + CRYPTO_malloc_init(); + OpenSSL_add_all_algorithms(); + SSL_library_init(); + SSL_load_error_strings(); + +#ifndef OPENSSL_NO_ENGINE + ENGINE_load_builtin_engines(); +#endif + + setup_ui_method(); +} + +static void +openssl_shutdown(void) +{ + CONF_modules_unload(1); + destroy_ui_method(); + OBJ_cleanup(); + EVP_cleanup(); + +#ifndef OPENSSL_NO_ENGINE + ENGINE_cleanup(); +#endif + + CRYPTO_cleanup_all_ex_data(); + ERR_remove_thread_state(NULL); + RAND_cleanup(); + 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; + + bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); + if (bio_err == NULL) { + fprintf(stderr, "openssl: failed to initialise bio_err\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 = getenv("SSLEAY_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; + 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++; + 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 = "<undefined>"; + if (!to) + to = "<undefined>"; + 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 = "<undefined>"; + if (!to) + to = "<undefined>"; + 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/usr.bin/openssl/passwd.c b/usr.bin/openssl/passwd.c new file mode 100644 index 00000000000..fd5d062f57d --- /dev/null +++ b/usr.bin/openssl/passwd.c @@ -0,0 +1,457 @@ +/* $OpenBSD: passwd.c,v 1.1 2014/08/26 17:47:25 jsing Exp $ */ + +#if defined OPENSSL_NO_MD5 +#define NO_MD5CRYPT_1 +#endif + +#if !defined(OPENSSL_NO_DES) || !defined(NO_MD5CRYPT_1) + +#include <assert.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/bio.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/rand.h> + +#ifndef OPENSSL_NO_DES +#include <openssl/des.h> +#endif + +#ifndef NO_MD5CRYPT_1 +#include <openssl/md5.h> +#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); + +/* -crypt - standard Unix password algorithm (default) + * -1 - MD5-based password algorithm + * -apr1 - MD5-based password algorithm, Apache variant + * -salt string - salt + * -in file - read passwords from file + * -stdin - read passwords from stdin + * -noverify - never verify when reading password from terminal + * -quiet - no warnings + * -table - format output as table + * -reverse - switch table columns + */ + +int passwd_main(int, char **); + +int +passwd_main(int argc, char **argv) +{ + int ret = 1; + char *infile = NULL; + int in_stdin = 0; + int in_noverify = 0; + char *salt = NULL, *passwd = NULL, **passwds = NULL; + char *salt_malloc = NULL, *passwd_malloc = NULL; + size_t passwd_malloc_size = 0; + int pw_source_defined = 0; + BIO *in = NULL, *out = NULL; + int i, badopt, opt_done; + int passed_salt = 0, quiet = 0, table = 0, reverse = 0; + int usecrypt = 0, use1 = 0, useapr1 = 0; + size_t pw_maxlen = 0; + + out = BIO_new(BIO_s_file()); + if (out == NULL) + goto err; + BIO_set_fp(out, stdout, BIO_NOCLOSE | BIO_FP_TEXT); + + badopt = 0, opt_done = 0; + i = 0; + while (!badopt && !opt_done && argv[++i] != NULL) { + if (strcmp(argv[i], "-crypt") == 0) + usecrypt = 1; + else if (strcmp(argv[i], "-1") == 0) + use1 = 1; + else if (strcmp(argv[i], "-apr1") == 0) + useapr1 = 1; + else if (strcmp(argv[i], "-salt") == 0) { + if ((argv[i + 1] != NULL) && (salt == NULL)) { + passed_salt = 1; + salt = argv[++i]; + } else + badopt = 1; + } else if (strcmp(argv[i], "-in") == 0) { + if ((argv[i + 1] != NULL) && !pw_source_defined) { + pw_source_defined = 1; + infile = argv[++i]; + } else + badopt = 1; + } else if (strcmp(argv[i], "-stdin") == 0) { + if (!pw_source_defined) { + pw_source_defined = 1; + in_stdin = 1; + } else + badopt = 1; + } else if (strcmp(argv[i], "-noverify") == 0) + in_noverify = 1; + else if (strcmp(argv[i], "-quiet") == 0) + quiet = 1; + else if (strcmp(argv[i], "-table") == 0) + table = 1; + else if (strcmp(argv[i], "-reverse") == 0) + reverse = 1; + else if (argv[i][0] == '-') + badopt = 1; + else if (!pw_source_defined) + /* non-option arguments, use as passwords */ + { + pw_source_defined = 1; + passwds = &argv[i]; + opt_done = 1; + } else + badopt = 1; + } + + if (!usecrypt && !use1 && !useapr1) /* use default */ + usecrypt = 1; + if (usecrypt + use1 + useapr1 > 1) /* conflict */ + badopt = 1; + + /* reject unsupported algorithms */ +#ifdef OPENSSL_NO_DES + if (usecrypt) + badopt = 1; +#endif +#ifdef NO_MD5CRYPT_1 + if (use1 || useapr1) + badopt = 1; +#endif + + if (badopt) { + BIO_printf(bio_err, "Usage: passwd [options] [passwords]\n"); + BIO_printf(bio_err, "where options are\n"); +#ifndef OPENSSL_NO_DES + BIO_printf(bio_err, "-crypt standard Unix password algorithm (default)\n"); +#endif +#ifndef NO_MD5CRYPT_1 + BIO_printf(bio_err, "-1 MD5-based password algorithm\n"); + BIO_printf(bio_err, "-apr1 MD5-based password algorithm, Apache variant\n"); +#endif + BIO_printf(bio_err, "-salt string use provided salt\n"); + BIO_printf(bio_err, "-in file read passwords from file\n"); + BIO_printf(bio_err, "-stdin read passwords from stdin\n"); + BIO_printf(bio_err, "-noverify never verify when reading password from terminal\n"); + BIO_printf(bio_err, "-quiet no warnings\n"); + BIO_printf(bio_err, "-table format output as table\n"); + BIO_printf(bio_err, "-reverse switch table columns\n"); + + goto err; + } + if ((infile != NULL) || in_stdin) { + in = BIO_new(BIO_s_file()); + if (in == NULL) + goto err; + if (infile != NULL) { + assert(in_stdin == 0); + if (BIO_read_filename(in, infile) <= 0) + goto err; + } else { + assert(in_stdin); + BIO_set_fp(in, stdin, BIO_NOCLOSE); + } + } + if (usecrypt) + pw_maxlen = 8; + else if (use1 || 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 || in_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, &salt, &salt_malloc, passwd, out, + quiet, table, reverse, pw_maxlen, usecrypt, use1, useapr1)) + goto err; + } + while (*passwds != NULL); + } else + /* in != NULL */ + { + 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, &salt, &salt_malloc, passwd, out, + quiet, table, reverse, pw_maxlen, usecrypt, use1, 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); + if (out) + 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; + } + if (RAND_pseudo_bytes((unsigned char *) *salt_p, 2) < 0) + goto err; + (*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; + } + if (RAND_pseudo_bytes((unsigned char *) *salt_p, 8) < 0) + goto err; + + 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/usr.bin/openssl/pkcs12.c b/usr.bin/openssl/pkcs12.c new file mode 100644 index 00000000000..77b7c31d016 --- /dev/null +++ b/usr.bin/openssl/pkcs12.c @@ -0,0 +1,913 @@ +/* $OpenBSD: pkcs12.c,v 1.1 2014/08/26 17:47:25 jsing 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 <openssl/opensslconf.h> + +#if !defined(OPENSSL_NO_DES) && !defined(OPENSSL_NO_SHA1) + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/crypto.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/pkcs12.h> + +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, char **); + +int +pkcs12_main(int argc, char **argv) +{ + ENGINE *e = NULL; + 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; +#ifndef OPENSSL_NO_ENGINE + char *engine = NULL; +#endif + + 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; +#ifndef OPENSSL_NO_ENGINE + } else if (!strcmp(*args, "-engine")) { + if (args[1]) { + args++; + engine = *args; + } else + badarg = 1; +#endif + } 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"); +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, "-engine e use engine e, possibly a hardware device.\n"); +#endif + 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; + } +#ifndef OPENSSL_NO_ENGINE + e = setup_engine(bio_err, engine, 0); +#endif + + 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; + } + + ERR_load_crypto_strings(); + + + 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 : "<stdin>"); + 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 : "<stdout>"); + 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, e, "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, e, + "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, e, + "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 (M_PKCS12_bag_type(bag)) { + 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 (M_PKCS12_cert_bag_type(bag) != 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: <No Attributes>\n", name); + return 1; + } + if (!sk_X509_ATTRIBUTE_num(attrlst)) { + BIO_printf(out, "%s: <Empty Attributes>\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, "<Unsupported tag %d>\n", av->type); + break; + } + } else + BIO_printf(out, "<No Values>\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/usr.bin/openssl/pkcs7.c b/usr.bin/openssl/pkcs7.c new file mode 100644 index 00000000000..2c2af168a95 --- /dev/null +++ b/usr.bin/openssl/pkcs7.c @@ -0,0 +1,284 @@ +/* $OpenBSD: pkcs7.c,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.] + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "apps.h" + +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/objects.h> +#include <openssl/pem.h> +#include <openssl/pkcs7.h> +#include <openssl/x509.h> + +/* -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 + * -print_certs + */ + +int pkcs7_main(int, char **); + +int +pkcs7_main(int argc, char **argv) +{ + PKCS7 *p7 = NULL; + int i, badops = 0; + BIO *in = NULL, *out = NULL; + int informat, outformat; + char *infile, *outfile, *prog; + int print_certs = 0, text = 0, noout = 0, p7_print = 0; + int ret = 1; +#ifndef OPENSSL_NO_ENGINE + char *engine = NULL; +#endif + + 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, "-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, "-noout") == 0) + noout = 1; + else if (strcmp(*argv, "-text") == 0) + text = 1; + else if (strcmp(*argv, "-print") == 0) + p7_print = 1; + else if (strcmp(*argv, "-print_certs") == 0) + print_certs = 1; +#ifndef OPENSSL_NO_ENGINE + else if (strcmp(*argv, "-engine") == 0) { + if (--argc < 1) + goto bad; + engine = *(++argv); + } +#endif + else { + BIO_printf(bio_err, "unknown option %s\n", *argv); + badops = 1; + break; + } + argc--; + argv++; + } + + if (badops) { +bad: + BIO_printf(bio_err, "%s [options] <infile >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, " -print_certs print any certs or crl in the input\n"); + BIO_printf(bio_err, " -text print full details of certificates\n"); + BIO_printf(bio_err, " -noout don't output encoded data\n"); +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, " -engine e use engine e, possibly a hardware device.\n"); +#endif + ret = 1; + goto end; + } + ERR_load_crypto_strings(); + +#ifndef OPENSSL_NO_ENGINE + setup_engine(bio_err, engine, 0); +#endif + + 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 (infile == NULL) + BIO_set_fp(in, stdin, BIO_NOCLOSE); + else { + if (BIO_read_filename(in, infile) <= 0) + if (in == NULL) { + perror(infile); + goto end; + } + } + + if (informat == FORMAT_ASN1) + p7 = d2i_PKCS7_bio(in, NULL); + else if (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 (outfile == NULL) { + BIO_set_fp(out, stdout, BIO_NOCLOSE); + } else { + if (BIO_write_filename(out, outfile) <= 0) { + perror(outfile); + goto end; + } + } + + if (p7_print) + PKCS7_print_ctx(out, p7, 0, NULL); + + if (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 (text) + X509_print(out, x); + else + dump_cert_text(out, x); + + if (!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 (!noout) + PEM_write_bio_X509_CRL(out, crl); + BIO_puts(out, "\n"); + } + } + ret = 0; + goto end; + } + if (!noout) { + if (outformat == FORMAT_ASN1) + i = i2d_PKCS7_bio(out, p7); + else if (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/usr.bin/openssl/pkcs8.c b/usr.bin/openssl/pkcs8.c new file mode 100644 index 00000000000..1715fe1d6b6 --- /dev/null +++ b/usr.bin/openssl/pkcs8.c @@ -0,0 +1,367 @@ +/* $OpenBSD: pkcs8.c,v 1.1 2014/08/26 17:47:25 jsing 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 <stdio.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/pem.h> +#include <openssl/pkcs12.h> + +int pkcs8_main(int, char **); + +int +pkcs8_main(int argc, char **argv) +{ + ENGINE *e = NULL; + char **args, *infile = NULL, *outfile = NULL; + char *passargin = NULL, *passargout = NULL; + BIO *in = NULL, *out = NULL; + int topk8 = 0; + int pbe_nid = -1; + const EVP_CIPHER *cipher = NULL; + int iter = PKCS12_DEFAULT_ITER; + int informat, outformat; + int p8_broken = PKCS8_OK; + int nocrypt = 0; + X509_SIG *p8 = NULL; + PKCS8_PRIV_KEY_INFO *p8inf = NULL; + EVP_PKEY *pkey = NULL; + char pass[50], *passin = NULL, *passout = NULL, *p8pass = NULL; + int badarg = 0; + int ret = 1; +#ifndef OPENSSL_NO_ENGINE + char *engine = NULL; +#endif + + informat = FORMAT_PEM; + outformat = FORMAT_PEM; + + ERR_load_crypto_strings(); + OpenSSL_add_all_algorithms(); + args = argv + 1; + while (!badarg && *args && *args[0] == '-') { + if (!strcmp(*args, "-v2")) { + if (args[1]) { + args++; + cipher = EVP_get_cipherbyname(*args); + if (!cipher) { + BIO_printf(bio_err, + "Unknown cipher %s\n", *args); + badarg = 1; + } + } else + badarg = 1; + } else if (!strcmp(*args, "-v1")) { + if (args[1]) { + args++; + pbe_nid = OBJ_txt2nid(*args); + if (pbe_nid == NID_undef) { + BIO_printf(bio_err, + "Unknown PBE algorithm %s\n", *args); + badarg = 1; + } + } else + badarg = 1; + } else 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, "-topk8")) + topk8 = 1; + else if (!strcmp(*args, "-noiter")) + iter = 1; + else if (!strcmp(*args, "-nocrypt")) + nocrypt = 1; + else if (!strcmp(*args, "-nooct")) + p8_broken = PKCS8_NO_OCTET; + else if (!strcmp(*args, "-nsdb")) + p8_broken = PKCS8_NS_DB; + else if (!strcmp(*args, "-embed")) + p8_broken = PKCS8_EMBEDDED_PARAM; + else if (!strcmp(*args, "-passin")) { + if (!args[1]) + goto bad; + passargin = *(++args); + } else if (!strcmp(*args, "-passout")) { + if (!args[1]) + goto bad; + passargout = *(++args); + } +#ifndef OPENSSL_NO_ENGINE + else if (strcmp(*args, "-engine") == 0) { + if (!args[1]) + goto bad; + engine = *(++args); + } +#endif + 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 + badarg = 1; + args++; + } + + if (badarg) { +bad: + BIO_printf(bio_err, "Usage pkcs8 [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"); + BIO_printf(bio_err, "-topk8 output PKCS8 file\n"); + BIO_printf(bio_err, "-nooct use (nonstandard) no octet format\n"); + BIO_printf(bio_err, "-embed use (nonstandard) embedded DSA parameters format\n"); + BIO_printf(bio_err, "-nsdb use (nonstandard) DSA Netscape DB format\n"); + BIO_printf(bio_err, "-noiter use 1 as iteration count\n"); + BIO_printf(bio_err, "-nocrypt use or expect unencrypted private key\n"); + BIO_printf(bio_err, "-v2 alg use PKCS#5 v2.0 and cipher \"alg\"\n"); + BIO_printf(bio_err, "-v1 obj use PKCS#5 v1.5 and cipher \"alg\"\n"); +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, " -engine e use engine e, possibly a hardware device.\n"); +#endif + goto end; + } +#ifndef OPENSSL_NO_ENGINE + e = setup_engine(bio_err, engine, 0); +#endif + + if (!app_passwd(bio_err, passargin, passargout, &passin, &passout)) { + BIO_printf(bio_err, "Error getting passwords\n"); + goto end; + } + if ((pbe_nid == -1) && !cipher) + pbe_nid = NID_pbeWithMD5AndDES_CBC; + + if (infile) { + if (!(in = BIO_new_file(infile, "rb"))) { + BIO_printf(bio_err, + "Can't open input file %s\n", infile); + goto end; + } + } else + in = BIO_new_fp(stdin, BIO_NOCLOSE); + + 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 (topk8) { + pkey = load_key(bio_err, infile, informat, 1, + passin, e, "key"); + if (!pkey) + goto end; + if (!(p8inf = EVP_PKEY2PKCS8_broken(pkey, p8_broken))) { + BIO_printf(bio_err, "Error converting key\n"); + ERR_print_errors(bio_err); + goto end; + } + if (nocrypt) { + if (outformat == FORMAT_PEM) + PEM_write_bio_PKCS8_PRIV_KEY_INFO(out, p8inf); + else if (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(pbe_nid, cipher, + p8pass, strlen(p8pass), + NULL, 0, iter, p8inf))) { + BIO_printf(bio_err, "Error encrypting key\n"); + ERR_print_errors(bio_err); + goto end; + } + if (outformat == FORMAT_PEM) + PEM_write_bio_PKCS8(out, p8); + else if (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 (nocrypt) { + if (informat == FORMAT_PEM) + p8inf = PEM_read_bio_PKCS8_PRIV_KEY_INFO(in, NULL, NULL, NULL); + else if (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 (informat == FORMAT_PEM) + p8 = PEM_read_bio_PKCS8(in, NULL, NULL, NULL); + else if (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 (outformat == FORMAT_PEM) + PEM_write_bio_PrivateKey(out, pkey, NULL, NULL, 0, NULL, passout); + else if (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/usr.bin/openssl/pkey.c b/usr.bin/openssl/pkey.c new file mode 100644 index 00000000000..7f13bbbf620 --- /dev/null +++ b/usr.bin/openssl/pkey.c @@ -0,0 +1,235 @@ +/* $OpenBSD: pkey.c,v 1.1 2014/08/26 17:47:25 jsing 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 <stdio.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/pem.h> + +int pkey_main(int, char **); + +int +pkey_main(int argc, char **argv) +{ + ENGINE *e = NULL; + 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; +#ifndef OPENSSL_NO_ENGINE + char *engine = NULL; +#endif + int ret = 1; + + informat = FORMAT_PEM; + outformat = FORMAT_PEM; + + ERR_load_crypto_strings(); + OpenSSL_add_all_algorithms(); + 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); + } +#ifndef OPENSSL_NO_ENGINE + else if (strcmp(*args, "-engine") == 0) { + if (!args[1]) + goto bad; + engine = *(++args); + } +#endif + 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"); +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, "-engine e use engine e, possibly a hardware device.\n"); +#endif + return 1; + } +#ifndef OPENSSL_NO_ENGINE + e = setup_engine(bio_err, engine, 0); +#endif + + 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, e, "Public Key"); + else + pkey = load_key(bio_err, infile, informat, 1, + passin, e, "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/usr.bin/openssl/pkeyparam.c b/usr.bin/openssl/pkeyparam.c new file mode 100644 index 00000000000..c48f1a95ddf --- /dev/null +++ b/usr.bin/openssl/pkeyparam.c @@ -0,0 +1,173 @@ +/* $OpenBSD: pkeyparam.c,v 1.1 2014/08/26 17:47:25 jsing 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 <stdio.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/pem.h> + +int pkeyparam_main(int, char **); + +int +pkeyparam_main(int argc, char **argv) +{ + char **args, *infile = NULL, *outfile = NULL; + BIO *in = NULL, *out = NULL; + int text = 0, noout = 0; + EVP_PKEY *pkey = NULL; + int badarg = 0; +#ifndef OPENSSL_NO_ENGINE + char *engine = NULL; +#endif + int ret = 1; + + ERR_load_crypto_strings(); + OpenSSL_add_all_algorithms(); + args = argv + 1; + while (!badarg && *args && *args[0] == '-') { + 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; + } +#ifndef OPENSSL_NO_ENGINE + else if (strcmp(*args, "-engine") == 0) { + if (!args[1]) + goto bad; + engine = *(++args); + } +#endif + + else if (strcmp(*args, "-text") == 0) + text = 1; + else if (strcmp(*args, "-noout") == 0) + noout = 1; + args++; + } + + if (badarg) { +#ifndef OPENSSL_NO_ENGINE +bad: +#endif + BIO_printf(bio_err, "Usage pkeyparam [options]\n"); + BIO_printf(bio_err, "where options are\n"); + BIO_printf(bio_err, "-in file input file\n"); + BIO_printf(bio_err, "-out file output file\n"); + BIO_printf(bio_err, "-text print parameters as text\n"); + BIO_printf(bio_err, "-noout don't output encoded parameters\n"); +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, "-engine e use engine e, possibly a hardware device.\n"); +#endif + return 1; + } +#ifndef OPENSSL_NO_ENGINE + setup_engine(bio_err, engine, 0); +#endif + + if (infile) { + if (!(in = BIO_new_file(infile, "r"))) { + BIO_printf(bio_err, + "Can't open input file %s\n", infile); + goto end; + } + } else + in = BIO_new_fp(stdin, BIO_NOCLOSE); + + if (outfile) { + if (!(out = BIO_new_file(outfile, "w"))) { + BIO_printf(bio_err, + "Can't open output file %s\n", 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 (!noout) + PEM_write_bio_Parameters(out, pkey); + + if (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/usr.bin/openssl/pkeyutl.c b/usr.bin/openssl/pkeyutl.c new file mode 100644 index 00000000000..5fff008db62 --- /dev/null +++ b/usr.bin/openssl/pkeyutl.c @@ -0,0 +1,503 @@ +/* $OpenBSD: pkeyutl.c,v 1.1 2014/08/26 17:47:25 jsing 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 <string.h> + +#include "apps.h" + +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/pem.h> + +#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, ENGINE * e); + +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 **); + +int +pkeyutl_main(int argc, char **argv) +{ + BIO *in = NULL, *out = NULL; + char *infile = NULL, *outfile = NULL, *sigfile = NULL; + ENGINE *e = 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; + + argc--; + argv++; + + ERR_load_crypto_strings(); + OpenSSL_add_all_algorithms(); + + 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, e); + 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)); + } +#ifndef OPENSSL_NO_ENGINE + else if (!strcmp(*argv, "-engine")) { + if (--argc < 1) + badarg = 1; + else + e = setup_engine(bio_err, *(++argv), 0); + } +#endif + 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 == 0) + BIO_puts(out, "Signature Verification Failure\n"); + else if (rv == 1) + BIO_puts(out, "Signature Verified Successfully\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"); +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, "-engine e use engine e, possibly a hardware device.\n"); +#endif + 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, ENGINE * e) +{ + 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, e, "Private Key"); + break; + + case KEY_PUBKEY: + pkey = load_pubkey(bio_err, keyfile, keyform, 0, + NULL, e, "Public Key"); + break; + + case KEY_CERT: + x = load_cert(bio_err, keyfile, keyform, + NULL, e, "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, e); + + 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, 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/usr.bin/openssl/prime.c b/usr.bin/openssl/prime.c new file mode 100644 index 00000000000..e7fb3257d8f --- /dev/null +++ b/usr.bin/openssl/prime.c @@ -0,0 +1,147 @@ +/* $OpenBSD: prime.c,v 1.1 2014/08/26 17:47:25 jsing 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 <string.h> +#include <limits.h> + +#include "apps.h" + +#include <openssl/bn.h> + +int prime_main(int, char **); + +int +prime_main(int argc, char **argv) +{ + int hex = 0; + int checks = 20; + int generate = 0; + int bits = 0; + int safe = 0; + BIGNUM *bn = NULL; + const char *errstr = NULL; + BIO *bio_out; + + --argc; + ++argv; + while (argc >= 1 && **argv == '-') { + if (!strcmp(*argv, "-hex")) + hex = 1; + else if (!strcmp(*argv, "-generate")) + generate = 1; + else if (!strcmp(*argv, "-bits")) { + if (--argc < 1) + goto bad; + else + bits = strtonum(*(++argv), 0, INT_MAX, &errstr); + if (errstr) + goto bad; + } else if (!strcmp(*argv, "-safe")) + safe = 1; + else if (!strcmp(*argv, "-checks")) { + if (--argc < 1) + goto bad; + else + checks = strtonum(*(++argv), 0, INT_MAX, &errstr); + if (errstr) + goto bad; + } else { + BIO_printf(bio_err, "Unknown option '%s'\n", *argv); + goto bad; + } + --argc; + ++argv; + } + + if (argv[0] == NULL && !generate) { + BIO_printf(bio_err, "No prime specified\n"); + goto bad; + } + if ((bio_out = BIO_new(BIO_s_file())) != NULL) { + BIO_set_fp(bio_out, stdout, BIO_NOCLOSE); + } + if (generate) { + char *s; + + if (!bits) { + BIO_printf(bio_err, "Specifiy the number of bits.\n"); + return 1; + } + bn = BN_new(); + BN_generate_prime_ex(bn, bits, safe, NULL, NULL, NULL); + s = hex ? BN_bn2hex(bn) : BN_bn2dec(bn); + BIO_printf(bio_out, "%s\n", s); + free(s); + } else { + if (hex) + BN_hex2bn(&bn, argv[0]); + else + BN_dec2bn(&bn, argv[0]); + + BN_print(bio_out, bn); + BIO_printf(bio_out, " is %sprime\n", + BN_is_prime_ex(bn, checks, NULL, NULL) ? "" : "not "); + } + + BN_free(bn); + BIO_free_all(bio_out); + + return 0; + +bad: + if (errstr) + BIO_printf(bio_err, "invalid argument %s: %s\n", *argv, errstr); + else { + BIO_printf(bio_err, "options are\n"); + BIO_printf(bio_err, "%-14s hex\n", "-hex"); + BIO_printf(bio_err, "%-14s number of checks\n", "-checks <n>"); + } + return 1; +} diff --git a/usr.bin/openssl/progs.h b/usr.bin/openssl/progs.h new file mode 100644 index 00000000000..6f957c6f7c9 --- /dev/null +++ b/usr.bin/openssl/progs.h @@ -0,0 +1,234 @@ +/* $OpenBSD: progs.h,v 1.1 2014/08/26 17:47:25 jsing Exp $ */ +/* Public domain */ + +extern int asn1parse_main(int argc, char *argv[]); +extern int ca_main(int argc, char *argv[]); +extern int ciphers_main(int argc, char *argv[]); +extern int cms_main(int argc, char *argv[]); +extern int crl2pkcs7_main(int argc, char *argv[]); +extern int crl_main(int argc, char *argv[]); +extern int dgst_main(int argc, char *argv[]); +extern int dh_main(int argc, char *argv[]); +extern int dhparam_main(int argc, char *argv[]); +extern int dsa_main(int argc, char *argv[]); +extern int dsaparam_main(int argc, char *argv[]); +extern int ec_main(int argc, char *argv[]); +extern int ecparam_main(int argc, char *argv[]); +extern int enc_main(int argc, char *argv[]); +extern int engine_main(int argc, char *argv[]); +extern int errstr_main(int argc, char *argv[]); +extern int gendh_main(int argc, char *argv[]); +extern int gendsa_main(int argc, char *argv[]); +extern int genpkey_main(int argc, char *argv[]); +extern int genrsa_main(int argc, char *argv[]); +extern int nseq_main(int argc, char *argv[]); +extern int ocsp_main(int argc, char *argv[]); +extern int passwd_main(int argc, char *argv[]); +extern int pkcs7_main(int argc, char *argv[]); +extern int pkcs8_main(int argc, char *argv[]); +extern int pkcs12_main(int argc, char *argv[]); +extern int pkey_main(int argc, char *argv[]); +extern int pkeyparam_main(int argc, char *argv[]); +extern int pkeyutl_main(int argc, char *argv[]); +extern int prime_main(int argc, char *argv[]); +extern int rand_main(int argc, char *argv[]); +extern int req_main(int argc, char *argv[]); +extern int rsa_main(int argc, char *argv[]); +extern int rsautl_main(int argc, char *argv[]); +extern int s_client_main(int argc, char *argv[]); +extern int s_server_main(int argc, char *argv[]); +extern int s_time_main(int argc, char *argv[]); +extern int sess_id_main(int argc, char *argv[]); +extern int smime_main(int argc, char *argv[]); +extern int speed_main(int argc, char *argv[]); +extern int spkac_main(int argc, char *argv[]); +extern int ts_main(int argc, char *argv[]); +extern int verify_main(int argc, char *argv[]); +extern int version_main(int argc, char *argv[]); +extern int x509_main(int argc, char *argv[]); + +#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 + +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, "ciphers", ciphers_main }, +#ifndef OPENSSL_NO_CMS + { FUNC_TYPE_GENERAL, "cms", cms_main }, +#endif + { FUNC_TYPE_GENERAL, "crl2pkcs7", crl2pkcs7_main }, + { FUNC_TYPE_GENERAL, "crl", crl_main }, + { FUNC_TYPE_GENERAL, "dgst", dgst_main }, + { FUNC_TYPE_GENERAL, "enc", enc_main }, +#ifndef OPENSSL_NO_ENGINE + { FUNC_TYPE_GENERAL, "engine", engine_main }, +#endif + { 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_MD4 + { FUNC_TYPE_MD, "md4", dgst_main }, +#endif +#ifndef OPENSSL_NO_MD5 + { FUNC_TYPE_MD, "md5", dgst_main }, +#endif +#ifndef OPENSSL_NO_RMD160 + { FUNC_TYPE_MD, "rmd160", dgst_main }, +#endif +#ifndef OPENSSL_NO_SHA + { FUNC_TYPE_MD, "sha", dgst_main }, +#endif +#ifndef OPENSSL_NO_SHA1 + { FUNC_TYPE_MD, "sha1", 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 +#ifndef OPENSSL_NO_RC5 + { FUNC_TYPE_CIPHER, "rc5", enc_main }, + { FUNC_TYPE_CIPHER, "rc5-cbc", enc_main }, + { FUNC_TYPE_CIPHER, "rc5-ecb", enc_main }, + { FUNC_TYPE_CIPHER, "rc5-cfb", enc_main }, + { FUNC_TYPE_CIPHER, "rc5-ofb", enc_main }, +#endif +#ifdef ZLIB + { FUNC_TYPE_CIPHER, "zlib", enc_main }, +#endif + + { 0, NULL, NULL } +}; diff --git a/usr.bin/openssl/rand.c b/usr.bin/openssl/rand.c new file mode 100644 index 00000000000..0800157a35d --- /dev/null +++ b/usr.bin/openssl/rand.c @@ -0,0 +1,194 @@ +/* $OpenBSD: rand.c,v 1.1 2014/08/26 17:47:25 jsing 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 <ctype.h> +#include <stdio.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/bio.h> +#include <openssl/err.h> +#include <openssl/rand.h> + +/* -out file - write to file + * -base64 - base64 encode output + * -hex - hex encode output + * num - write 'num' bytes + */ + +int rand_main(int, char **); + +int +rand_main(int argc, char **argv) +{ + int i, r, ret = 1; + int badopt; + char *outfile = NULL; + int base64 = 0; + int hex = 0; + BIO *out = NULL; + int num = -1; +#ifndef OPENSSL_NO_ENGINE + char *engine = NULL; +#endif + + badopt = 0; + i = 0; + while (!badopt && argv[++i] != NULL) { + if (strcmp(argv[i], "-out") == 0) { + if ((argv[i + 1] != NULL) && (outfile == NULL)) + outfile = argv[++i]; + else + badopt = 1; + } +#ifndef OPENSSL_NO_ENGINE + else if (strcmp(argv[i], "-engine") == 0) { + if ((argv[i + 1] != NULL) && (engine == NULL)) + engine = argv[++i]; + else + badopt = 1; + } +#endif + else if (strcmp(argv[i], "-base64") == 0) { + if (!base64) + base64 = 1; + else + badopt = 1; + } else if (strcmp(argv[i], "-hex") == 0) { + if (!hex) + hex = 1; + else + badopt = 1; + } else if (isdigit((unsigned char) argv[i][0])) { + if (num < 0) { + r = sscanf(argv[i], "%d", &num); + if (r == 0 || num < 0) + badopt = 1; + } else + badopt = 1; + } else + badopt = 1; + } + + if (hex && base64) + badopt = 1; + + if (num < 0) + badopt = 1; + + if (badopt) { + BIO_printf(bio_err, "Usage: rand [options] num\n"); + BIO_printf(bio_err, "where options are\n"); + BIO_printf(bio_err, "-out file - write to file\n"); +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, "-engine e - use engine e, possibly a hardware device.\n"); +#endif + BIO_printf(bio_err, "-base64 - base64 encode output\n"); + BIO_printf(bio_err, "-hex - hex encode output\n"); + goto err; + } +#ifndef OPENSSL_NO_ENGINE + setup_engine(bio_err, engine, 0); +#endif + + out = BIO_new(BIO_s_file()); + if (out == NULL) + goto err; + if (outfile != NULL) + r = BIO_write_filename(out, outfile); + else { + r = BIO_set_fp(out, stdout, BIO_NOCLOSE | BIO_FP_TEXT); + } + if (r <= 0) + goto err; + + if (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; + r = RAND_bytes(buf, chunk); + if (r <= 0) + goto err; + if (!hex) + BIO_write(out, buf, chunk); + else { + for (i = 0; i < chunk; i++) + BIO_printf(out, "%02x", buf[i]); + } + num -= chunk; + } + if (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/usr.bin/openssl/req.c b/usr.bin/openssl/req.c new file mode 100644 index 00000000000..87599b35e14 --- /dev/null +++ b/usr.bin/openssl/req.c @@ -0,0 +1,1602 @@ +/* $OpenBSD: req.c,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.] + */ + +/* 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 <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include <time.h> + +#include "apps.h" + +#include <openssl/asn1.h> +#include <openssl/bio.h> +#include <openssl/bn.h> +#include <openssl/conf.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/objects.h> +#include <openssl/pem.h> +#include <openssl/x509.h> +#include <openssl/x509v3.h> + +#include <openssl/dsa.h> + +#include <openssl/rsa.h> + +#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 512 +#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 mutlirdn, + 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, + ENGINE * keygen_engine); +static CONF *req_conf = NULL; +static int batch = 0; + +int req_main(int, char **); + +int +req_main(int argc, char **argv) +{ + ENGINE *e = NULL, *gen_eng = NULL; + 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; +#ifndef OPENSSL_NO_ENGINE + char *engine = NULL; +#endif + 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; + + req_conf = NULL; +#ifndef OPENSSL_NO_DES + cipher = EVP_des_ede3_cbc(); +#endif + + 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)); + } +#ifndef OPENSSL_NO_ENGINE + else if (strcmp(*argv, "-engine") == 0) { + if (--argc < 1) + goto bad; + engine = *(++argv); + } else if (strcmp(*argv, "-keygen_engine") == 0) { + if (--argc < 1) + goto bad; + gen_eng = ENGINE_by_id(*(++argv)); + if (gen_eng == NULL) { + BIO_printf(bio_err, "Can't find keygen engine %s\n", *argv); + goto end; + } + } +#endif + 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] <infile >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"); +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, " -engine e use engine e, possibly a hardware device\n"); +#endif + 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, md2, mdc2, 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; + } + ERR_load_crypto_strings(); + 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; + +#ifndef OPENSSL_NO_ENGINE + e = setup_engine(bio_err, engine, 0); +#endif + + if (keyfile != NULL) { + pkey = load_key(bio_err, keyfile, keyform, 0, passin, e, + "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, gen_eng); + 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, gen_eng); + 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); +#ifndef OPENSSL_NO_ENGINE + if (gen_eng) + ENGINE_free(gen_eng); +#endif + 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, + ENGINE * keygen_engine) +{ + 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; + ENGINE *tmpeng; + const EVP_PKEY_ASN1_METHOD *ameth; + + if (p) + len = p - gstr; + else + len = strlen(gstr); + /* + * The lookup of a the string will cover all engines so keep + * a note of the implementation. + */ + + ameth = EVP_PKEY_asn1_find_str(&tmpeng, 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); +#ifndef OPENSSL_NO_ENGINE + if (tmpeng) + ENGINE_finish(tmpeng); +#endif + 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; + ENGINE *tmpeng; + const char *anam; + ameth = EVP_PKEY_asn1_find(&tmpeng, *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 = BUF_strdup(anam); +#ifndef OPENSSL_NO_ENGINE + if (tmpeng) + ENGINE_finish(tmpeng); +#endif + } + if (param) { + gctx = EVP_PKEY_CTX_new(param, keygen_engine); + *pkeylen = EVP_PKEY_bits(param); + EVP_PKEY_free(param); + } else + gctx = EVP_PKEY_CTX_new_id(*pkey_type, keygen_engine); + + 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/usr.bin/openssl/rsa.c b/usr.bin/openssl/rsa.c new file mode 100644 index 00000000000..677e35f8592 --- /dev/null +++ b/usr.bin/openssl/rsa.c @@ -0,0 +1,392 @@ +/* $OpenBSD: rsa.c,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.] + */ + +#include <openssl/opensslconf.h> + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "apps.h" + +#include <openssl/bio.h> +#include <openssl/bn.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/pem.h> +#include <openssl/rsa.h> +#include <openssl/x509.h> + +/* -inform arg - input format - default PEM (one of DER, NET or PEM) + * -outform arg - output format - default PEM + * -in arg - input file - default stdin + * -out arg - output file - default stdout + * -des - encrypt output if PEM format with DES in cbc mode + * -des3 - encrypt output if PEM format + * -idea - encrypt output if PEM format + * -seed - encrypt output if PEM format + * -aes128 - encrypt output if PEM format + * -aes192 - encrypt output if PEM format + * -aes256 - encrypt output if PEM format + * -camellia128 - encrypt output if PEM format + * -camellia192 - encrypt output if PEM format + * -camellia256 - encrypt output if PEM format + * -text - print a text version + * -modulus - print the RSA key modulus + * -check - verify key consistency + * -pubin - Expect a public key in input file. + * -pubout - Output a public key. + */ + +int rsa_main(int, char **); + +int +rsa_main(int argc, char **argv) +{ + ENGINE *e = NULL; + int ret = 1; + RSA *rsa = NULL; + int i, badops = 0, sgckey = 0; + const EVP_CIPHER *enc = NULL; + BIO *out = NULL; + int informat, outformat, text = 0, check = 0, noout = 0; + int pubin = 0, pubout = 0; + char *infile, *outfile, *prog; + char *passargin = NULL, *passargout = NULL; + char *passin = NULL, *passout = NULL; +#ifndef OPENSSL_NO_ENGINE + char *engine = NULL; +#endif + int modulus = 0; + + int pvk_encr = 2; + + 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, "-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, "-passin") == 0) { + if (--argc < 1) + goto bad; + passargin = *(++argv); + } else if (strcmp(*argv, "-passout") == 0) { + if (--argc < 1) + goto bad; + passargout = *(++argv); + } +#ifndef OPENSSL_NO_ENGINE + else if (strcmp(*argv, "-engine") == 0) { + if (--argc < 1) + goto bad; + engine = *(++argv); + } +#endif + else if (strcmp(*argv, "-sgckey") == 0) + sgckey = 1; + else if (strcmp(*argv, "-pubin") == 0) + pubin = 1; + else if (strcmp(*argv, "-pubout") == 0) + pubout = 1; + else if (strcmp(*argv, "-RSAPublicKey_in") == 0) + pubin = 2; + else if (strcmp(*argv, "-RSAPublicKey_out") == 0) + pubout = 2; + else if (strcmp(*argv, "-pvk-strong") == 0) + pvk_encr = 2; + else if (strcmp(*argv, "-pvk-weak") == 0) + pvk_encr = 1; + else if (strcmp(*argv, "-pvk-none") == 0) + pvk_encr = 0; + else if (strcmp(*argv, "-noout") == 0) + noout = 1; + else if (strcmp(*argv, "-text") == 0) + text = 1; + else if (strcmp(*argv, "-modulus") == 0) + modulus = 1; + else if (strcmp(*argv, "-check") == 0) + check = 1; + else if ((enc = EVP_get_cipherbyname(&(argv[0][1]))) == NULL) { + BIO_printf(bio_err, "unknown option %s\n", *argv); + badops = 1; + break; + } + argc--; + argv++; + } + + if (badops) { +bad: + BIO_printf(bio_err, "%s [options] <infile >outfile\n", prog); + BIO_printf(bio_err, "where options are\n"); + BIO_printf(bio_err, " -inform arg input format - one of DER NET PEM\n"); + BIO_printf(bio_err, " -outform arg output format - one of DER NET PEM\n"); + BIO_printf(bio_err, " -in arg input file\n"); + BIO_printf(bio_err, " -sgckey Use IIS SGC key format\n"); + BIO_printf(bio_err, " -passin arg input file pass phrase source\n"); + BIO_printf(bio_err, " -out arg output file\n"); + BIO_printf(bio_err, " -passout arg output file pass phrase source\n"); + BIO_printf(bio_err, " -des encrypt PEM output with cbc des\n"); + BIO_printf(bio_err, " -des3 encrypt PEM output with ede cbc des using 168 bit key\n"); +#ifndef OPENSSL_NO_IDEA + BIO_printf(bio_err, " -idea encrypt PEM output with cbc 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, " -text print the key in text\n"); + BIO_printf(bio_err, " -noout don't print key out\n"); + BIO_printf(bio_err, " -modulus print the RSA key modulus\n"); + BIO_printf(bio_err, " -check verify key consistency\n"); + BIO_printf(bio_err, " -pubin expect a public key in input file\n"); + BIO_printf(bio_err, " -pubout output a public key\n"); +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, " -engine e use engine e, possibly a hardware device.\n"); +#endif + goto end; + } + ERR_load_crypto_strings(); + +#ifndef OPENSSL_NO_ENGINE + e = setup_engine(bio_err, engine, 0); +#endif + + if (!app_passwd(bio_err, passargin, passargout, &passin, &passout)) { + BIO_printf(bio_err, "Error getting passwords\n"); + goto end; + } + if (check && pubin) { + BIO_printf(bio_err, "Only private keys can be checked\n"); + goto end; + } + out = BIO_new(BIO_s_file()); + + { + EVP_PKEY *pkey; + + if (pubin) { + int tmpformat = -1; + if (pubin == 2) { + if (informat == FORMAT_PEM) + tmpformat = FORMAT_PEMRSA; + else if (informat == FORMAT_ASN1) + tmpformat = FORMAT_ASN1RSA; + } else if (informat == FORMAT_NETSCAPE && sgckey) + tmpformat = FORMAT_IISSGC; + else + tmpformat = informat; + + pkey = load_pubkey(bio_err, infile, tmpformat, 1, + passin, e, "Public Key"); + } else + pkey = load_key(bio_err, infile, + (informat == FORMAT_NETSCAPE && sgckey ? + FORMAT_IISSGC : informat), 1, + passin, e, "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 (outfile == NULL) { + BIO_set_fp(out, stdout, BIO_NOCLOSE); + } else { + if (BIO_write_filename(out, outfile) <= 0) { + perror(outfile); + goto end; + } + } + + if (text) + if (!RSA_print(out, rsa, 0)) { + perror(outfile); + ERR_print_errors(bio_err); + goto end; + } + if (modulus) { + BIO_printf(out, "Modulus="); + BN_print(out, rsa->n); + BIO_printf(out, "\n"); + } + if (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 (noout) { + ret = 0; + goto end; + } + BIO_printf(bio_err, "writing RSA key\n"); + if (outformat == FORMAT_ASN1) { + if (pubout || pubin) { + if (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 (outformat == FORMAT_NETSCAPE) { + unsigned char *p, *pp; + int size; + + i = 1; + size = i2d_RSA_NET(rsa, NULL, NULL, sgckey); + if ((p = malloc(size)) == NULL) { + BIO_printf(bio_err, "Memory allocation failure\n"); + goto end; + } + pp = p; + i2d_RSA_NET(rsa, &p, NULL, sgckey); + BIO_write(out, (char *) pp, size); + free(pp); + } +#endif + else if (outformat == FORMAT_PEM) { + if (pubout || pubin) { + if (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, + enc, NULL, 0, NULL, passout); +#if !defined(OPENSSL_NO_DSA) && !defined(OPENSSL_NO_RC4) + } else if (outformat == FORMAT_MSBLOB || outformat == FORMAT_PVK) { + EVP_PKEY *pk; + pk = EVP_PKEY_new(); + EVP_PKEY_set1_RSA(pk, rsa); + if (outformat == FORMAT_PVK) + i = i2b_PVK_bio(out, pk, pvk_encr, 0, passout); + else if (pubin || 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: + if (out != NULL) + BIO_free_all(out); + if (rsa != NULL) + RSA_free(rsa); + free(passin); + free(passout); + + return (ret); +} diff --git a/usr.bin/openssl/rsautl.c b/usr.bin/openssl/rsautl.c new file mode 100644 index 00000000000..7c83f1a82c1 --- /dev/null +++ b/usr.bin/openssl/rsautl.c @@ -0,0 +1,341 @@ +/* $OpenBSD: rsautl.c,v 1.1 2014/08/26 17:47:25 jsing 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 <openssl/opensslconf.h> + + +#include <string.h> + +#include "apps.h" + +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/rsa.h> + +#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 **); + +int +rsautl_main(int argc, char **argv) +{ + ENGINE *e = NULL; + BIO *in = NULL, *out = NULL; + char *infile = NULL, *outfile = NULL; +#ifndef OPENSSL_NO_ENGINE + char *engine = NULL; +#endif + 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; + + argc--; + argv++; + + ERR_load_crypto_strings(); + OpenSSL_add_all_algorithms(); + 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)); +#ifndef OPENSSL_NO_ENGINE + } else if (!strcmp(*argv, "-engine")) { + if (--argc < 1) + badarg = 1; + else + engine = *(++argv); +#endif + } 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; + } +#ifndef OPENSSL_NO_ENGINE + e = setup_engine(bio_err, engine, 0); +#endif + 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, e, "Private Key"); + break; + + case KEY_PUBKEY: + pkey = load_pubkey(bio_err, keyfile, keyform, 0, + NULL, e, "Public Key"); + break; + + case KEY_CERT: + x = load_cert(bio_err, keyfile, keyform, + NULL, e, "Certificate"); + if (x) { + pkey = X509_get_pubkey(x); + X509_free(x); + } + break; + } + + if (!pkey) { + return 1; + } + 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); + rsa_out = malloc(keysize); + + /* 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"); +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, "-engine e use engine e, possibly a hardware device.\n"); + BIO_printf(bio_err, "-passin arg pass phrase source\n"); +#endif + +} + diff --git a/usr.bin/openssl/s_apps.h b/usr.bin/openssl/s_apps.h new file mode 100644 index 00000000000..dd4b733afb2 --- /dev/null +++ b/usr.bin/openssl/s_apps.h @@ -0,0 +1,147 @@ +/* $OpenBSD: s_apps.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.] + */ +/* ==================================================================== + * 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 <sys/types.h> +#include <openssl/opensslconf.h> + +#define PORT 4433 +#define PORT_STR "4433" +#define PROTOCOL "tcp" + +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 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/usr.bin/openssl/s_cb.c b/usr.bin/openssl/s_cb.c new file mode 100644 index 00000000000..2e00abe7f15 --- /dev/null +++ b/usr.bin/openssl/s_cb.c @@ -0,0 +1,854 @@ +/* $OpenBSD: s_cb.c,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.] + */ +/* ==================================================================== + * 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 <sys/socket.h> + +#include <netinet/in.h> + +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/err.h> +#include <openssl/rand.h> +#include <openssl/ssl.h> +#include <openssl/x509.h> + +#include "s_apps.h" + +#define COOKIE_SECRET_LENGTH 16 + +int verify_depth = 0; +int verify_error = X509_V_OK; +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, "<no cert>\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; + verify_error = X509_V_OK; + } else { + ok = 0; + verify_error = X509_V_ERR_CERT_CHAIN_TOO_LONG; + } + } + switch (err) { + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: + BIO_puts(bio_err, "issuer= "); + 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="); + 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="); + 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; +} + +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; + case DTLS1_BAD_VER: + str_version = "DTLS 1.0 (bad) "; + 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 || version == DTLS1_BAD_VER) { + 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; +#if 0 + if (num > 16) + num = 16; +#endif + 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) { + if (!RAND_bytes(cookie_secret, COOKIE_SECRET_LENGTH)) { + BIO_printf(bio_err, + "error setting random cookie secret\n"); + return 0; + } + 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/usr.bin/openssl/s_client.c b/usr.bin/openssl/s_client.c new file mode 100644 index 00000000000..f35624bacac --- /dev/null +++ b/usr.bin/openssl/s_client.c @@ -0,0 +1,1507 @@ +/* $OpenBSD: s_client.c,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.] + */ +/* ==================================================================== + * 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 <sys/types.h> +#include <sys/ioctl.h> +#include <sys/select.h> +#include <sys/socket.h> + +#include <netinet/in.h> + +#include <assert.h> +#include <ctype.h> +#include <limits.h> +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include <unistd.h> + +#include "apps.h" + +#include <openssl/bn.h> +#include <openssl/err.h> +#include <openssl/ocsp.h> +#include <openssl/pem.h> +#include <openssl/rand.h> +#include <openssl/ssl.h> +#include <openssl/x509.h> + +#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 + +extern int verify_depth; +extern int verify_error; +extern int verify_return_error; + +static int c_nbio = 0; +static int c_Pause = 0; +static int c_debug = 0; +#ifndef OPENSSL_NO_TLSEXT +static int c_tlsextdebug = 0; +static int c_status_req = 0; +#endif +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); +#ifndef OPENSSL_NO_TLSEXT +static int ocsp_resp_cb(SSL * s, void *arg); +#endif +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, " -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, " -ssl3 - just use SSLv3\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"); +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, " -engine id - Initialise and use the specified engine\n"); +#endif + 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"); +#ifndef OPENSSL_NO_TLSEXT + 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"); +#ifndef OPENSSL_NO_NEXTPROTONEG + BIO_printf(bio_err, " -nextprotoneg arg - enable NPN extension, considering named protocols supported (comma-separated list)\n"); +#endif +#endif +#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"); +} + +#ifndef OPENSSL_NO_TLSEXT + +/* 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 + +#ifndef OPENSSL_NO_NEXTPROTONEG +/* 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; +} +#endif /* ndef OPENSSL_NO_NEXTPROTONEG */ +#endif + +enum { + PROTO_OFF = 0, + PROTO_SMTP, + PROTO_LMTP, + PROTO_POP3, + PROTO_IMAP, + PROTO_FTP, + PROTO_XMPP +}; + +int s_client_main(int, char **); + +int +s_client_main(int argc, char **argv) +{ + unsigned int off = 0, clr = 0; + SSL *con = NULL; + int s, k, width, state = 0, af = AF_UNSPEC; + char *cbuf = NULL, *sbuf = NULL, *mbuf = NULL; + int cbuf_len, cbuf_off; + int sbuf_len, sbuf_off; + fd_set readfds, writefds; + char *port = PORT_STR; + int full_log = 1; + char *host = SSL_HOST_NAME; + 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, *timeoutp; + const char *errstr = NULL; +#ifndef OPENSSL_NO_ENGINE + char *engine_id = NULL; + char *ssl_client_engine_id = NULL; + ENGINE *ssl_client_engine = NULL; +#endif + ENGINE *e = NULL; +#ifndef OPENSSL_NO_TLSEXT + char *servername = NULL; + tlsextctx tlsextcbp = + {NULL, 0}; +#ifndef OPENSSL_NO_NEXTPROTONEG + const char *next_proto_neg_in = NULL; +#endif +#endif + char *sess_in = NULL; + char *sess_out = NULL; + struct sockaddr peer; + int peerlen = sizeof(peer); + int enable_timeouts = 0; + long socket_mtu = 0; + + 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; + verify_error = X509_V_OK; + 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; + if (!extract_host_port(*(++argv), &host, NULL, &port)) + goto bad; + } 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; +#ifndef OPENSSL_NO_TLSEXT + else if (strcmp(*argv, "-tlsextdebug") == 0) + c_tlsextdebug = 1; + else if (strcmp(*argv, "-status") == 0) + c_status_req = 1; +#endif + 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, "-ssl3") == 0) + meth = SSLv3_client_method(); + 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; + } +#ifndef OPENSSL_NO_TLSEXT + else if (strcmp(*argv, "-no_ticket") == 0) { + off |= SSL_OP_NO_TICKET; + } +#ifndef OPENSSL_NO_NEXTPROTONEG + else if (strcmp(*argv, "-nextprotoneg") == 0) { + if (--argc < 1) + goto bad; + next_proto_neg_in = *(++argv); + } +#endif +#endif + 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; + } +#ifndef OPENSSL_NO_ENGINE + else if (strcmp(*argv, "-engine") == 0) { + if (--argc < 1) + goto bad; + engine_id = *(++argv); + } else if (strcmp(*argv, "-ssl_client_engine") == 0) { + if (--argc < 1) + goto bad; + ssl_client_engine_id = *(++argv); + } +#endif + else if (strcmp(*argv, "-4") == 0) { + af = AF_INET; + } else if (strcmp(*argv, "-6") == 0) { + af = AF_INET6; + } +#ifndef OPENSSL_NO_TLSEXT + else if (strcmp(*argv, "-servername") == 0) { + if (--argc < 1) + goto bad; + servername = *(++argv); + /* meth=TLSv1_client_method(); */ + } +#endif +#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) { + const char *errstr; + + 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 + sc_usage(); + goto end; + } + +#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) + 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; +#endif + +#ifndef OPENSSL_NO_ENGINE + e = setup_engine(bio_err, engine_id, 1); + if (ssl_client_engine_id) { + ssl_client_engine = ENGINE_by_id(ssl_client_engine_id); + if (!ssl_client_engine) { + BIO_printf(bio_err, + "Error getting client auth engine\n"); + goto end; + } + } +#endif + 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, e, + "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, e, "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_ENGINE + if (ssl_client_engine) { + if (!SSL_CTX_set_client_cert_engine(ctx, ssl_client_engine)) { + BIO_puts(bio_err, "Error setting client auth engine\n"); + ERR_print_errors(bio_err); + ENGINE_free(ssl_client_engine); + goto end; + } + ENGINE_free(ssl_client_engine); + } +#endif + +#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 !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) + if (next_proto.data) + SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &next_proto); +#endif + + 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 ((!SSL_CTX_load_verify_locations(ctx, CAfile, CApath)) || + (!SSL_CTX_set_default_verify_paths(ctx))) { + /* + * BIO_printf(bio_err,"error setting default verify + * locations\n"); + */ + ERR_print_errors(bio_err); + /* goto end; */ + } +#ifndef OPENSSL_NO_TLSEXT + 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); + } +#endif + + 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); + } +#ifndef OPENSSL_NO_TLSEXT + 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; + } + } +#endif +/* 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); + shutdown(s, SHUT_RD); + close(s); + goto end; + } + BIO_printf(bio_c_out, "CONNECTED(%08X)\n", s); + + if (c_nbio) { + unsigned long l = 1; + BIO_printf(bio_c_out, "turning on non blocking io\n"); + if (BIO_socket_ioctl(s, FIONBIO, &l) < 0) { + 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); + } +#ifndef OPENSSL_NO_TLSEXT + 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); + } +#endif + + SSL_set_bio(con, sbio, sbio); + SSL_set_connect_state(con); + + /* ok, lets connect */ + width = SSL_get_fd(con) + 1; + + 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); + } + if (starttls_proto == PROTO_XMPP) { + int seen = 0; + BIO_printf(sbio, "<stream:stream " + "xmlns:stream='http://etherx.jabber.org/streams' " + "xmlns='jabber:client' to='%s' version='1.0'>", host); + seen = BIO_read(sbio, mbuf, BUFSIZZ); + mbuf[seen] = 0; + while (!strstr(mbuf, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'")) { + if (strstr(mbuf, "/stream:features>")) + goto shut; + seen = BIO_read(sbio, mbuf, BUFSIZZ); + mbuf[seen] = 0; + } + BIO_printf(sbio, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"); + seen = BIO_read(sbio, sbuf, BUFSIZZ); + sbuf[seen] = 0; + if (!strstr(sbuf, "<proceed")) + goto shut; + mbuf[0] = 0; + } + for (;;) { + FD_ZERO(&readfds); + FD_ZERO(&writefds); + + if ((SSL_version(con) == DTLS1_VERSION) && + DTLSv1_get_timeout(con, &timeout)) + timeoutp = &timeout; + else + timeoutp = NULL; + + if (SSL_in_init(con) && !SSL_total_renegotiations(con)) { + in_init = 1; + tty_on = 0; + } else { + tty_on = 1; + if (in_init) { + in_init = 0; + if (sess_out) { + BIO *stmp = BIO_new_file(sess_out, "w"); + if (stmp) { + PEM_write_bio_SSL_SESSION(stmp, SSL_get_session(con)); + BIO_free(stmp); + } else + BIO_printf(bio_err, "Error writing session file %s\n", sess_out); + } + print_stuff(bio_c_out, con, full_log); + if (full_log > 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); + + /* XXX should add tests for fd_set overflow */ + + if (!ssl_pending) { + if (tty_on) { + if (read_tty) + FD_SET(fileno(stdin), &readfds); + if (write_tty) + FD_SET(fileno(stdout), &writefds); + } + if (read_ssl) + FD_SET(SSL_get_fd(con), &readfds); + if (write_ssl) + FD_SET(SSL_get_fd(con), &writefds); +/* printf("mode tty(%d %d%d) ssl(%d%d)\n", + tty_on,read_tty,write_tty,read_ssl,write_ssl);*/ + + i = select(width, &readfds, &writefds, + NULL, timeoutp); + 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 && FD_ISSET(SSL_get_fd(con), &writefds)) { + 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 && FD_ISSET(fileno(stdout), &writefds)) { + 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 || FD_ISSET(SSL_get_fd(con), &readfds)) { +#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 (FD_ISSET(fileno(stdin), &readfds)) { + 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); + } +#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) + free(next_proto.data); +#endif + 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) { + OPENSSL_cleanse(cbuf, BUFSIZZ); + free(cbuf); + } + if (sbuf != NULL) { + OPENSSL_cleanse(sbuf, BUFSIZZ); + free(sbuf); + } + if (mbuf != NULL) { + OPENSSL_cleanse(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); + } + 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 !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) + 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); + } +#endif + +#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); +} + +#ifndef OPENSSL_NO_TLSEXT + +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; +} + +#endif diff --git a/usr.bin/openssl/s_server.c b/usr.bin/openssl/s_server.c new file mode 100644 index 00000000000..7fa875c661c --- /dev/null +++ b/usr.bin/openssl/s_server.c @@ -0,0 +1,2154 @@ +/* $OpenBSD: s_server.c,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.] + */ +/* ==================================================================== + * 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 <sys/types.h> +#include <sys/ioctl.h> +#include <sys/select.h> +#include <sys/socket.h> + +#include <assert.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include <unistd.h> + +#include "apps.h" + +#include <openssl/bn.h> +#include <openssl/err.h> +#include <openssl/lhash.h> +#include <openssl/ocsp.h> +#include <openssl/pem.h> +#include <openssl/rand.h> +#include <openssl/ssl.h> +#include <openssl/x509.h> + +#ifndef OPENSSL_NO_DH +#include <openssl/dh.h> +#endif + +#include <openssl/rsa.h> + +#include "s_apps.h" +#include "timeouts.h" + +static RSA *tmp_rsa_cb(SSL * s, int is_export, int keylength); +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); +static DH *get_dh512(void); +#endif + +static void s_server_init(void); + +#ifndef OPENSSL_NO_DH +static unsigned char dh512_p[] = { + 0xDA, 0x58, 0x3C, 0x16, 0xD9, 0x85, 0x22, 0x89, 0xD0, 0xE4, 0xAF, 0x75, + 0x6F, 0x4C, 0xCA, 0x92, 0xDD, 0x4B, 0xE5, 0x33, 0xB8, 0x04, 0xFB, 0x0F, + 0xED, 0x94, 0xEF, 0x9C, 0x8A, 0x44, 0x03, 0xED, 0x57, 0x46, 0x50, 0xD3, + 0x69, 0x99, 0xDB, 0x29, 0xD7, 0x76, 0x27, 0x6B, 0xA2, 0xD3, 0xD4, 0x12, + 0xE2, 0x18, 0xF4, 0xDD, 0x1E, 0x08, 0x4C, 0xF6, 0xD8, 0x00, 0x3E, 0x7C, + 0x47, 0x74, 0xE8, 0x33, +}; +static unsigned char dh512_g[] = { + 0x02, +}; + +static DH * +get_dh512(void) +{ + DH *dh = NULL; + + if ((dh = DH_new()) == NULL) + return (NULL); + dh->p = BN_bin2bn(dh512_p, sizeof(dh512_p), NULL); + dh->g = BN_bin2bn(dh512_g, sizeof(dh512_g), NULL); + if ((dh->p == NULL) || (dh->g == NULL)) + return (NULL); + return (dh); +} +#endif + + +/* 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" +#ifndef OPENSSL_NO_TLSEXT +#define TEST_CERT2 "server2.pem" +#endif + +extern int verify_depth, verify_return_error; + +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; +#ifndef OPENSSL_NO_TLSEXT +static const char *s_cert_file2 = TEST_CERT2, *s_key_file2 = NULL; +#endif +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; +#ifndef OPENSSL_NO_TLSEXT +static SSL_CTX *ctx2 = NULL; +#endif +static int www = 0; + +static BIO *bio_s_out = NULL; +static int s_debug = 0; +#ifndef OPENSSL_NO_TLSEXT +static int s_tlsextdebug = 0; +static int s_tlsextstatus = 0; +static int cert_status_cb(SSL * s, void *arg); +#endif +static int s_msg = 0; +static int s_quiet = 0; + +static char *keymatexportlabel = NULL; +static int keymatexportlen = 20; + +static int hack = 0; +#ifndef OPENSSL_NO_ENGINE +static char *engine_id = NULL; +#endif +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; +#ifndef OPENSSL_NO_TLSEXT + s_cert_file2 = TEST_CERT2; + s_key_file2 = NULL; + ctx2 = NULL; +#endif + s_nbio = 0; + s_nbio_test = 0; + ctx = NULL; + www = 0; + + bio_s_out = NULL; + s_debug = 0; + s_msg = 0; + s_quiet = 0; + hack = 0; +#ifndef OPENSSL_NO_ENGINE + engine_id = NULL; +#endif +} + +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, DER or ENGINE) 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, DER or ENGINE) 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, " -no_tmp_rsa - Do not generate a tmp RSA key\n"); + BIO_printf(bio_err, " -ssl3 - Just talk SSLv3\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 /<path> HTTP/1.0' with file ./<path>\n"); + BIO_printf(bio_err, " -HTTP - Respond to a 'GET /<path> HTTP/1.0' with file ./<path>\n"); + BIO_printf(bio_err, " with the assumption it contains a complete HTTP response.\n"); +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, " -engine id - Initialise and use the specified engine\n"); +#endif + BIO_printf(bio_err, " -id_prefix arg - Generate SSL/TLS session IDs prefixed by 'arg'\n"); +#ifndef OPENSSL_NO_TLSEXT + 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"); +#ifndef OPENSSL_NO_NEXTPROTONEG + BIO_printf(bio_err, " -nextprotoneg arg - set the advertised protocols for the NPN extension (comma-separated list)\n"); +#endif +#ifndef OPENSSL_NO_SRTP + BIO_printf(bio_err, " -use_srtp profiles - Offer SRTP key management with a colon-separated profile list\n"); +#endif +#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; + +#ifndef OPENSSL_NO_TLSEXT + +/* 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; +} + +#ifndef OPENSSL_NO_NEXTPROTONEG +/* 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; +} +#endif /* ndef OPENSSL_NO_NEXTPROTONEG */ + + +#endif + +int s_server_main(int, char **); + +#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_tmp_rsa = 0, no_dhe = 0, no_ecdhe = 0, nocert = 0; + int state = 0; + const SSL_METHOD *meth = NULL; + int socket_type = SOCK_STREAM; + ENGINE *e = NULL; + 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; +#ifndef OPENSSL_NO_TLSEXT + EVP_PKEY *s_key2 = NULL; + X509 *s_cert2 = NULL; + tlsextctx tlsextcbp = {NULL, NULL, SSL_TLSEXT_ERR_ALERT_WARNING}; +#ifndef OPENSSL_NO_NEXTPROTONEG + const char *next_proto_neg_in = NULL; + tlsextnextprotoctx next_proto; +#endif +#endif + 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; + } +#ifndef OPENSSL_NO_TLSEXT + 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; + } + } +#endif + else if (strcmp(*argv, "-msg") == 0) { + s_msg = 1; + } else if (strcmp(*argv, "-hack") == 0) { + hack = 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_tmp_rsa = 1; + } 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; + } +#ifndef OPENSSL_NO_TLSEXT + else if (strcmp(*argv, "-no_ticket") == 0) { + off |= SSL_OP_NO_TICKET; + } +#endif + else if (strcmp(*argv, "-ssl3") == 0) { + meth = SSLv3_server_method(); + } 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); + } +#ifndef OPENSSL_NO_ENGINE + else if (strcmp(*argv, "-engine") == 0) { + if (--argc < 1) + goto bad; + engine_id = *(++argv); + } +#endif +#ifndef OPENSSL_NO_TLSEXT + 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); + } +#ifndef OPENSSL_NO_NEXTPROTONEG + else if (strcmp(*argv, "-nextprotoneg") == 0) { + if (--argc < 1) + goto bad; + next_proto_neg_in = *(++argv); + } +#endif +#endif +#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; + } + +#ifndef OPENSSL_NO_ENGINE + e = setup_engine(bio_err, engine_id, 1); +#endif + + 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; +#ifndef OPENSSL_NO_TLSEXT + if (s_key_file2 == NULL) + s_key_file2 = s_cert_file2; +#endif + + if (nocert == 0) { + s_key = load_key(bio_err, s_key_file, s_key_format, 0, pass, e, + "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, e, "server certificate file"); + + if (!s_cert) { + ERR_print_errors(bio_err); + goto end; + } +#ifndef OPENSSL_NO_TLSEXT + if (tlsextcbp.servername) { + s_key2 = load_key(bio_err, s_key_file2, s_key_format, 0, pass, e, + "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, e, "second server certificate file"); + + if (!s_cert2) { + ERR_print_errors(bio_err); + goto end; + } + } +#endif + } +#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) + 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; + } +#endif + + + 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, e, + "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, e, "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; +#ifndef OPENSSL_NO_TLSEXT + s_cert_file2 = NULL; + s_key_file2 = NULL; +#endif + } + 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); + if (hack) + SSL_CTX_set_options(ctx, SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG); + 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); + +#ifndef OPENSSL_NO_TLSEXT + 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); + if (hack) + SSL_CTX_set_options(ctx2, SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG); + 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); + } +#ifndef OPENSSL_NO_NEXTPROTONEG + if (next_proto.data) + SSL_CTX_set_next_protos_advertised_cb(ctx, next_proto_cb, &next_proto); +#endif +#endif + +#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 default temp DH parameters\n"); + dh = get_dh512(); + } + (void) BIO_flush(bio_s_out); + + SSL_CTX_set_tmp_dh(ctx, dh); +#ifndef OPENSSL_NO_TLSEXT + if (ctx2) { + if (!dhfile) { + DH *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; + } + } + SSL_CTX_set_tmp_dh(ctx2, dh); + } +#endif + 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); +#ifndef OPENSSL_NO_TLSEXT + if (ctx2) + SSL_CTX_set_tmp_ecdh(ctx2, ecdh); +#endif + EC_KEY_free(ecdh); + } + + if (!set_cert_key_stuff(ctx, s_cert, s_key)) + goto end; +#ifndef OPENSSL_NO_TLSEXT + if (ctx2 && !set_cert_key_stuff(ctx2, s_cert2, s_key2)) + goto end; +#endif + if (s_dcert != NULL) { + if (!set_cert_key_stuff(ctx, s_dcert, s_dkey)) + goto end; + } + if (!no_tmp_rsa) { + SSL_CTX_set_tmp_rsa_callback(ctx, tmp_rsa_cb); +#ifndef OPENSSL_NO_TLSEXT + if (ctx2) + SSL_CTX_set_tmp_rsa_callback(ctx2, tmp_rsa_cb); +#endif + } + + + 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; + } +#ifndef OPENSSL_NO_TLSEXT + 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; + } +#endif + } + 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); + +#ifndef OPENSSL_NO_TLSEXT + 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); + } +#endif + + if (CAfile != NULL) { + SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(CAfile)); +#ifndef OPENSSL_NO_TLSEXT + if (ctx2) + SSL_CTX_set_client_CA_list(ctx2, SSL_load_client_CA_file(CAfile)); +#endif + } + 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); +#ifndef OPENSSL_NO_TLSEXT + 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); +#endif + 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; + fd_set readfds; + int ret = 1, width; + int k, i; + unsigned long l; + SSL *con = NULL; + BIO *sbio; + struct timeval timeout; + struct timeval *timeoutp; + + if ((buf = malloc(bufsize)) == NULL) { + BIO_printf(bio_err, "out of memory\n"); + goto err; + } + if (s_nbio) { + unsigned long sl = 1; + + if (!s_quiet) + BIO_printf(bio_err, "turning on non blocking io\n"); + if (BIO_socket_ioctl(s, FIONBIO, &sl) < 0) + ERR_print_errors(bio_err); + } + + if (con == NULL) { + con = SSL_new(ctx); +#ifndef OPENSSL_NO_TLSEXT + 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); + } +#endif + 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); + } +#ifndef OPENSSL_NO_TLSEXT + if (s_tlsextdebug) { + SSL_set_tlsext_debug_callback(con, tlsext_cb); + SSL_set_tlsext_debug_arg(con, bio_s_out); + } +#endif + + width = s + 1; + for (;;) { + int read_from_terminal; + int read_from_sslcon; + + read_from_terminal = 0; + read_from_sslcon = SSL_pending(con); + + if (!read_from_sslcon) { + FD_ZERO(&readfds); + FD_SET(fileno(stdin), &readfds); + FD_SET(s, &readfds); + if ((SSL_version(con) == DTLS1_VERSION) && + DTLSv1_get_timeout(con, &timeout)) + timeoutp = &timeout; + else + timeoutp = NULL; + + i = select(width, &readfds, NULL, NULL, timeoutp); + + if ((SSL_version(con) == DTLS1_VERSION) && DTLSv1_handle_timeout(con) > 0) { + BIO_printf(bio_err, "TIMEOUT occured\n"); + } + if (i <= 0) + continue; + if (FD_ISSET(fileno(stdin), &readfds)) + read_from_terminal = 1; + if (FD_ISSET(s, &readfds)) + 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; + /* + * strcpy(buf,"server side + * 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; + /* + * strcpy(buf,"server side + * 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) { + OPENSSL_cleanse(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]; +#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) + const unsigned char *next_proto_neg; + unsigned next_proto_neg_len; +#endif + 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)"); + +#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) + 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"); + } +#endif +#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"); + if (SSL_ctrl(con, SSL_CTRL_GET_FLAGS, 0, NULL) & + TLS1_FLAGS_TLS_PADDING_BUG) + BIO_printf(bio_s_out, + "Peer has incorrect TLSv1 block padding\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) { + unsigned long sl = 1; + + if (!s_quiet) + BIO_printf(bio_err, "turning on non blocking io\n"); + if (BIO_socket_ioctl(s, FIONBIO, &sl) < 0) + 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; +#ifndef OPENSSL_NO_TLSEXT + if (s_tlsextdebug) { + SSL_set_tlsext_debug_callback(con, tlsext_cb); + SSL_set_tlsext_debug_arg(con, bio_s_out); + } +#endif + 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 (;;) { + if (hack) { + i = SSL_accept(con); + switch (SSL_get_error(con, i)) { + case SSL_ERROR_NONE: + break; + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_X509_LOOKUP: + continue; + case SSL_ERROR_SYSCALL: + case SSL_ERROR_SSL: + case SSL_ERROR_ZERO_RETURN: + ret = 1; + goto err; + /* break; */ + } + + SSL_renegotiate(con); + SSL_write(con, NULL, 0); + } + 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, "<HTML><BODY BGCOLOR=\"#ffffff\">\n"); + BIO_puts(io, "<pre>\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, "</BODY></HTML>\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"); + + if (buf != NULL) + free(buf); + if (io != NULL) + BIO_free_all(io); +/* if (ssl_bio != NULL) BIO_free(ssl_bio);*/ + return (ret); +} + +static RSA * +tmp_rsa_cb(SSL * s, int is_export, int keylength) +{ + BIGNUM *bn = NULL; + static RSA *rsa_tmp = NULL; + + if (!rsa_tmp && ((bn = BN_new()) == NULL)) + BIO_printf(bio_err, "Allocation error in generating RSA key\n"); + if (!rsa_tmp && bn) { + if (!s_quiet) { + BIO_printf(bio_err, "Generating temp (%d bit) RSA key...", keylength); + (void) BIO_flush(bio_err); + } + if (!BN_set_word(bn, RSA_F4) || ((rsa_tmp = RSA_new()) == NULL) || + !RSA_generate_key_ex(rsa_tmp, keylength, bn, NULL)) { + if (rsa_tmp) + RSA_free(rsa_tmp); + rsa_tmp = NULL; + } + if (!s_quiet) { + BIO_printf(bio_err, "\n"); + (void) BIO_flush(bio_err); + } + BN_free(bn); + } + return (rsa_tmp); +} + +#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 { + RAND_pseudo_bytes(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/usr.bin/openssl/s_socket.c b/usr.bin/openssl/s_socket.c new file mode 100644 index 00000000000..48af178a231 --- /dev/null +++ b/usr.bin/openssl/s_socket.c @@ -0,0 +1,351 @@ +/* $OpenBSD: s_socket.c,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.] + */ + +#include <sys/socket.h> + +#include <netinet/in.h> + +#include <errno.h> +#include <netdb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "apps.h" + +#include <openssl/ssl.h> + +#include "s_apps.h" + +static int ssl_sock_init(void); +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); + +#define SOCKET_PROTOCOL IPPROTO_TCP + +static int +ssl_sock_init(void) +{ + return (1); +} + +int +init_client(int *sock, char *host, char *port, int type, int af) +{ + struct addrinfo hints, *ai_top, *ai; + int i, s; + + if (!ssl_sock_init()) + return (0); + + 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"); + close(s); + return (0); + } + } + if ((i = connect(s, ai->ai_addr, ai->ai_addrlen)) == 0) { + *sock = s; + freeaddrinfo(ai_top); + return (1); + } + close(s); + } + + perror("connect"); + 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; + + if (!ssl_sock_init()) + return (0); + + 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, SOCKET_PROTOCOL); + 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; + setsockopt(s, SOL_SOCKET, SO_REUSEADDR, + (void *) &j, sizeof j); + } +#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; */ + + if (!ssl_sock_init()) + return (0); + +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/usr.bin/openssl/s_time.c b/usr.bin/openssl/s_time.c new file mode 100644 index 00000000000..f8c104b7d7d --- /dev/null +++ b/usr.bin/openssl/s_time.c @@ -0,0 +1,587 @@ +/* $OpenBSD: s_time.c,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.] + */ + +#define NO_SHUTDOWN + +/*----------------------------------------- + s_time - SSL client connection timer program + Written and donated by Larry Streepy <streepy@healthcare.com> + -----------------------------------------*/ + +#include <sys/select.h> +#include <sys/socket.h> + +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include <unistd.h> + +#include "apps.h" + +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/ssl.h> +#include <openssl/x509.h> + +#include "s_apps.h" + +#define SSL_CONNECT_NAME "localhost:4433" + + /*#define TEST_CERT "client.pem" *//* no default cert. */ + +#define BUFSIZZ 1024*10 + +#define MYBUFSIZ 1024*8 + +#undef min +#undef max +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#define max(a,b) (((a) > (b)) ? (a) : (b)) + +#define SECONDS 30 +extern int verify_depth; +extern int verify_error; + +static void s_time_usage(void); +static int parseArgs(int argc, char **argv); +static SSL *doConnection(SSL * scon); +static void s_time_init(void); + +/*********************************************************************** + * Static data declarations + */ + +/* static char *port=PORT_STR;*/ +static char *host = SSL_CONNECT_NAME; +static char *t_cert_file = NULL; +static char *t_key_file = NULL; +static char *CApath = NULL; +static char *CAfile = NULL; +static char *tm_cipher = NULL; +static int tm_verify = SSL_VERIFY_NONE; +static int maxTime = SECONDS; +static SSL_CTX *tm_ctx = NULL; +static const SSL_METHOD *s_time_meth = NULL; +static char *s_www_path = NULL; +static long bytes_read = 0; +static int st_bugs = 0; +static int perform = 0; +static int t_nbio = 0; + +static void +s_time_init(void) +{ + host = SSL_CONNECT_NAME; + t_cert_file = NULL; + t_key_file = NULL; + CApath = NULL; + CAfile = NULL; + tm_cipher = NULL; + tm_verify = SSL_VERIFY_NONE; + maxTime = SECONDS; + tm_ctx = NULL; + s_time_meth = NULL; + s_www_path = NULL; + bytes_read = 0; + st_bugs = 0; + perform = 0; + + t_nbio = 0; +} + +/*********************************************************************** + * usage - display usage message + */ +static void +s_time_usage(void) +{ + static const char umsg[] = "\ +-time arg - max number of seconds to collect data, default %d\n\ +-verify arg - turn on peer certificate verification, arg == depth\n\ +-cert arg - certificate file to use, PEM format assumed\n\ +-key arg - RSA file to use, PEM format assumed, key is in cert file\n\ + file if not specified by this option\n\ +-CApath arg - PEM format directory of CA's\n\ +-CAfile arg - PEM format file of CA's\n\ +-cipher - preferred cipher to use, play with 'openssl ciphers'\n\n"; + + printf("usage: s_time <args>\n\n"); + + printf("-connect host:port - host:port to connect to (default is %s)\n", SSL_CONNECT_NAME); + printf("-nbio - Run with non-blocking IO\n"); + printf("-ssl2 - Just use SSLv2\n"); + printf("-ssl3 - Just use SSLv3\n"); + printf("-bugs - Turn on SSL bug compatibility\n"); + printf("-new - Just time new connections\n"); + printf("-reuse - Just time connection reuse\n"); + printf("-www page - Retrieve 'page' from the site\n"); + printf(umsg, SECONDS); +} + +/*********************************************************************** + * parseArgs - Parse command line arguments and initialize data + * + * Returns 0 if ok, -1 on bad args + */ +static int +parseArgs(int argc, char **argv) +{ + int badop = 0; + const char *errstr; + + verify_depth = 0; + verify_error = X509_V_OK; + + argc--; + argv++; + + while (argc >= 1) { + if (strcmp(*argv, "-connect") == 0) { + if (--argc < 1) + goto bad; + host = *(++argv); + } +#if 0 + else 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); + } +#endif + else if (strcmp(*argv, "-reuse") == 0) + perform = 2; + else if (strcmp(*argv, "-new") == 0) + perform = 1; + else if (strcmp(*argv, "-verify") == 0) { + const char *errstr; + + tm_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, "-cert") == 0) { + + if (--argc < 1) + goto bad; + t_cert_file = *(++argv); + + } else if (strcmp(*argv, "-key") == 0) { + + if (--argc < 1) + goto bad; + t_key_file = *(++argv); + + } 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, "-cipher") == 0) { + + if (--argc < 1) + goto bad; + tm_cipher = *(++argv); + } + else if (strcmp(*argv, "-nbio") == 0) { + t_nbio = 1; + } + else if (strcmp(*argv, "-www") == 0) { + if (--argc < 1) + goto bad; + s_www_path = *(++argv); + if (strlen(s_www_path) > MYBUFSIZ - 100) { + BIO_printf(bio_err, "-www option too long\n"); + badop = 1; + } + } else if (strcmp(*argv, "-bugs") == 0) + st_bugs = 1; + else if (strcmp(*argv, "-ssl3") == 0) + s_time_meth = SSLv3_client_method(); + else if (strcmp(*argv, "-time") == 0) { + + if (--argc < 1) + goto bad; + maxTime = strtonum(*(++argv), 0, INT_MAX, &errstr); + if (errstr) + goto bad; + } else { + BIO_printf(bio_err, "unknown option %s\n", *argv); + badop = 1; + break; + } + + argc--; + argv++; + } + + if (perform == 0) + perform = 3; + + if (badop) { +bad: + s_time_usage(); + return -1; + } + return 0; /* Valid args */ +} + +/*********************************************************************** + * 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, char **); + +int +s_time_main(int argc, char **argv) +{ + double totalTime = 0.0; + int nConn = 0; + SSL *scon = NULL; + long finishtime = 0; + int ret = 1, i; + char buf[1024 * 8]; + int ver; + + s_time_init(); + + s_time_meth = SSLv23_client_method(); + + /* parse the command line arguments */ + if (parseArgs(argc, argv) < 0) + goto end; + + if ((tm_ctx = SSL_CTX_new(s_time_meth)) == NULL) + return (1); + + SSL_CTX_set_quiet_shutdown(tm_ctx, 1); + + if (st_bugs) + SSL_CTX_set_options(tm_ctx, SSL_OP_ALL); + SSL_CTX_set_cipher_list(tm_ctx, tm_cipher); + if (!set_cert_stuff(tm_ctx, t_cert_file, t_key_file)) + goto end; + + if ((!SSL_CTX_load_verify_locations(tm_ctx, CAfile, 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 (tm_cipher == NULL) + tm_cipher = getenv("SSL_CIPHER"); + + if (tm_cipher == NULL) { + fprintf(stderr, "No CIPHER specified\n"); + } + if (!(perform & 1)) + goto next; + printf("Collecting connection statistics for %d seconds\n", maxTime); + + /* Loop and time how long it takes to make connections */ + + bytes_read = 0; + finishtime = (long) time(NULL) + maxTime; + tm_Time_F(START); + for (;;) { + if (finishtime < (long) time(NULL)) + break; + if ((scon = doConnection(NULL)) == NULL) + goto end; + + if (s_www_path != NULL) { + int ret = snprintf(buf, sizeof buf, + "GET %s HTTP/1.0\r\n\r\n", s_www_path); + if (ret == -1 || ret >= 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; + } +#ifdef NO_SHUTDOWN + SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); +#else + SSL_shutdown(scon); +#endif + 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 */ + + i = (int) ((long) time(NULL) - finishtime + maxTime); + 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 %ld real seconds, %ld bytes read per connection\n", nConn, (long) time(NULL) - finishtime + maxTime, bytes_read / nConn); + + /* + * Now loop and time connections using the same session id over and + * over + */ + +next: + if (!(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_www_path != NULL) { + int ret = snprintf(buf, sizeof buf, + "GET %s HTTP/1.0\r\n\r\n", s_www_path); + if (ret == -1 || ret >= sizeof buf) { + fprintf(stderr, "URL too long\n"); + goto end; + } + SSL_write(scon, buf, strlen(buf)); + while (SSL_read(scon, buf, sizeof(buf)) > 0); + } +#ifdef NO_SHUTDOWN + SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); +#else + SSL_shutdown(scon); +#endif + shutdown(SSL_get_fd(scon), SHUT_RDWR); + close(SSL_get_fd(scon)); + + nConn = 0; + totalTime = 0.0; + + finishtime = (long) time(NULL) + maxTime; + + printf("starting\n"); + bytes_read = 0; + tm_Time_F(START); + + for (;;) { + if (finishtime < (long) time(NULL)) + break; + if ((doConnection(scon)) == NULL) + goto end; + + if (s_www_path) { + int ret = snprintf(buf, sizeof buf, + "GET %s HTTP/1.0\r\n\r\n", s_www_path); + if (ret == -1 || ret >= 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; + } +#ifdef NO_SHUTDOWN + SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); +#else + SSL_shutdown(scon); +#endif + 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 %ld real seconds, %ld bytes read per connection\n", nConn, (long) time(NULL) - finishtime + 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) +{ + BIO *conn; + SSL *serverCon; + int width, i; + fd_set readfds; + + if ((conn = BIO_new(BIO_s_connect())) == NULL) + return (NULL); + +/* BIO_set_conn_port(conn,port);*/ + BIO_set_conn_hostname(conn, host); + + if (scon == NULL) + serverCon = SSL_new(tm_ctx); + else { + serverCon = scon; + SSL_set_connect_state(serverCon); + } + + SSL_set_bio(serverCon, conn, conn); + +#if 0 + if (scon != NULL) + SSL_set_session(serverCon, SSL_get_session(scon)); +#endif + + /* 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); + width = i + 1; + FD_ZERO(&readfds); + FD_SET(i, &readfds); + select(width, &readfds, NULL, NULL, NULL); + continue; + } + break; + } + if (i <= 0) { + BIO_printf(bio_err, "ERROR\n"); + 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/usr.bin/openssl/sess_id.c b/usr.bin/openssl/sess_id.c new file mode 100644 index 00000000000..23df0301b36 --- /dev/null +++ b/usr.bin/openssl/sess_id.c @@ -0,0 +1,282 @@ +/* $OpenBSD: sess_id.c,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.] + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/bio.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/ssl.h> +#include <openssl/x509.h> + +static const char *sess_id_usage[] = { + "usage: sess_id args\n", + "\n", + " -inform arg - input format - default PEM (DER or PEM)\n", + " -outform arg - output format - default PEM\n", + " -in arg - input file - default stdin\n", + " -out arg - output file - default stdout\n", + " -text - print ssl session id details\n", + " -cert - output certificate \n", + " -noout - no output of encoded session info\n", + " -context arg - set the session ID context\n", + NULL +}; + +static SSL_SESSION *load_sess_id(char *file, int format); + +int sess_id_main(int, char **); + +int +sess_id_main(int argc, char **argv) +{ + SSL_SESSION *x = NULL; + X509 *peer = NULL; + int ret = 1, i, num, badops = 0; + BIO *out = NULL; + int informat, outformat; + char *infile = NULL, *outfile = NULL, *context = NULL; + int cert = 0, noout = 0, text = 0; + const char **pp; + + informat = FORMAT_PEM; + outformat = FORMAT_PEM; + + 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, "-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, "-text") == 0) + text = ++num; + else if (strcmp(*argv, "-cert") == 0) + cert = ++num; + else if (strcmp(*argv, "-noout") == 0) + noout = ++num; + else if (strcmp(*argv, "-context") == 0) { + if (--argc < 1) + goto bad; + context = *++argv; + } else { + BIO_printf(bio_err, "unknown option %s\n", *argv); + badops = 1; + break; + } + argc--; + argv++; + } + + if (badops) { +bad: + for (pp = sess_id_usage; (*pp != NULL); pp++) + BIO_printf(bio_err, "%s", *pp); + goto end; + } + ERR_load_crypto_strings(); + x = load_sess_id(infile, informat); + if (x == NULL) { + goto end; + } + peer = SSL_SESSION_get0_peer(x); + + if (context) { + size_t ctx_len = strlen(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 *) context, ctx_len); + } +#ifdef undef + /* just testing for memory leaks :-) */ + { + SSL_SESSION *s; + char buf[1024 * 10], *p; + int i; + + s = SSL_SESSION_new(); + + p = &buf; + i = i2d_SSL_SESSION(x, &p); + p = &buf; + d2i_SSL_SESSION(&s, &p, (long) i); + p = &buf; + d2i_SSL_SESSION(&s, &p, (long) i); + p = &buf; + d2i_SSL_SESSION(&s, &p, (long) i); + SSL_SESSION_free(s); + } +#endif + + if (!noout || text) { + 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 (text) { + SSL_SESSION_print(out, x); + + if (cert) { + if (peer == NULL) + BIO_puts(out, "No certificate present\n"); + else + X509_print(out, peer); + } + } + if (!noout && !cert) { + if (outformat == FORMAT_ASN1) + i = i2d_SSL_SESSION_bio(out, x); + else if (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 (!noout && (peer != NULL)) { /* just print the certificate */ + if (outformat == FORMAT_ASN1) + i = (int) i2d_X509_bio(out, peer); + else if (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: + if (out != NULL) + BIO_free_all(out); + if (x != NULL) + 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/usr.bin/openssl/smime.c b/usr.bin/openssl/smime.c new file mode 100644 index 00000000000..155bb8b03d8 --- /dev/null +++ b/usr.bin/openssl/smime.c @@ -0,0 +1,697 @@ +/* $OpenBSD: smime.c,v 1.1 2014/08/26 17:47:25 jsing 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 <stdio.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/crypto.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/x509_vfy.h> +#include <openssl/x509v3.h> + +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, char **); + +int +smime_main(int argc, char **argv) +{ + ENGINE *e = NULL; + 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; +#ifndef OPENSSL_NO_ENGINE + char *engine = NULL; +#endif + + X509_VERIFY_PARAM *vpm = NULL; + + 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; +#ifndef OPENSSL_NO_ENGINE + else if (!strcmp(*args, "-engine")) { + if (!args[1]) + goto argerr; + engine = *++args; + } +#endif + 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 or ENGINE)\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"); +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, "-engine e use engine e, possibly a hardware device.\n"); +#endif + 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; + } +#ifndef OPENSSL_NO_ENGINE + e = setup_engine(bio_err, engine, 0); +#endif + + 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, e, "recipient certificate file"))) { +#if 0 /* An appropriate message is already printed */ + BIO_printf(bio_err, "Can't read recipient certificate file %s\n", *args); +#endif + goto end; + } + sk_X509_push(encerts, cert); + cert = NULL; + args++; + } + } + if (certfile) { + if (!(other = load_certs(bio_err, certfile, FORMAT_PEM, NULL, + e, "certificate file"))) { + ERR_print_errors(bio_err); + goto end; + } + } + if (recipfile && (operation == SMIME_DECRYPT)) { + if (!(recip = load_cert(bio_err, recipfile, FORMAT_PEM, NULL, + e, "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, e, + "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, + e, "signer certificate"); + if (!signer) + goto end; + key = load_key(bio_err, keyfile, keyform, 0, passin, e, + "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/usr.bin/openssl/speed.c b/usr.bin/openssl/speed.c new file mode 100644 index 00000000000..82a0f90f054 --- /dev/null +++ b/usr.bin/openssl/speed.c @@ -0,0 +1,2170 @@ +/* $OpenBSD: speed.c,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.] + */ +/* ==================================================================== + * 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 + +/* 11-Sep-92 Andrew Daviel Support for Silicon Graphics IRIX added */ +/* 06-Apr-92 Luke Brennan Support for VMS and add extra signal calls */ + +#include <math.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include <unistd.h> + +#include "apps.h" + +#include <openssl/bn.h> +#include <openssl/crypto.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/modes.h> +#include <openssl/objects.h> +#include <openssl/rand.h> +#include <openssl/x509.h> + +#ifndef OPENSSL_NO_AES +#include <openssl/aes.h> +#endif +#ifndef OPENSSL_NO_BF +#include <openssl/blowfish.h> +#endif +#ifndef OPENSSL_NO_CAST +#include <openssl/cast.h> +#endif +#ifndef OPENSSL_NO_CAMELLIA +#include <openssl/camellia.h> +#endif +#ifndef OPENSSL_NO_DES +#include <openssl/des.h> +#endif +#include <openssl/dsa.h> +#include <openssl/ecdh.h> +#include <openssl/ecdsa.h> +#ifndef OPENSSL_NO_HMAC +#include <openssl/hmac.h> +#endif +#ifndef OPENSSL_NO_IDEA +#include <openssl/idea.h> +#endif +#ifndef OPENSSL_NO_MDC2 +#include <openssl/mdc2.h> +#endif +#ifndef OPENSSL_NO_MD4 +#include <openssl/md4.h> +#endif +#ifndef OPENSSL_NO_MD5 +#include <openssl/md5.h> +#endif +#ifndef OPENSSL_NO_RC2 +#include <openssl/rc2.h> +#endif +#ifndef OPENSSL_NO_RC4 +#include <openssl/rc4.h> +#endif +#ifndef OPENSSL_NO_RC5 +#include <openssl/rc5.h> +#endif +#include <openssl/rsa.h> +#ifndef OPENSSL_NO_RIPEMD +#include <openssl/ripemd.h> +#endif +#ifndef OPENSSL_NO_SHA +#include <openssl/sha.h> +#endif +#ifndef OPENSSL_NO_WHIRLPOOL +#include <openssl/whrlpool.h> +#endif + +#include "./testdsa.h" +#include "./testrsa.h" + +#define BUFSIZE ((long)1024*8+1) +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 30 +#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", "mdc2", "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"}; +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, char **); + +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_MDC2 + unsigned char mdc2[MDC2_DIGEST_LENGTH]; +#endif +#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_RC5 + RC5_32_KEY rc5_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_MDC2 1 +#define D_MD4 2 +#define D_MD5 3 +#define D_HMAC 4 +#define D_SHA1 5 +#define D_RMD160 6 +#define D_RC4 7 +#define D_CBC_DES 8 +#define D_EDE3_DES 9 +#define D_CBC_IDEA 10 +#define D_CBC_SEED 11 +#define D_CBC_RC2 12 +#define D_CBC_RC5 13 +#define D_CBC_BF 14 +#define D_CBC_CAST 15 +#define D_CBC_128_AES 16 +#define D_CBC_192_AES 17 +#define D_CBC_256_AES 18 +#define D_CBC_128_CML 19 +#define D_CBC_192_CML 20 +#define D_CBC_256_CML 21 +#define D_EVP 22 +#define D_SHA256 23 +#define D_SHA512 24 +#define D_WHIRLPOOL 25 +#define D_IGE_128_AES 26 +#define D_IGE_192_AES 27 +#define D_IGE_256_AES 28 +#define D_GHASH 29 + 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; + +#ifndef TIMES + usertime = -1; +#endif + + 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((int) BUFSIZE)) == NULL) { + BIO_printf(bio_err, "out of memory\n"); + goto end; + } + if ((buf2 = malloc((int) 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. */ + } +#ifndef OPENSSL_NO_ENGINE + else if ((argc > 0) && (strcmp(*argv, "-engine") == 0)) { + argc--; + argv++; + if (argc == 0) { + BIO_printf(bio_err, "no engine given\n"); + goto end; + } + setup_engine(bio_err, *argv, 0); + /* + * j will be increased again further down. We just + * don't want speed to confuse an engine with an + * algorithm, especially when none is given (which + * means all of them should be run) + */ + j--; + } +#endif + 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_MDC2 + if (strcmp(*argv, "mdc2") == 0) + doit[D_MDC2] = 1; + else +#endif +#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 +#if 0 /* was: #ifdef RSAref */ + if (strcmp(*argv, "rsaref") == 0) { + RSA_set_default_openssl_method(RSA_PKCS1_RSAref()); + j--; + } 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_RC5 + if (strcmp(*argv, "rc5-cbc") == 0) + doit[D_CBC_RC5] = 1; + else if (strcmp(*argv, "rc5") == 0) + doit[D_CBC_RC5] = 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 +#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 (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_MDC2 + BIO_printf(bio_err, "mdc2 "); +#endif +#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_MDC2) || \ + !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_RC5 + BIO_printf(bio_err, "rc5-cbc "); +#endif +#ifndef OPENSSL_NO_BF + BIO_printf(bio_err, "bf-cbc"); +#endif +#if !defined(OPENSSL_NO_IDEA) || !defined(OPENSSL_NO_SEED) || !defined(OPENSSL_NO_RC2) || \ + !defined(OPENSSL_NO_BF) || !defined(OPENSSL_NO_RC5) + BIO_printf(bio_err, "\n"); +#endif +#ifndef OPENSSL_NO_DES + BIO_printf(bio_err, "des-cbc des-ede3 "); +#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 "); +#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 + 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\n"); + BIO_printf(bio_err, "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\n"); + BIO_printf(bio_err, "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"); +#if defined(TIMES) || defined(USE_TOD) + BIO_printf(bio_err, "-elapsed measure time in real time instead of CPU user time.\n"); +#endif +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, "-engine e use engine e, possibly a hardware device.\n"); +#endif + 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; + } +#if 0 + else { + BIO_printf(bio_err, mr ? "+RK:%d:" + : "Loaded RSA key, %d bit modulus and e= 0x", + BN_num_bits(rsa_key[i]->n)); + BN_print(bio_err, rsa_key[i]->e); + BIO_printf(bio_err, "\n"); + } +#endif + } + + 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_RC5 + RC5_32_set_key(&rc5_ks, 16, key16, 12); +#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_MDC2 + if (doit[D_MDC2]) { + for (j = 0; j < SIZE_NUM; j++) { + print_message(names[D_MDC2], c[D_MDC2][j], lengths[j]); + Time_F(START); + for (count = 0, run = 1; COND(c[D_MDC2][j]); count++) + EVP_Digest(buf, (unsigned long) lengths[j], &(mdc2[0]), NULL, EVP_mdc2(), NULL); + d = Time_F(STOP); + print_result(D_MDC2, j, count, d); + } + } +#endif + +#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); + } +#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_RC5 + if (doit[D_CBC_RC5]) { + for (j = 0; j < SIZE_NUM; j++) { + print_message(names[D_CBC_RC5], c[D_CBC_RC5][j], lengths[j]); + Time_F(START); + for (count = 0, run = 1; COND(c[D_CBC_RC5][j]); count++) + RC5_32_cbc_encrypt(buf, buf, + (unsigned long) lengths[j], &rc5_ks, + iv, RC5_ENCRYPT); + d = Time_F(STOP); + print_result(D_CBC_RC5, 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); + } + } + RAND_pseudo_bytes(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; + } + +#if 1 + 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; + } +#endif + + if (rsa_count <= 1) { + /* if longer than 10s, don't do any more */ + for (j++; j < RSA_NUM; j++) + rsa_doit[j] = 0; + } + } + + RAND_pseudo_bytes(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 { +#if 1 + EC_KEY_precompute_mult(ecdsa[j], NULL); +#endif + /* 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; + } + 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); + 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/usr.bin/openssl/spkac.c b/usr.bin/openssl/spkac.c new file mode 100644 index 00000000000..266ed576622 --- /dev/null +++ b/usr.bin/openssl/spkac.c @@ -0,0 +1,284 @@ +/* $OpenBSD: spkac.c,v 1.1 2014/08/26 17:47:25 jsing 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "apps.h" + +#include <openssl/bio.h> +#include <openssl/conf.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/lhash.h> +#include <openssl/pem.h> +#include <openssl/x509.h> + +/* -in arg - input file - default stdin + * -out arg - output file - default stdout + */ + +int spkac_main(int, char **); + +int +spkac_main(int argc, char **argv) +{ + ENGINE *e = NULL; + int i, badops = 0, ret = 1; + BIO *in = NULL, *out = NULL; + int verify = 0, noout = 0, pubkey = 0; + char *infile = NULL, *outfile = NULL, *prog; + char *passargin = NULL, *passin = NULL; + const char *spkac = "SPKAC", *spksect = "default"; + char *spkstr = NULL; + char *challenge = NULL, *keyfile = NULL; + CONF *conf = NULL; + NETSCAPE_SPKI *spki = NULL; + EVP_PKEY *pkey = NULL; +#ifndef OPENSSL_NO_ENGINE + char *engine = NULL; +#endif + + prog = argv[0]; + argc--; + argv++; + while (argc >= 1) { + 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, "-passin") == 0) { + if (--argc < 1) + goto bad; + passargin = *(++argv); + } else if (strcmp(*argv, "-key") == 0) { + if (--argc < 1) + goto bad; + keyfile = *(++argv); + } else if (strcmp(*argv, "-challenge") == 0) { + if (--argc < 1) + goto bad; + challenge = *(++argv); + } else if (strcmp(*argv, "-spkac") == 0) { + if (--argc < 1) + goto bad; + spkac = *(++argv); + } else if (strcmp(*argv, "-spksect") == 0) { + if (--argc < 1) + goto bad; + spksect = *(++argv); + } +#ifndef OPENSSL_NO_ENGINE + else if (strcmp(*argv, "-engine") == 0) { + if (--argc < 1) + goto bad; + engine = *(++argv); + } +#endif + else if (strcmp(*argv, "-noout") == 0) + noout = 1; + else if (strcmp(*argv, "-pubkey") == 0) + pubkey = 1; + else if (strcmp(*argv, "-verify") == 0) + verify = 1; + else + badops = 1; + argc--; + argv++; + } + + if (badops) { +bad: + BIO_printf(bio_err, "%s [options]\n", prog); + BIO_printf(bio_err, "where options are\n"); + BIO_printf(bio_err, " -in arg input file\n"); + BIO_printf(bio_err, " -out arg output file\n"); + BIO_printf(bio_err, " -key arg create SPKAC using private key\n"); + BIO_printf(bio_err, " -passin arg input file pass phrase source\n"); + BIO_printf(bio_err, " -challenge arg challenge string\n"); + BIO_printf(bio_err, " -spkac arg alternative SPKAC name\n"); + BIO_printf(bio_err, " -noout don't print SPKAC\n"); + BIO_printf(bio_err, " -pubkey output public key\n"); + BIO_printf(bio_err, " -verify verify SPKAC signature\n"); +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, " -engine e use engine e, possibly a hardware device.\n"); +#endif + goto end; + } + ERR_load_crypto_strings(); + if (!app_passwd(bio_err, passargin, NULL, &passin, NULL)) { + BIO_printf(bio_err, "Error getting password\n"); + goto end; + } +#ifndef OPENSSL_NO_ENGINE + e = setup_engine(bio_err, engine, 0); +#endif + + if (keyfile) { + pkey = load_key(bio_err, + strcmp(keyfile, "-") ? keyfile : NULL, + FORMAT_PEM, 1, passin, e, "private key"); + if (!pkey) { + goto end; + } + spki = NETSCAPE_SPKI_new(); + if (challenge) + ASN1_STRING_set(spki->spkac->challenge, + challenge, (int) strlen(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 (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"); + ERR_print_errors(bio_err); + } else { + BIO_printf(out, "SPKAC=%s\n", spkstr); + ret = 0; + } + free(spkstr); + goto end; + } + if (infile) + in = BIO_new_file(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, spksect, spkac); + + if (!spkstr) { + BIO_printf(bio_err, "Can't find SPKAC called \"%s\"\n", 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 (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"); + ERR_print_errors(bio_err); + goto end; + } + if (!noout) + NETSCAPE_SPKI_print(out, spki); + pkey = NETSCAPE_SPKI_get_pubkey(spki); + if (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 (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/usr.bin/openssl/testdsa.h b/usr.bin/openssl/testdsa.h new file mode 100644 index 00000000000..1bbb09ca708 --- /dev/null +++ b/usr.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/usr.bin/openssl/testrsa.h b/usr.bin/openssl/testrsa.h new file mode 100644 index 00000000000..789afa9621e --- /dev/null +++ b/usr.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/usr.bin/openssl/timeouts.h b/usr.bin/openssl/timeouts.h new file mode 100644 index 00000000000..dd2f85028d9 --- /dev/null +++ b/usr.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/usr.bin/openssl/ts.c b/usr.bin/openssl/ts.c new file mode 100644 index 00000000000..fab79b9ceeb --- /dev/null +++ b/usr.bin/openssl/ts.c @@ -0,0 +1,1102 @@ +/* $OpenBSD: ts.c,v 1.1 2014/08/26 17:47:25 jsing 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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/bio.h> +#include <openssl/bn.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/rand.h> +#include <openssl/ts.h> + +/* 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 *engine, + 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 *engine, + 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); + +/* Main function definition. */ +int ts_main(int, char **); + +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; + char *engine = NULL; + /* Input is ContentInfo instead of TimeStampResp. */ + int token_in = 0; + /* Output is ContentInfo instead of TimeStampResp. */ + int token_out = 0; + + ERR_load_crypto_strings(); + + 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 (strcmp(*argv, "-engine") == 0) { + if (argc-- < 1) + goto usage; + engine = *++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, engine, 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]" + "[-md2|-md4|-md5|-sha|-sha1|-mdc2|-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] [-engine id]\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) + configfile = getenv("SSLEAY_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; + if (RAND_bytes(buf, len) <= 0) + goto err; + + /* 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 *engine, 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, engine, 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 *engine, + 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; +#ifndef OPENSSL_NO_ENGINE + /* Setting default OpenSSL engine. */ + if (!TS_CONF_set_crypto_device(conf, section, engine)) + goto end; +#endif + + /* 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/usr.bin/openssl/verify.c b/usr.bin/openssl/verify.c new file mode 100644 index 00000000000..057c4673723 --- /dev/null +++ b/usr.bin/openssl/verify.c @@ -0,0 +1,339 @@ +/* $OpenBSD: verify.c,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.] + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/bio.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/x509.h> +#include <openssl/x509v3.h> + +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, ENGINE * e); +static int v_verbose = 0, vflags = 0; + +int verify_main(int, char **); + +int +verify_main(int argc, char **argv) +{ + ENGINE *e = NULL; + 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; +#ifndef OPENSSL_NO_ENGINE + char *engine = NULL; +#endif + + cert_ctx = X509_STORE_new(); + if (cert_ctx == NULL) + goto end; + X509_STORE_set_verify_cb(cert_ctx, cb); + + ERR_load_crypto_strings(); + + 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); + } +#ifndef OPENSSL_NO_ENGINE + else if (strcmp(*argv, "-engine") == 0) { + if (--argc < 1) + goto end; + engine = *(++argv); + } +#endif + 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; + } + +#ifndef OPENSSL_NO_ENGINE + e = setup_engine(bio_err, engine, 0); +#endif + + 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, e, "untrusted certificates"); + if (!untrusted) + goto end; + } + if (trustfile) { + trusted = load_certs(bio_err, trustfile, FORMAT_PEM, + NULL, e, "trusted certificates"); + if (!trusted) + goto end; + } + if (crlfile) { + crls = load_crls(bio_err, crlfile, FORMAT_PEM, + NULL, e, "other CRLs"); + if (!crls) + goto end; + } + ret = 0; + if (argc < 1) { + if (1 != check(cert_ctx, NULL, untrusted, trusted, crls, e)) + ret = -1; + } else { + for (i = 0; i < argc; i++) + if (1 != check(cert_ctx, argv[i], untrusted, trusted, + crls, e)) + 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]"); +#ifndef OPENSSL_NO_ENGINE + BIO_printf(bio_err, " [-engine e]"); +#endif + 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, ENGINE * e) +{ + X509 *x = NULL; + int i = 0, ret = 0; + X509_STORE_CTX *csc; + + x = load_cert(bio_err, file, FORMAT_PEM, NULL, e, "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/usr.bin/openssl/version.c b/usr.bin/openssl/version.c new file mode 100644 index 00000000000..afad0c3e112 --- /dev/null +++ b/usr.bin/openssl/version.c @@ -0,0 +1,208 @@ +/* $OpenBSD: version.c,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.] + */ +/* ==================================================================== + * 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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/bn.h> +#include <openssl/crypto.h> +#include <openssl/evp.h> + +#ifndef OPENSSL_NO_BF +#include <openssl/blowfish.h> +#endif + +#ifndef OPENSSL_NO_DES +#include <openssl/des.h> +#endif + +#ifndef OPENSSL_NO_IDEA +#include <openssl/idea.h> +#endif + +#ifndef OPENSSL_NO_RC4 +#include <openssl/rc4.h> +#endif + +int version_main(int, char **); + +int +version_main(int argc, char **argv) +{ + int i, ret = 0; + int cflags = 0, version = 0, date = 0, options = 0, platform = 0, + dir = 0; + + if (argc == 1) + version = 1; + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-v") == 0) + version = 1; + else if (strcmp(argv[i], "-b") == 0) + date = 1; + else if (strcmp(argv[i], "-f") == 0) + cflags = 1; + else if (strcmp(argv[i], "-o") == 0) + options = 1; + else if (strcmp(argv[i], "-p") == 0) + platform = 1; + else if (strcmp(argv[i], "-d") == 0) + dir = 1; + else if (strcmp(argv[i], "-a") == 0) + date = version = cflags = options = platform = dir = 1; + else { + BIO_printf(bio_err, "usage:version -[avbofpd]\n"); + ret = 1; + goto end; + } + } + + if (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 (date) + printf("%s\n", SSLeay_version(SSLEAY_BUILT_ON)); + if (platform) + printf("%s\n", SSLeay_version(SSLEAY_PLATFORM)); + if (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 (cflags) + printf("%s\n", SSLeay_version(SSLEAY_CFLAGS)); + if (dir) + printf("%s\n", SSLeay_version(SSLEAY_DIR)); +end: + + return (ret); +} diff --git a/usr.bin/openssl/x509.c b/usr.bin/openssl/x509.c new file mode 100644 index 00000000000..afbccc00d6f --- /dev/null +++ b/usr.bin/openssl/x509.c @@ -0,0 +1,1160 @@ +/* $OpenBSD: x509.c,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.] + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> + +#include "apps.h" + +#include <openssl/asn1.h> +#include <openssl/bio.h> +#include <openssl/bn.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/objects.h> +#include <openssl/pem.h> +#include <openssl/x509.h> +#include <openssl/x509v3.h> + +#include <openssl/dsa.h> + +#include <openssl/rsa.h> + +#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", + " -md2/-md5/-sha1/-mdc2 - 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", +#ifndef OPENSSL_NO_ENGINE + " -engine e - use engine e, possibly a hardware device.\n", +#endif + " -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, char **); + +int +x509_main(int argc, char **argv) +{ + ENGINE *e = NULL; + 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; +#ifndef OPENSSL_NO_ENGINE + char *engine = NULL; +#endif + const char *errstr = NULL; + + 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; + 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; + } +#ifndef OPENSSL_NO_ENGINE + else if (strcmp(*argv, "-engine") == 0) { + if (--argc < 1) + goto bad; + engine = *(++argv); + } +#endif + 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; + } +#ifndef OPENSSL_NO_ENGINE + e = setup_engine(bio_err, engine, 0); +#endif + + ERR_load_crypto_strings(); + + 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, e, "Certificate"); + + if (x == NULL) + goto end; + if (CA_flag) { + xca = load_cert(bio_err, CAfile, CAformat, NULL, e, "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, "<No Alias>\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); + + 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, e, "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, e, + "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, e, "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(ASN1_ITEM_rptr(NETSCAPE_X509), 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; +} |