X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=apps%2Flib%2Fapps.c;h=df4450d7e40909584798ae9eb42bf41ea0676910;hp=73483d99f4313b52d10b6a0516c3ddbdbccc02b8;hb=0808a75e4db421f0f33d866b0abfe10db4f472f2;hpb=e78253f2d0c1a9fe6b023d867ee02342b4560150 diff --git a/apps/lib/apps.c b/apps/lib/apps.c index 73483d99f4..df4450d7e4 100644 --- a/apps/lib/apps.c +++ b/apps/lib/apps.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -57,6 +58,17 @@ static int WIN32_rename(const char *from, const char *to); #define PASS_SOURCE_SIZE_MAX 4 +DEFINE_STACK_OF(CONF) +DEFINE_STACK_OF(CONF_VALUE) +DEFINE_STACK_OF(X509) +DEFINE_STACK_OF(X509_CRL) +DEFINE_STACK_OF(X509_INFO) +DEFINE_STACK_OF(X509_EXTENSION) +DEFINE_STACK_OF(X509_POLICY_NODE) +DEFINE_STACK_OF(GENERAL_NAME) +DEFINE_STACK_OF(DIST_POINT) +DEFINE_STACK_OF_STRING() + typedef struct { const char *name; unsigned long flag; @@ -125,18 +137,29 @@ int app_init(long mesgwin) } #endif -int ctx_set_verify_locations(SSL_CTX *ctx, const char *CAfile, - const char *CApath, int noCAfile, int noCApath) +int ctx_set_verify_locations(SSL_CTX *ctx, + const char *CAfile, int noCAfile, + const char *CApath, int noCApath, + const char *CAstore, int noCAstore) { - if (CAfile == NULL && CApath == NULL) { + if (CAfile == NULL && CApath == NULL && CAstore == NULL) { if (!noCAfile && SSL_CTX_set_default_verify_file(ctx) <= 0) return 0; if (!noCApath && SSL_CTX_set_default_verify_dir(ctx) <= 0) return 0; + if (!noCAstore && SSL_CTX_set_default_verify_store(ctx) <= 0) + return 0; return 1; } - return SSL_CTX_load_verify_locations(ctx, CAfile, CApath); + + if (CAfile != NULL && !SSL_CTX_load_verify_file(ctx, CAfile)) + return 0; + if (CApath != NULL && !SSL_CTX_load_verify_dir(ctx, CApath)) + return 0; + if (CAstore != NULL && !SSL_CTX_load_verify_store(ctx, CAstore)) + return 0; + return 1; } #ifndef OPENSSL_NO_CT @@ -187,6 +210,24 @@ int wrap_password_callback(char *buf, int bufsiz, int verify, void *userdata) static char *app_get_pass(const char *arg, int keepbio); +char *get_passwd(const char *pass, const char *desc) +{ + char *result = NULL; + + if (desc == NULL) + desc = ""; + if (!app_passwd(pass, NULL, &result, NULL)) + BIO_printf(bio_err, "Error getting password for %s\n", desc); + if (pass != NULL && result == NULL) { + BIO_printf(bio_err, + "Trying plain input string (better precede with 'pass:')\n"); + result = OPENSSL_strdup(pass); + if (result == NULL) + BIO_printf(bio_err, "Out of memory getting password for %s\n", desc); + } + return result; +} + int app_passwd(const char *arg1, const char *arg2, char **pass1, char **pass2) { int same = arg1 != NULL && arg2 != NULL && strcmp(arg1, arg2) == 0; @@ -390,324 +431,162 @@ int add_oid_section(CONF *conf) return 1; } -static int load_pkcs12(BIO *in, const char *desc, - pem_password_cb *pem_cb, PW_CB_DATA *cb_data, - EVP_PKEY **pkey, X509 **cert, STACK_OF(X509) **ca) +X509 *load_cert_pass(const char *uri, int maybe_stdin, + const char *pass, const char *desc) { - const char *pass; - char tpass[PEM_BUFSIZE]; - int len, ret = 0; - PKCS12 *p12; - p12 = d2i_PKCS12_bio(in, NULL); - if (p12 == NULL) { - BIO_printf(bio_err, "Error loading PKCS12 file for %s\n", desc); - goto die; + X509 *cert = NULL; + + if (desc == NULL) + desc = "certificate"; + if (uri == NULL) { + unbuffer(stdin); + uri = ""; } - /* See if an empty password will do */ - if (PKCS12_verify_mac(p12, "", 0) || PKCS12_verify_mac(p12, NULL, 0)) { - pass = ""; - } else { - if (pem_cb == NULL) - pem_cb = (pem_password_cb *)password_callback; - len = pem_cb(tpass, PEM_BUFSIZE, 0, cb_data); - if (len < 0) { - BIO_printf(bio_err, "Passphrase callback error for %s\n", desc); - goto die; - } - if (len < PEM_BUFSIZE) - tpass[len] = 0; - if (!PKCS12_verify_mac(p12, tpass, len)) { - BIO_printf(bio_err, - "Mac verify error (wrong password?) in PKCS12 file for %s\n", - desc); - goto die; - } - pass = tpass; + (void)load_key_cert_crl(uri, maybe_stdin, pass, desc, NULL, &cert, NULL); + if (cert == NULL) { + BIO_printf(bio_err, "Unable to load %s\n", desc); + ERR_print_errors(bio_err); } - ret = PKCS12_parse(p12, pass, pkey, cert, ca); - die: - PKCS12_free(p12); - return ret; + return cert; } -#if !defined(OPENSSL_NO_OCSP) && !defined(OPENSSL_NO_SOCK) -static int load_cert_crl_http(const char *url, X509 **pcert, X509_CRL **pcrl) +/* the format parameter is meanwhile not needed anymore and thus ignored */ +X509 *load_cert(const char *uri, int format, const char *desc) { - char *host = NULL, *port = NULL, *path = NULL; - BIO *bio = NULL; - OCSP_REQ_CTX *rctx = NULL; - int use_ssl, rv = 0; - if (!OCSP_parse_url(url, &host, &port, &path, &use_ssl)) - goto err; - if (use_ssl) { - BIO_puts(bio_err, "https not supported\n"); - goto err; - } - bio = BIO_new_connect(host); - if (!bio || !BIO_set_conn_port(bio, port)) - goto err; - rctx = OCSP_REQ_CTX_new(bio, 1024); - if (rctx == NULL) - goto err; - if (!OCSP_REQ_CTX_http(rctx, "GET", path)) - goto err; - if (!OCSP_REQ_CTX_add1_header(rctx, "Host", host)) - goto err; - if (pcert) { - do { - rv = X509_http_nbio(rctx, pcert); - } while (rv == -1); - } else { - do { - rv = X509_CRL_http_nbio(rctx, pcrl); - } while (rv == -1); - } + return load_cert_pass(uri, 1, NULL, desc); +} - err: - OPENSSL_free(host); - OPENSSL_free(path); - OPENSSL_free(port); - BIO_free_all(bio); - OCSP_REQ_CTX_free(rctx); - if (rv != 1) { - BIO_printf(bio_err, "Error loading %s from %s\n", - pcert ? "certificate" : "CRL", url); +/* the format parameter is meanwhile not needed anymore and thus ignored */ +X509_CRL *load_crl(const char *uri, int format, const char *desc) +{ + X509_CRL *crl = NULL; + + if (desc == NULL) + desc = "CRL"; + (void)load_key_cert_crl(uri, 0, NULL, desc, NULL, NULL, &crl); + if (crl == NULL) { + BIO_printf(bio_err, "Unable to load %s\n", desc); ERR_print_errors(bio_err); } - return rv; + return crl; } -#endif -X509 *load_cert(const char *file, int format, const char *cert_descrip) +X509_REQ *load_csr(const char *file, int format, const char *desc) { - X509 *x = NULL; - BIO *cert; - - if (format == FORMAT_HTTP) { -#if !defined(OPENSSL_NO_OCSP) && !defined(OPENSSL_NO_SOCK) - load_cert_crl_http(file, &x, NULL); -#endif - return x; - } + X509_REQ *req = NULL; + BIO *in; - if (file == NULL) { - unbuffer(stdin); - cert = dup_bio_in(format); - } else { - cert = bio_open_default(file, 'r', format); - } - if (cert == NULL) + if (desc == NULL) + desc = "CSR"; + in = bio_open_default(file, 'r', format); + if (in == NULL) goto end; - if (format == FORMAT_ASN1) { - x = d2i_X509_bio(cert, NULL); - } else if (format == FORMAT_PEM) { - x = PEM_read_bio_X509_AUX(cert, NULL, - (pem_password_cb *)password_callback, NULL); - } else if (format == FORMAT_PKCS12) { - if (!load_pkcs12(cert, cert_descrip, NULL, NULL, NULL, &x, NULL)) - goto end; - } else { - BIO_printf(bio_err, "bad input format specified for %s\n", cert_descrip); - goto end; - } + if (format == FORMAT_ASN1) + req = d2i_X509_REQ_bio(in, NULL); + else if (format == FORMAT_PEM) + req = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL); + else + print_format_error(format, OPT_FMT_PEMDER); + end: - if (x == NULL) { - BIO_printf(bio_err, "unable to load certificate\n"); + if (req == NULL) { + BIO_printf(bio_err, "Unable to load %s\n", desc); ERR_print_errors(bio_err); } - BIO_free(cert); - return x; + BIO_free(in); + return req; } -X509_CRL *load_crl(const char *infile, int format) +void cleanse(char *str) { - X509_CRL *x = NULL; - BIO *in = NULL; - - if (format == FORMAT_HTTP) { -#if !defined(OPENSSL_NO_OCSP) && !defined(OPENSSL_NO_SOCK) - load_cert_crl_http(infile, NULL, &x); -#endif - return x; - } - - in = bio_open_default(infile, 'r', format); - if (in == NULL) - 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; - } + if (str != NULL) + OPENSSL_cleanse(str, strlen(str)); +} - end: - BIO_free(in); - return x; +void clear_free(char *str) +{ + if (str != NULL) + OPENSSL_clear_free(str, strlen(str)); } -EVP_PKEY *load_key(const char *file, int format, int maybe_stdin, - const char *pass, ENGINE *e, const char *key_descrip) +EVP_PKEY *load_key(const char *uri, int format, int may_stdin, + const char *pass, ENGINE *e, const char *desc) { - BIO *key = NULL; EVP_PKEY *pkey = NULL; - PW_CB_DATA cb_data; - cb_data.password = pass; - cb_data.prompt_info = file; + if (desc == NULL) + desc = "private key"; - if (file == NULL && (!maybe_stdin || format == FORMAT_ENGINE)) { - BIO_printf(bio_err, "no keyfile specified\n"); - goto end; - } if (format == FORMAT_ENGINE) { if (e == NULL) { - BIO_printf(bio_err, "no engine specified\n"); + BIO_printf(bio_err, "No engine specified for loading %s\n", desc); } else { #ifndef OPENSSL_NO_ENGINE + PW_CB_DATA cb_data; + + cb_data.password = pass; + cb_data.prompt_info = uri; if (ENGINE_init(e)) { - pkey = ENGINE_load_private_key(e, file, + pkey = ENGINE_load_private_key(e, uri, (UI_METHOD *)get_ui_method(), &cb_data); ENGINE_finish(e); } if (pkey == NULL) { - BIO_printf(bio_err, "cannot load %s from engine\n", key_descrip); + BIO_printf(bio_err, "Cannot load %s from engine\n", desc); ERR_print_errors(bio_err); } #else - BIO_printf(bio_err, "engines not supported\n"); + BIO_printf(bio_err, "Engines not supported for loading %s\n", desc); #endif } - goto end; - } - if (file == NULL && maybe_stdin) { - unbuffer(stdin); - key = dup_bio_in(format); - } else { - key = bio_open_default(file, 'r', format); - } - if (key == NULL) - goto end; - if (format == FORMAT_ASN1) { - pkey = d2i_PrivateKey_bio(key, NULL); - } else if (format == FORMAT_PEM) { - pkey = PEM_read_bio_PrivateKey(key, NULL, wrap_password_callback, &cb_data); - } else if (format == FORMAT_PKCS12) { - if (!load_pkcs12(key, key_descrip, wrap_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, wrap_password_callback, &cb_data); -#endif } else { - BIO_printf(bio_err, "bad input format specified for key file\n"); - goto end; + (void)load_key_cert_crl(uri, may_stdin, pass, desc, &pkey, NULL, NULL); } - end: - BIO_free(key); + if (pkey == NULL) { - BIO_printf(bio_err, "unable to load %s\n", key_descrip); + BIO_printf(bio_err, "Unable to load %s\n", desc); ERR_print_errors(bio_err); } return pkey; } -EVP_PKEY *load_pubkey(const char *file, int format, int maybe_stdin, - const char *pass, ENGINE *e, const char *key_descrip) +EVP_PKEY *load_pubkey(const char *uri, int format, int maybe_stdin, + const char *pass, ENGINE *e, const char *desc) { - BIO *key = NULL; EVP_PKEY *pkey = NULL; - PW_CB_DATA cb_data; - cb_data.password = pass; - cb_data.prompt_info = file; + if (desc == NULL) + desc = "public key"; - if (file == NULL && (!maybe_stdin || format == FORMAT_ENGINE)) { - BIO_printf(bio_err, "no keyfile specified\n"); - goto end; - } if (format == FORMAT_ENGINE) { if (e == NULL) { - BIO_printf(bio_err, "no engine specified\n"); + BIO_printf(bio_err, "No engine specified for loading %s\n", desc); } else { #ifndef OPENSSL_NO_ENGINE - pkey = ENGINE_load_public_key(e, file, (UI_METHOD *)get_ui_method(), + PW_CB_DATA cb_data; + + cb_data.password = pass; + cb_data.prompt_info = uri; + pkey = ENGINE_load_public_key(e, uri, (UI_METHOD *)get_ui_method(), &cb_data); if (pkey == NULL) { - BIO_printf(bio_err, "cannot load %s from engine\n", key_descrip); + BIO_printf(bio_err, "Cannot load %s from engine\n", desc); ERR_print_errors(bio_err); } #else - BIO_printf(bio_err, "engines not supported\n"); + BIO_printf(bio_err, "Engines not supported for loading %s\n", desc); #endif } - goto end; - } - if (file == NULL && maybe_stdin) { - unbuffer(stdin); - key = dup_bio_in(format); } else { - key = bio_open_default(file, 'r', format); + (void)load_key_cert_crl(uri, maybe_stdin, pass, desc, &pkey, + NULL, NULL); } - if (key == NULL) - goto end; - if (format == FORMAT_ASN1) { - pkey = d2i_PUBKEY_bio(key, NULL); - } else if (format == FORMAT_ASN1RSA) { -#ifndef OPENSSL_NO_RSA - RSA *rsa; - rsa = d2i_RSAPublicKey_bio(key, NULL); - if (rsa) { - pkey = EVP_PKEY_new(); - if (pkey != NULL) - EVP_PKEY_set1_RSA(pkey, rsa); - RSA_free(rsa); - } else -#else - BIO_printf(bio_err, "RSA keys not supported\n"); -#endif - pkey = NULL; - } else if (format == FORMAT_PEMRSA) { -#ifndef OPENSSL_NO_RSA - RSA *rsa; - rsa = PEM_read_bio_RSAPublicKey(key, NULL, - (pem_password_cb *)password_callback, - &cb_data); - if (rsa != NULL) { - pkey = EVP_PKEY_new(); - if (pkey != NULL) - EVP_PKEY_set1_RSA(pkey, rsa); - RSA_free(rsa); - } else -#else - BIO_printf(bio_err, "RSA keys not supported\n"); -#endif - pkey = NULL; - } else if (format == FORMAT_PEM) { - pkey = PEM_read_bio_PUBKEY(key, NULL, - (pem_password_cb *)password_callback, - &cb_data); -#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DSA) - } else if (format == FORMAT_MSBLOB) { - pkey = b2i_PublicKey_bio(key); -#endif + if (pkey == NULL) { + BIO_printf(bio_err, "Unable to load %s\n", desc); + ERR_print_errors(bio_err); } - end: - BIO_free(key); - if (pkey == NULL) - BIO_printf(bio_err, "unable to load %s\n", key_descrip); return pkey; } @@ -727,7 +606,7 @@ static int load_certs_crls(const char *file, int format, cb_data.prompt_info = file; if (format != FORMAT_PEM) { - BIO_printf(bio_err, "bad input format specified for %s\n", desc); + BIO_printf(bio_err, "Bad input format specified for %s\n", desc); return 0; } @@ -786,23 +665,30 @@ static int load_certs_crls(const char *file, int format, sk_X509_CRL_pop_free(*pcrls, X509_CRL_free); *pcrls = NULL; } - BIO_printf(bio_err, "unable to load %s\n", - pcerts ? "certificates" : "CRLs"); - ERR_print_errors(bio_err); + BIO_printf(bio_err, "Unable to load %s\n", desc != NULL ? desc : + pcerts != NULL ? "certificates" : "CRLs"); } return rv; } +void app_bail_out(char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + BIO_vprintf(bio_err, fmt, args); + va_end(args); + ERR_print_errors(bio_err); + exit(1); +} + void* app_malloc(int sz, const char *what) { void *vp = OPENSSL_malloc(sz); - if (vp == NULL) { - BIO_printf(bio_err, "%s: Could not allocate %d bytes for %s\n", - opt_getprog(), sz, what); - ERR_print_errors(bio_err); - exit(1); - } + if (vp == NULL) + app_bail_out("%s: Could not allocate %d bytes for %s\n", + opt_getprog(), sz, what); return vp; } @@ -824,6 +710,102 @@ int load_crls(const char *file, STACK_OF(X509_CRL) **crls, int format, return load_certs_crls(file, format, pass, desc, NULL, crls); } +/* + * Load those types of credentials for which the result pointer is not NULL. + * Reads from stdio if uri is NULL and maybe_stdin is nonzero. + * For each type the first credential found in the store is loaded. + * May yield partial result even if rv == 0. + */ +int load_key_cert_crl(const char *uri, int maybe_stdin, + const char *pass, const char *desc, + EVP_PKEY **ppkey, X509 **pcert, X509_CRL **pcrl) +{ + PW_CB_DATA uidata; + OSSL_STORE_CTX *ctx = NULL; + int ret = 0; + /* TODO make use of the engine reference 'eng' when loading pkeys */ + + if (ppkey != NULL) + *ppkey = NULL; + if (pcert != NULL) + *pcert = NULL; + if (pcrl != NULL) + *pcrl = NULL; + + if (desc == NULL) + desc = "key/certificate/CRL"; + uidata.password = pass; + uidata.prompt_info = uri; + + if (uri == NULL) { + BIO *bio; + + if (!maybe_stdin) { + BIO_printf(bio_err, "No filename or uri specified for loading %s\n", + desc); + goto end; + } + unbuffer(stdin); + bio = BIO_new_fp(stdin, 0); + if (bio != NULL) + ctx = OSSL_STORE_attach(bio, NULL, "file", NULL, + get_ui_method(), &uidata, NULL, NULL); + uri = ""; + } else { + ctx = OSSL_STORE_open(uri, get_ui_method(), &uidata, NULL, NULL); + } + if (ctx == NULL) { + BIO_printf(bio_err, "Could not open file or uri %s for loading %s\n", + uri, desc); + goto end; + } + + for (;;) { + OSSL_STORE_INFO *info = OSSL_STORE_load(ctx); + int type = info == NULL ? 0 : OSSL_STORE_INFO_get_type(info); + const char *infostr = + info == NULL ? NULL : OSSL_STORE_INFO_type_string(type); + int err = 0; + + if (info == NULL) { + if (OSSL_STORE_eof(ctx)) + ret = 1; + break; + } + + switch (type) { + case OSSL_STORE_INFO_PKEY: + if (ppkey != NULL && *ppkey == NULL) + err = ((*ppkey = OSSL_STORE_INFO_get1_PKEY(info)) == NULL); + break; + case OSSL_STORE_INFO_CERT: + if (pcert != NULL && *pcert == NULL) + err = ((*pcert = OSSL_STORE_INFO_get1_CERT(info)) == NULL); + break; + case OSSL_STORE_INFO_CRL: + if (pcrl != NULL && *pcrl == NULL) + err = ((*pcrl = OSSL_STORE_INFO_get1_CRL(info)) == NULL); + break; + default: + /* skip any other type */ + break; + } + OSSL_STORE_INFO_free(info); + if (err) { + BIO_printf(bio_err, "Could not read %s of %s from %s\n", + infostr, desc, uri); + break; + } + } + + end: + OSSL_STORE_close(ctx); + if (!ret) + ERR_print_errors(bio_err); + return ret; +} + + #define X509V3_EXT_UNKNOWN_MASK (0xfL << 16) /* Return error for unknown extensions */ #define X509V3_EXT_DEFAULT 0 @@ -1005,7 +987,7 @@ static int set_table_opts(unsigned long *flags, const char *arg, return 0; } -void print_name(BIO *out, const char *title, X509_NAME *nm, +void print_name(BIO *out, const char *title, const X509_NAME *nm, unsigned long lflags) { char *buf; @@ -1068,7 +1050,9 @@ void print_array(BIO *out, const char* title, int len, const unsigned char* d) BIO_printf(out, "\n};\n"); } -X509_STORE *setup_verify(const char *CAfile, const char *CApath, int noCAfile, int noCApath) +X509_STORE *setup_verify(const char *CAfile, int noCAfile, + const char *CApath, int noCApath, + const char *CAstore, int noCAstore) { X509_STORE *store = X509_STORE_new(); X509_LOOKUP *lookup; @@ -1080,7 +1064,7 @@ X509_STORE *setup_verify(const char *CAfile, const char *CApath, int noCAfile, i lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); if (lookup == NULL) goto end; - if (CAfile) { + if (CAfile != NULL) { if (!X509_LOOKUP_load_file(lookup, CAfile, X509_FILETYPE_PEM)) { BIO_printf(bio_err, "Error loading file %s\n", CAfile); goto end; @@ -1094,7 +1078,7 @@ X509_STORE *setup_verify(const char *CAfile, const char *CApath, int noCAfile, i lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir()); if (lookup == NULL) goto end; - if (CApath) { + if (CApath != NULL) { if (!X509_LOOKUP_add_dir(lookup, CApath, X509_FILETYPE_PEM)) { BIO_printf(bio_err, "Error loading directory %s\n", CApath); goto end; @@ -1104,9 +1088,21 @@ X509_STORE *setup_verify(const char *CAfile, const char *CApath, int noCAfile, i } } + if (CAstore != NULL || !noCAstore) { + lookup = X509_STORE_add_lookup(store, X509_LOOKUP_store()); + if (lookup == NULL) + goto end; + if (!X509_LOOKUP_add_store(lookup, CAstore)) { + if (CAstore != NULL) + BIO_printf(bio_err, "Error loading store URI %s\n", CAstore); + goto end; + } + } + ERR_clear_error(); return store; end: + ERR_print_errors(bio_err); X509_STORE_free(store); return NULL; } @@ -1127,36 +1123,35 @@ static ENGINE *try_load_engine(const char *engine) } #endif -ENGINE *setup_engine(const char *engine, int debug) +ENGINE *setup_engine_methods(const char *id, unsigned int methods, int debug) { ENGINE *e = NULL; #ifndef OPENSSL_NO_ENGINE - if (engine != NULL) { - if (strcmp(engine, "auto") == 0) { - BIO_printf(bio_err, "enabling auto ENGINE support\n"); + if (id != NULL) { + if (strcmp(id, "auto") == 0) { + BIO_printf(bio_err, "Enabling auto ENGINE support\n"); ENGINE_register_all_complete(); return NULL; } - if ((e = ENGINE_by_id(engine)) == NULL - && (e = try_load_engine(engine)) == NULL) { - BIO_printf(bio_err, "invalid engine \"%s\"\n", engine); + if ((e = ENGINE_by_id(id)) == NULL + && (e = try_load_engine(id)) == NULL) { + BIO_printf(bio_err, "Invalid engine \"%s\"\n", id); ERR_print_errors(bio_err); return NULL; } - if (debug) { - ENGINE_ctrl(e, ENGINE_CTRL_SET_LOGSTREAM, 0, bio_err, 0); - } - ENGINE_ctrl_cmd(e, "SET_USER_INTERFACE", 0, (void *)get_ui_method(), - 0, 1); - if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { - BIO_printf(bio_err, "can't use that engine\n"); + if (debug) + (void)ENGINE_ctrl(e, ENGINE_CTRL_SET_LOGSTREAM, 0, bio_err, 0); + if (!ENGINE_ctrl_cmd(e, "SET_USER_INTERFACE", 0, + (void *)get_ui_method(), 0, 1) + || !ENGINE_set_default(e, methods)) { + BIO_printf(bio_err, "Cannot use engine \"%s\"\n", ENGINE_get_id(e)); ERR_print_errors(bio_err); ENGINE_free(e); return NULL; } - BIO_printf(bio_err, "engine \"%s\" set.\n", ENGINE_get_id(e)); + BIO_printf(bio_err, "Engine \"%s\" set.\n", ENGINE_get_id(e)); } #endif return e; @@ -1235,14 +1230,13 @@ BIGNUM *load_serial(const char *serialfile, int create, ASN1_INTEGER **retai) 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", + 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"); + BIO_printf(bio_err, "Error converting number from bin to BIGNUM\n"); goto err; } } @@ -1252,6 +1246,7 @@ BIGNUM *load_serial(const char *serialfile, int create, ASN1_INTEGER **retai) ai = NULL; } err: + ERR_print_errors(bio_err); BIO_free(in); ASN1_INTEGER_free(ai); return ret; @@ -1271,7 +1266,7 @@ int save_serial(const char *serialfile, const char *suffix, const BIGNUM *serial else j = strlen(serialfile) + strlen(suffix) + 1; if (j >= BSIZE) { - BIO_printf(bio_err, "file name too long\n"); + BIO_printf(bio_err, "File name too long\n"); goto err; } @@ -1286,7 +1281,6 @@ int save_serial(const char *serialfile, const char *suffix, const BIGNUM *serial } out = BIO_new_file(buf[0], "w"); if (out == NULL) { - ERR_print_errors(bio_err); goto err; } @@ -1302,6 +1296,8 @@ int save_serial(const char *serialfile, const char *suffix, const BIGNUM *serial ai = NULL; } err: + if (!ret) + ERR_print_errors(bio_err); BIO_free_all(out); ASN1_INTEGER_free(ai); return ret; @@ -1318,7 +1314,7 @@ int rotate_serial(const char *serialfile, const char *new_suffix, if (i > j) j = i; if (j + 1 >= BSIZE) { - BIO_printf(bio_err, "file name too long\n"); + BIO_printf(bio_err, "File name too long\n"); goto err; } #ifndef OPENSSL_SYS_VMS @@ -1334,19 +1330,20 @@ int rotate_serial(const char *serialfile, const char *new_suffix, #endif ) { BIO_printf(bio_err, - "unable to rename %s to %s\n", serialfile, buf[1]); + "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); + "Unable to rename %s to %s\n", buf[0], serialfile); perror("reason"); rename(buf[1], serialfile); goto err; } return 1; err: + ERR_print_errors(bio_err); return 0; } @@ -1387,17 +1384,14 @@ CA_DB *load_index(const char *dbfile, DB_ATTR *db_attr) #endif in = BIO_new_file(dbfile, "r"); - if (in == NULL) { - ERR_print_errors(bio_err); + if (in == NULL) goto err; - } #ifndef OPENSSL_NO_POSIX_IO BIO_get_fp(in, &dbfp); if (fstat(fileno(dbfp), &dbst) == -1) { ERR_raise_data(ERR_LIB_SYS, errno, "calling fstat(%s)", dbfile); - ERR_print_errors(bio_err); goto err; } #endif @@ -1434,6 +1428,7 @@ CA_DB *load_index(const char *dbfile, DB_ATTR *db_attr) #endif err: + ERR_print_errors(bio_err); NCONF_free(dbattr_conf); TXT_DB_free(tmpdb); BIO_free_all(in); @@ -1449,20 +1444,23 @@ int index_index(CA_DB *db) LHASH_HASH_FN(index_serial), LHASH_COMP_FN(index_serial))) { BIO_printf(bio_err, - "error creating serial number index:(%ld,%ld,%ld)\n", + "Error creating serial number index:(%ld,%ld,%ld)\n", db->db->error, db->db->arg1, db->db->arg2); - return 0; + goto err; } 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", + BIO_printf(bio_err, "Error creating name index:(%ld,%ld,%ld)\n", db->db->error, db->db->arg1, db->db->arg2); - return 0; + goto err; } return 1; + err: + ERR_print_errors(bio_err); + return 0; } int save_index(const char *dbfile, const char *suffix, CA_DB *db) @@ -1473,7 +1471,7 @@ int save_index(const char *dbfile, const char *suffix, CA_DB *db) j = strlen(dbfile) + strlen(suffix); if (j + 6 >= BSIZE) { - BIO_printf(bio_err, "file name too long\n"); + BIO_printf(bio_err, "File name too long\n"); goto err; } #ifndef OPENSSL_SYS_VMS @@ -1488,7 +1486,7 @@ int save_index(const char *dbfile, const char *suffix, CA_DB *db) out = BIO_new_file(buf[0], "w"); if (out == NULL) { perror(dbfile); - BIO_printf(bio_err, "unable to open '%s'\n", dbfile); + BIO_printf(bio_err, "Unable to open '%s'\n", dbfile); goto err; } j = TXT_DB_write(out, db->db); @@ -1499,7 +1497,7 @@ int save_index(const char *dbfile, const char *suffix, CA_DB *db) out = BIO_new_file(buf[1], "w"); if (out == NULL) { perror(buf[2]); - BIO_printf(bio_err, "unable to open '%s'\n", buf[2]); + BIO_printf(bio_err, "Unable to open '%s'\n", buf[2]); goto err; } BIO_printf(out, "unique_subject = %s\n", @@ -1508,6 +1506,7 @@ int save_index(const char *dbfile, const char *suffix, CA_DB *db) return 1; err: + ERR_print_errors(bio_err); return 0; } @@ -1522,7 +1521,7 @@ int rotate_index(const char *dbfile, const char *new_suffix, if (i > j) j = i; if (j + 6 >= BSIZE) { - BIO_printf(bio_err, "file name too long\n"); + BIO_printf(bio_err, "File name too long\n"); goto err; } #ifndef OPENSSL_SYS_VMS @@ -1543,12 +1542,12 @@ int rotate_index(const char *dbfile, const char *new_suffix, && errno != ENOTDIR #endif ) { - BIO_printf(bio_err, "unable to rename %s to %s\n", dbfile, buf[1]); + 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); + BIO_printf(bio_err, "Unable to rename %s to %s\n", buf[0], dbfile); perror("reason"); rename(buf[1], dbfile); goto err; @@ -1558,14 +1557,14 @@ int rotate_index(const char *dbfile, const char *new_suffix, && errno != ENOTDIR #endif ) { - BIO_printf(bio_err, "unable to rename %s to %s\n", buf[4], buf[3]); + 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]); + 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]); @@ -1574,6 +1573,7 @@ int rotate_index(const char *dbfile, const char *new_suffix, } return 1; err: + ERR_print_errors(bio_err); return 0; } @@ -1664,7 +1664,7 @@ X509_NAME *parse_name(const char *cp, long chtype, int canmulti) } if (*cp == '\\' && *++cp == '\0') { BIO_printf(bio_err, - "%s: escape character at end of string\n", + "%s: Escape character at end of string\n", opt_getprog()); goto err; } @@ -1913,18 +1913,18 @@ static X509_CRL *load_crl_crldp(STACK_OF(DIST_POINT) *crldp) DIST_POINT *dp = sk_DIST_POINT_value(crldp, i); urlptr = get_dp_url(dp); if (urlptr) - return load_crl(urlptr, FORMAT_HTTP); + return load_crl(urlptr, FORMAT_HTTP, "CRL via CDP"); } return NULL; } /* - * Example of downloading CRLs from CRLDP: not usable for real world as it - * always downloads, doesn't support non-blocking I/O and doesn't cache - * anything. + * Example of downloading CRLs from CRLDP: + * not usable for real world as it always downloads and doesn't cache anything. */ -static STACK_OF(X509_CRL) *crls_http_cb(X509_STORE_CTX *ctx, X509_NAME *nm) +static STACK_OF(X509_CRL) *crls_http_cb(const X509_STORE_CTX *ctx, + const X509_NAME *nm) { X509 *x; STACK_OF(X509_CRL) *crls = NULL; @@ -1957,6 +1957,137 @@ void store_setup_crl_download(X509_STORE *st) X509_STORE_set_lookup_crls_cb(st, crls_http_cb); } +#ifndef OPENSSL_NO_SOCK +static const char *tls_error_hint(void) +{ + unsigned long err = ERR_peek_error(); + + if (ERR_GET_LIB(err) != ERR_LIB_SSL) + err = ERR_peek_last_error(); + if (ERR_GET_LIB(err) != ERR_LIB_SSL) + return NULL; + + switch (ERR_GET_REASON(err)) { + case SSL_R_WRONG_VERSION_NUMBER: + return "The server does not support (a suitable version of) TLS"; + case SSL_R_UNKNOWN_PROTOCOL: + return "The server does not support HTTPS"; + case SSL_R_CERTIFICATE_VERIFY_FAILED: + return "Cannot authenticate server via its TLS certificate, likely due to mismatch with our trusted TLS certs or missing revocation status"; + case SSL_AD_REASON_OFFSET + TLS1_AD_UNKNOWN_CA: + return "Server did not accept our TLS certificate, likely due to mismatch with server's trust anchor or missing revocation status"; + case SSL_AD_REASON_OFFSET + SSL3_AD_HANDSHAKE_FAILURE: + return "TLS handshake failure. Possibly the server requires our TLS certificate but did not receive it"; + default: /* no error or no hint available for error */ + return NULL; + } +} + +/* HTTP callback function that supports TLS connection also via HTTPS proxy */ +BIO *app_http_tls_cb(BIO *hbio, void *arg, int connect, int detail) +{ + APP_HTTP_TLS_INFO *info = (APP_HTTP_TLS_INFO *)arg; + SSL_CTX *ssl_ctx = info->ssl_ctx; + SSL *ssl; + BIO *sbio = NULL; + + if (connect && detail) { /* connecting with TLS */ + if ((info->use_proxy + && !OSSL_HTTP_proxy_connect(hbio, info->server, info->port, + NULL, NULL, /* no proxy credentials */ + info->timeout, bio_err, opt_getprog())) + || (sbio = BIO_new(BIO_f_ssl())) == NULL) { + return NULL; + } + if (ssl_ctx == NULL || (ssl = SSL_new(ssl_ctx)) == NULL) { + BIO_free(sbio); + return NULL; + } + + SSL_set_tlsext_host_name(ssl, info->server); + + SSL_set_connect_state(ssl); + BIO_set_ssl(sbio, ssl, BIO_CLOSE); + + hbio = BIO_push(sbio, hbio); + } else if (!connect && !detail) { /* disconnecting after error */ + const char *hint = tls_error_hint(); + if (hint != NULL) + ERR_add_error_data(2, " : ", hint); + /* + * If we pop sbio and BIO_free() it this may lead to libssl double free. + * Rely on BIO_free_all() done by OSSL_HTTP_transfer() in http_client.c + */ + } + return hbio; +} + +ASN1_VALUE *app_http_get_asn1(const char *url, const char *proxy, + const char *no_proxy, SSL_CTX *ssl_ctx, + const STACK_OF(CONF_VALUE) *headers, + long timeout, const char *expected_content_type, + const ASN1_ITEM *it) +{ + APP_HTTP_TLS_INFO info; + char *server; + char *port; + int use_ssl; + ASN1_VALUE *resp = NULL; + + if (url == NULL || it == NULL) { + HTTPerr(0, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + + if (!OSSL_HTTP_parse_url(url, &server, &port, NULL /* ppath */, &use_ssl)) + return NULL; + if (use_ssl && ssl_ctx == NULL) { + HTTPerr(0, ERR_R_PASSED_NULL_PARAMETER); + ERR_add_error_data(1, "missing SSL_CTX"); + goto end; + } + + info.server = server; + info.port = port; + info.use_proxy = proxy != NULL; + info.timeout = timeout; + info.ssl_ctx = ssl_ctx; + resp = OSSL_HTTP_get_asn1(url, proxy, no_proxy, + NULL, NULL, app_http_tls_cb, &info, + headers, 0 /* maxline */, 0 /* max_resp_len */, + timeout, expected_content_type, it); + end: + OPENSSL_free(server); + OPENSSL_free(port); + return resp; + +} + +ASN1_VALUE *app_http_post_asn1(const char *host, const char *port, + const char *path, const char *proxy, + const char *no_proxy, SSL_CTX *ssl_ctx, + const STACK_OF(CONF_VALUE) *headers, + const char *content_type, + ASN1_VALUE *req, const ASN1_ITEM *req_it, + long timeout, const ASN1_ITEM *rsp_it) +{ + APP_HTTP_TLS_INFO info; + + info.server = host; + info.port = port; + info.use_proxy = proxy != NULL; + info.timeout = timeout; + info.ssl_ctx = ssl_ctx; + return OSSL_HTTP_post_asn1(host, port, path, ssl_ctx != NULL, + proxy, no_proxy, + NULL, NULL, app_http_tls_cb, &info, + headers, content_type, req, req_it, + 0 /* maxline */, + 0 /* max_resp_len */, timeout, NULL, rsp_it); +} + +#endif + /* * Platform-specific sections */ @@ -2107,40 +2238,6 @@ double app_tminterval(int stop, int usertime) return ret; } -#elif defined(OPENSSL_SYSTEM_VMS) -# include -# include - -double app_tminterval(int stop, int usertime) -{ - static clock_t tmstart; - double ret = 0; - clock_t now; -# ifdef __TMS - struct tms rus; - - now = times(&rus); - if (usertime) - now = rus.tms_utime; -# else - if (usertime) - now = clock(); /* sum of user and kernel times */ - else { - struct timeval tv; - gettimeofday(&tv, NULL); - now = (clock_t)((unsigned long long)tv.tv_sec * CLK_TCK + - (unsigned long long)tv.tv_usec * (1000000 / CLK_TCK) - ); - } -# endif - if (stop == TM_START) - tmstart = now; - else - ret = (now - tmstart) / (double)(CLK_TCK); - - return ret; -} - #elif defined(_SC_CLK_TCK) /* by means of unistd.h */ # include @@ -2300,8 +2397,8 @@ BIO *dup_bio_out(int format) if (FMT_istext(format) && (prefix = getenv("HARNESS_OSSL_PREFIX")) != NULL) { - b = BIO_push(BIO_new(apps_bf_prefix()), b); - BIO_ctrl(b, PREFIX_CTRL_SET_PREFIX, 0, prefix); + b = BIO_push(BIO_new(BIO_f_prefix()), b); + BIO_set_prefix(b, prefix); } return b; @@ -2318,17 +2415,6 @@ BIO *dup_bio_err(int format) return b; } -/* - * Because the prefix method is created dynamically, we must also be able - * to destroy it. - */ -void destroy_prefix_method(void) -{ - BIO_METHOD *prefix_method = apps_bf_prefix(); - BIO_meth_free(prefix_method); - prefix_method = NULL; -} - void unbuffer(FILE *fp) { /* @@ -2594,6 +2680,7 @@ OSSL_PARAM *app_params_new_from_opts(STACK_OF(OPENSSL_STRING) *opts, size_t sz = (size_t)sk_OPENSSL_STRING_num(opts); size_t params_n; char *opt = "", *stmp, *vtmp = NULL; + int found = 1; if (opts == NULL) return NULL; @@ -2612,7 +2699,7 @@ OSSL_PARAM *app_params_new_from_opts(STACK_OF(OPENSSL_STRING) *opts, /* Skip over the separator so that vmtp points to the value */ vtmp++; if (!OSSL_PARAM_allocate_from_text(¶ms[params_n], paramdefs, - stmp, vtmp, strlen(vtmp))) + stmp, vtmp, strlen(vtmp), &found)) goto err; OPENSSL_free(stmp); } @@ -2620,7 +2707,8 @@ OSSL_PARAM *app_params_new_from_opts(STACK_OF(OPENSSL_STRING) *opts, return params; err: OPENSSL_free(stmp); - BIO_printf(bio_err, "Parameter error '%s'\n", opt); + BIO_printf(bio_err, "Parameter %s '%s'\n", found ? "error" : "unknown", + opt); ERR_print_errors(bio_err); app_params_free(params); return NULL;