diff options
author | jkim <jkim@FreeBSD.org> | 2015-10-23 19:46:02 +0000 |
---|---|---|
committer | jkim <jkim@FreeBSD.org> | 2015-10-23 19:46:02 +0000 |
commit | 64cb0c902e312216cdc4c826fc0be9ba9e1bf4da (patch) | |
tree | ae816a5a768ec78af3610e509ca39507b33aa9f7 /apps | |
parent | e5911a7a89e76432a8d4607068e9171b30272e08 (diff) | |
download | FreeBSD-src-64cb0c902e312216cdc4c826fc0be9ba9e1bf4da.zip FreeBSD-src-64cb0c902e312216cdc4c826fc0be9ba9e1bf4da.tar.gz |
Import OpenSSL 1.0.2d.
Diffstat (limited to 'apps')
-rw-r--r-- | apps/apps.c | 254 | ||||
-rw-r--r-- | apps/apps.h | 22 | ||||
-rw-r--r-- | apps/ca.c | 22 | ||||
-rw-r--r-- | apps/ciphers.c | 16 | ||||
-rw-r--r-- | apps/cms.c | 146 | ||||
-rw-r--r-- | apps/crl.c | 92 | ||||
-rw-r--r-- | apps/dgst.c | 38 | ||||
-rw-r--r-- | apps/dhparam.c | 9 | ||||
-rw-r--r-- | apps/ecparam.c | 3 | ||||
-rw-r--r-- | apps/genrsa.c | 2 | ||||
-rw-r--r-- | apps/ocsp.c | 96 | ||||
-rw-r--r-- | apps/openssl.cnf | 2 | ||||
-rw-r--r-- | apps/pkcs8.c | 10 | ||||
-rw-r--r-- | apps/s_apps.h | 33 | ||||
-rw-r--r-- | apps/s_cb.c | 792 | ||||
-rw-r--r-- | apps/s_client.c | 354 | ||||
-rw-r--r-- | apps/s_server.c | 782 | ||||
-rw-r--r-- | apps/s_socket.c | 11 | ||||
-rw-r--r-- | apps/smime.c | 6 | ||||
-rw-r--r-- | apps/speed.c | 129 | ||||
-rw-r--r-- | apps/verify.c | 7 | ||||
-rw-r--r-- | apps/x509.c | 74 |
22 files changed, 2544 insertions, 356 deletions
diff --git a/apps/apps.c b/apps/apps.c index 6801238..7478fc3 100644 --- a/apps/apps.c +++ b/apps/apps.c @@ -119,7 +119,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#if !defined(OPENSSL_SYSNAME_WIN32) && !defined(NETWARE_CLIB) +#if !defined(OPENSSL_SYSNAME_WIN32) && !defined(OPENSSL_SYSNAME_WINCE) && !defined(NETWARE_CLIB) # include <strings.h> #endif #include <sys/types.h> @@ -285,6 +285,8 @@ int str2fmt(char *s) return (FORMAT_PKCS12); else if ((*s == 'E') || (*s == 'e')) return (FORMAT_ENGINE); + else if ((*s == 'H') || (*s == 'h')) + return FORMAT_HTTP; else if ((*s == 'P') || (*s == 'p')) { if (s[1] == 'V' || s[1] == 'v') return FORMAT_PVK; @@ -787,12 +789,72 @@ static int load_pkcs12(BIO *err, BIO *in, const char *desc, return ret; } +int load_cert_crl_http(const char *url, BIO *err, + X509 **pcert, X509_CRL **pcrl) +{ + 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) { + if (err) + BIO_puts(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) + 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); + } + + err: + if (host) + OPENSSL_free(host); + if (path) + OPENSSL_free(path); + if (port) + OPENSSL_free(port); + if (bio) + BIO_free_all(bio); + if (rctx) + OCSP_REQ_CTX_free(rctx); + if (rv != 1) { + if (bio && err) + BIO_printf(bio_err, "Error loading %s from %s\n", + pcert ? "certificate" : "CRL", url); + ERR_print_errors(bio_err); + } + return rv; +} + 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 (format == FORMAT_HTTP) { + load_cert_crl_http(file, err, &x, NULL); + return x; + } + if ((cert = BIO_new(BIO_s_file())) == NULL) { ERR_print_errors(err); goto end; @@ -850,6 +912,49 @@ X509 *load_cert(BIO *err, const char *file, int format, return (x); } +X509_CRL *load_crl(const char *infile, int format) +{ + X509_CRL *x = NULL; + BIO *in = NULL; + + if (format == FORMAT_HTTP) { + load_cert_crl_http(infile, bio_err, NULL, &x); + return x; + } + + 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); +} + EVP_PKEY *load_key(BIO *err, const char *file, int format, int maybe_stdin, const char *pass, ENGINE *e, const char *key_descrip) { @@ -2159,6 +2264,9 @@ int args_verify(char ***pargs, int *pargc, char **oldargs = *pargs; char *arg = **pargs, *argn = (*pargs)[1]; time_t at_time = 0; + char *hostname = NULL; + char *email = NULL; + char *ipasc = NULL; if (!strcmp(arg, "-policy")) { if (!argn) *badarg = 1; @@ -2212,6 +2320,21 @@ int args_verify(char ***pargs, int *pargc, at_time = (time_t)timestamp; } (*pargs)++; + } else if (strcmp(arg, "-verify_hostname") == 0) { + if (!argn) + *badarg = 1; + hostname = argn; + (*pargs)++; + } else if (strcmp(arg, "-verify_email") == 0) { + if (!argn) + *badarg = 1; + email = argn; + (*pargs)++; + } else if (strcmp(arg, "-verify_ip") == 0) { + if (!argn) + *badarg = 1; + ipasc = argn; + (*pargs)++; } else if (!strcmp(arg, "-ignore_critical")) flags |= X509_V_FLAG_IGNORE_CRITICAL; else if (!strcmp(arg, "-issuer_checks")) @@ -2238,6 +2361,16 @@ int args_verify(char ***pargs, int *pargc, flags |= X509_V_FLAG_NOTIFY_POLICY; else if (!strcmp(arg, "-check_ss_sig")) flags |= X509_V_FLAG_CHECK_SS_SIGNATURE; + else if (!strcmp(arg, "-trusted_first")) + flags |= X509_V_FLAG_TRUSTED_FIRST; + else if (!strcmp(arg, "-suiteB_128_only")) + flags |= X509_V_FLAG_SUITEB_128_LOS_ONLY; + else if (!strcmp(arg, "-suiteB_128")) + flags |= X509_V_FLAG_SUITEB_128_LOS; + else if (!strcmp(arg, "-suiteB_192")) + flags |= X509_V_FLAG_SUITEB_192_LOS; + else if (!strcmp(arg, "-partial_chain")) + flags |= X509_V_FLAG_PARTIAL_CHAIN; else if (!strcmp(arg, "-no_alt_chains")) flags |= X509_V_FLAG_NO_ALT_CHAINS; else @@ -2269,6 +2402,15 @@ int args_verify(char ***pargs, int *pargc, if (at_time) X509_VERIFY_PARAM_set_time(*pm, at_time); + if (hostname && !X509_VERIFY_PARAM_set1_host(*pm, hostname, 0)) + *badarg = 1; + + if (email && !X509_VERIFY_PARAM_set1_email(*pm, email, 0)) + *badarg = 1; + + if (ipasc && !X509_VERIFY_PARAM_set1_ip_asc(*pm, ipasc)) + *badarg = 1; + end: (*pargs)++; @@ -2552,6 +2694,9 @@ void jpake_client_auth(BIO *out, BIO *conn, const char *secret) BIO_puts(out, "JPAKE authentication succeeded, setting PSK\n"); + if (psk_key) + OPENSSL_free(psk_key); + psk_key = BN_bn2hex(JPAKE_get_shared_key(ctx)); BIO_pop(bconn); @@ -2581,6 +2726,9 @@ void jpake_server_auth(BIO *out, BIO *conn, const char *secret) BIO_puts(out, "JPAKE authentication succeeded, setting PSK\n"); + if (psk_key) + OPENSSL_free(psk_key); + psk_key = BN_bn2hex(JPAKE_get_shared_key(ctx)); BIO_pop(bconn); @@ -2591,7 +2739,7 @@ void jpake_server_auth(BIO *out, BIO *conn, const char *secret) #endif -#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) +#ifndef OPENSSL_NO_TLSEXT /*- * 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. @@ -2630,8 +2778,106 @@ unsigned char *next_protos_parse(unsigned short *outlen, const char *in) *outlen = len + 1; return out; } -#endif /* !OPENSSL_NO_TLSEXT && - * !OPENSSL_NO_NEXTPROTONEG */ +#endif /* ndef OPENSSL_NO_TLSEXT */ + +void print_cert_checks(BIO *bio, X509 *x, + const char *checkhost, + const char *checkemail, const char *checkip) +{ + if (x == NULL) + return; + if (checkhost) { + BIO_printf(bio, "Hostname %s does%s match certificate\n", + checkhost, X509_check_host(x, checkhost, 0, 0, NULL) == 1 + ? "" : " NOT"); + } + + if (checkemail) { + BIO_printf(bio, "Email %s does%s match certificate\n", + checkemail, X509_check_email(x, checkemail, 0, + 0) ? "" : " NOT"); + } + + if (checkip) { + BIO_printf(bio, "IP %s does%s match certificate\n", + checkip, X509_check_ip_asc(x, checkip, 0) ? "" : " NOT"); + } +} + +/* Get first http URL from a DIST_POINT structure */ + +static const char *get_dp_url(DIST_POINT *dp) +{ + GENERAL_NAMES *gens; + GENERAL_NAME *gen; + int i, gtype; + ASN1_STRING *uri; + if (!dp->distpoint || dp->distpoint->type != 0) + return NULL; + gens = dp->distpoint->name.fullname; + for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) { + gen = sk_GENERAL_NAME_value(gens, i); + uri = GENERAL_NAME_get0_value(gen, >ype); + if (gtype == GEN_URI && ASN1_STRING_length(uri) > 6) { + char *uptr = (char *)ASN1_STRING_data(uri); + if (!strncmp(uptr, "http://", 7)) + return uptr; + } + } + return NULL; +} + +/* + * Look through a CRLDP structure and attempt to find an http URL to + * downloads a CRL from. + */ + +static X509_CRL *load_crl_crldp(STACK_OF(DIST_POINT) *crldp) +{ + int i; + const char *urlptr = NULL; + for (i = 0; i < sk_DIST_POINT_num(crldp); i++) { + DIST_POINT *dp = sk_DIST_POINT_value(crldp, i); + urlptr = get_dp_url(dp); + if (urlptr) + return load_crl(urlptr, FORMAT_HTTP); + } + 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. + */ + +static STACK_OF(X509_CRL) *crls_http_cb(X509_STORE_CTX *ctx, X509_NAME *nm) +{ + X509 *x; + STACK_OF(X509_CRL) *crls = NULL; + X509_CRL *crl; + STACK_OF(DIST_POINT) *crldp; + x = X509_STORE_CTX_get_current_cert(ctx); + crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, NULL, NULL); + crl = load_crl_crldp(crldp); + sk_DIST_POINT_pop_free(crldp, DIST_POINT_free); + if (!crl) + return NULL; + crls = sk_X509_CRL_new_null(); + sk_X509_CRL_push(crls, crl); + /* Try to download delta CRL */ + crldp = X509_get_ext_d2i(x, NID_freshest_crl, NULL, NULL); + crl = load_crl_crldp(crldp); + sk_DIST_POINT_pop_free(crldp, DIST_POINT_free); + if (crl) + sk_X509_CRL_push(crls, crl); + return crls; +} + +void store_setup_crl_download(X509_STORE *st) +{ + X509_STORE_set_lookup_crls_cb(st, crls_http_cb); +} /* * Platform-specific sections diff --git a/apps/apps.h b/apps/apps.h index 33b293e..8276e70 100644 --- a/apps/apps.h +++ b/apps/apps.h @@ -205,7 +205,7 @@ extern BIO *bio_err; # endif # endif -# ifdef OPENSSL_SYSNAME_WIN32 +# if defined(OPENSSL_SYSNAME_WIN32) || defined(OPENSSL_SYSNAME_WINCE) # define openssl_fdset(a,b) FD_SET((unsigned int)a, b) # else # define openssl_fdset(a,b) FD_SET(a, b) @@ -245,6 +245,9 @@ 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); +X509_CRL *load_crl(const char *infile, int format); +int load_cert_crl_http(const char *url, BIO *err, + X509 **pcert, X509_CRL **pcrl); 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, @@ -262,8 +265,9 @@ ENGINE *setup_engine(BIO *err, const char *engine, int debug); # 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, + const char *host, const char *path, + const char *port, int use_ssl, + const STACK_OF(CONF_VALUE) *headers, int req_timeout); # endif @@ -334,10 +338,15 @@ void jpake_client_auth(BIO *out, BIO *conn, const char *secret); void jpake_server_auth(BIO *out, BIO *conn, const char *secret); # endif -# if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) +# ifndef OPENSSL_NO_TLSEXT unsigned char *next_protos_parse(unsigned short *outlen, const char *in); -# endif /* !OPENSSL_NO_TLSEXT && - * !OPENSSL_NO_NEXTPROTONEG */ +# endif /* ndef OPENSSL_NO_TLSEXT */ + +void print_cert_checks(BIO *bio, X509 *x, + const char *checkhost, + const char *checkemail, const char *checkip); + +void store_setup_crl_download(X509_STORE *st); # define FORMAT_UNDEF 0 # define FORMAT_ASN1 1 @@ -353,6 +362,7 @@ unsigned char *next_protos_parse(unsigned short *outlen, const char *in); # define FORMAT_ASN1RSA 10 /* DER RSAPubicKey format */ # define FORMAT_MSBLOB 11 /* MS Key blob format */ # define FORMAT_PVK 12 /* MS PVK file format */ +# define FORMAT_HTTP 13 /* Download using HTTP */ # define EXT_COPY_NONE 0 # define EXT_COPY_ADD 1 @@ -479,6 +479,11 @@ int MAIN(int argc, char **argv) goto bad; infile = *(++argv); dorevoke = 1; + } else if (strcmp(*argv, "-valid") == 0) { + if (--argc < 1) + goto bad; + infile = *(++argv); + dorevoke = 2; } else if (strcmp(*argv, "-extensions") == 0) { if (--argc < 1) goto bad; @@ -1441,6 +1446,8 @@ int MAIN(int argc, char **argv) revcert = load_cert(bio_err, infile, FORMAT_PEM, NULL, e, infile); if (revcert == NULL) goto err; + if (dorevoke == 2) + rev_type = -1; j = do_revoke(revcert, db, rev_type, rev_arg); if (j <= 0) goto err; @@ -1968,8 +1975,12 @@ static int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, if (enddate == NULL) X509_time_adj_ex(X509_get_notAfter(ret), days, 0, NULL); - else + else { + int tdays; ASN1_TIME_set_string(X509_get_notAfter(ret), enddate); + ASN1_TIME_diff(&tdays, NULL, NULL, X509_get_notAfter(ret)); + days = tdays; + } if (!X509_set_subject_name(ret, subject)) goto err; @@ -2409,13 +2420,20 @@ static int do_revoke(X509 *x509, CA_DB *db, int type, char *value) } /* Revoke Certificate */ - ok = do_revoke(x509, db, type, value); + if (type == -1) + ok = 1; + else + 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 (type == -1) { + BIO_printf(bio_err, "ERROR:Already present, serial number %s\n", + row[DB_serial]); + goto err; } else if (rrow[DB_type][0] == 'R') { BIO_printf(bio_err, "ERROR:Already revoked, serial number %s\n", row[DB_serial]); diff --git a/apps/ciphers.c b/apps/ciphers.c index f299175..66636d2 100644 --- a/apps/ciphers.c +++ b/apps/ciphers.c @@ -85,6 +85,9 @@ int MAIN(int argc, char **argv) { int ret = 1, i; int verbose = 0, Verbose = 0; +#ifndef OPENSSL_NO_SSL_TRACE + int stdname = 0; +#endif const char **pp; const char *p; int badops = 0; @@ -119,6 +122,10 @@ int MAIN(int argc, char **argv) verbose = 1; else if (strcmp(*argv, "-V") == 0) verbose = Verbose = 1; +#ifndef OPENSSL_NO_SSL_TRACE + else if (strcmp(*argv, "-stdname") == 0) + stdname = verbose = 1; +#endif #ifndef OPENSSL_NO_SSL2 else if (strcmp(*argv, "-ssl2") == 0) meth = SSLv2_client_method(); @@ -202,7 +209,14 @@ int MAIN(int argc, char **argv) id1, id2, id3); } } - +#ifndef OPENSSL_NO_SSL_TRACE + if (stdname) { + const char *nm = SSL_CIPHER_standard_name(c); + if (nm == NULL) + nm = "UNKNOWN"; + BIO_printf(STDout, "%s - ", nm); + } +#endif BIO_puts(STDout, SSL_CIPHER_description(c, buf, sizeof buf)); } } @@ -75,6 +75,8 @@ 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); +static int cms_set_pkey_param(EVP_PKEY_CTX *pctx, + STACK_OF(OPENSSL_STRING) *param); # define SMIME_OP 0x10 # define SMIME_IP 0x20 @@ -98,6 +100,14 @@ static CMS_ReceiptRequest *make_receipt_request(STACK_OF(OPENSSL_STRING) int verify_err = 0; +typedef struct cms_key_param_st cms_key_param; + +struct cms_key_param_st { + int idx; + STACK_OF(OPENSSL_STRING) *param; + cms_key_param *next; +}; + int MAIN(int, char **); int MAIN(int argc, char **argv) @@ -112,7 +122,7 @@ int MAIN(int argc, char **argv) STACK_OF(OPENSSL_STRING) *sksigners = NULL, *skkeys = NULL; char *certfile = NULL, *keyfile = NULL, *contfile = NULL; char *certsoutfile = NULL; - const EVP_CIPHER *cipher = NULL; + const EVP_CIPHER *cipher = NULL, *wrap_cipher = NULL; CMS_ContentInfo *cms = NULL, *rcms = NULL; X509_STORE *store = NULL; X509 *cert = NULL, *recip = NULL, *signer = NULL; @@ -140,6 +150,8 @@ int MAIN(int argc, char **argv) unsigned char *pwri_pass = NULL, *pwri_tmp = NULL; size_t secret_keylen = 0, secret_keyidlen = 0; + cms_key_param *key_first = NULL, *key_param = NULL; + ASN1_OBJECT *econtent_type = NULL; X509_VERIFY_PARAM *vpm = NULL; @@ -201,6 +213,8 @@ int MAIN(int argc, char **argv) cipher = EVP_des_ede3_cbc(); else if (!strcmp(*args, "-des")) cipher = EVP_des_cbc(); + else if (!strcmp(*args, "-des3-wrap")) + wrap_cipher = EVP_des_ede3_wrap(); # endif # ifndef OPENSSL_NO_SEED else if (!strcmp(*args, "-seed")) @@ -221,6 +235,12 @@ int MAIN(int argc, char **argv) cipher = EVP_aes_192_cbc(); else if (!strcmp(*args, "-aes256")) cipher = EVP_aes_256_cbc(); + else if (!strcmp(*args, "-aes128-wrap")) + wrap_cipher = EVP_aes_128_wrap(); + else if (!strcmp(*args, "-aes192-wrap")) + wrap_cipher = EVP_aes_192_wrap(); + else if (!strcmp(*args, "-aes256-wrap")) + wrap_cipher = EVP_aes_256_wrap(); # endif # ifndef OPENSSL_NO_CAMELLIA else if (!strcmp(*args, "-camellia128")) @@ -378,7 +398,17 @@ int MAIN(int argc, char **argv) } else if (!strcmp(*args, "-recip")) { if (!args[1]) goto argerr; - recipfile = *++args; + if (operation == SMIME_ENCRYPT) { + if (!encerts) + encerts = sk_X509_new_null(); + cert = load_cert(bio_err, *++args, FORMAT_PEM, + NULL, e, "recipient certificate file"); + if (!cert) + goto end; + sk_X509_push(encerts, cert); + cert = NULL; + } else + recipfile = *++args; } else if (!strcmp(*args, "-certsout")) { if (!args[1]) goto argerr; @@ -413,6 +443,40 @@ int MAIN(int argc, char **argv) if (!args[1]) goto argerr; keyform = str2fmt(*++args); + } else if (!strcmp(*args, "-keyopt")) { + int keyidx = -1; + if (!args[1]) + goto argerr; + if (operation == SMIME_ENCRYPT) { + if (encerts) + keyidx += sk_X509_num(encerts); + } else { + if (keyfile || signerfile) + keyidx++; + if (skkeys) + keyidx += sk_OPENSSL_STRING_num(skkeys); + } + if (keyidx < 0) { + BIO_printf(bio_err, "No key specified\n"); + goto argerr; + } + if (key_param == NULL || key_param->idx != keyidx) { + cms_key_param *nparam; + nparam = OPENSSL_malloc(sizeof(cms_key_param)); + if (!nparam) { + BIO_printf(bio_err, "Out of memory\n"); + goto argerr; + } + nparam->idx = keyidx; + nparam->param = sk_OPENSSL_STRING_new_null(); + nparam->next = NULL; + if (key_first == NULL) + key_first = nparam; + else + key_param->next = nparam; + key_param = nparam; + } + sk_OPENSSL_STRING_push(key_param->param, *++args); } else if (!strcmp(*args, "-rctform")) { if (!args[1]) goto argerr; @@ -502,7 +566,7 @@ int MAIN(int argc, char **argv) badarg = 1; } } else if (operation == SMIME_ENCRYPT) { - if (!*args && !secret_key && !pwri_pass) { + if (!*args && !secret_key && !pwri_pass && !encerts) { BIO_printf(bio_err, "No recipient(s) certificate(s) specified\n"); badarg = 1; } @@ -567,6 +631,7 @@ int MAIN(int argc, char **argv) "-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, "-keyopt nm:v set public key parameters\n"); BIO_printf(bio_err, "-out file output file\n"); BIO_printf(bio_err, "-outform arg output format SMIME (default), PEM or DER\n"); @@ -652,7 +717,7 @@ int MAIN(int argc, char **argv) goto end; } - if (*args) + if (*args && !encerts) encerts = sk_X509_new_null(); while (*args) { if (!(cert = load_cert(bio_err, *args, FORMAT_PEM, @@ -804,10 +869,39 @@ int MAIN(int argc, char **argv) } else if (operation == SMIME_COMPRESS) { cms = CMS_compress(in, -1, flags); } else if (operation == SMIME_ENCRYPT) { + int i; flags |= CMS_PARTIAL; - cms = CMS_encrypt(encerts, in, cipher, flags); + cms = CMS_encrypt(NULL, in, cipher, flags); if (!cms) goto end; + for (i = 0; i < sk_X509_num(encerts); i++) { + CMS_RecipientInfo *ri; + cms_key_param *kparam; + int tflags = flags; + X509 *x = sk_X509_value(encerts, i); + for (kparam = key_first; kparam; kparam = kparam->next) { + if (kparam->idx == i) { + tflags |= CMS_KEY_PARAM; + break; + } + } + ri = CMS_add1_recipient_cert(cms, x, tflags); + if (!ri) + goto end; + if (kparam) { + EVP_PKEY_CTX *pctx; + pctx = CMS_RecipientInfo_get0_pkey_ctx(ri); + if (!cms_set_pkey_param(pctx, kparam->param)) + goto end; + } + if (CMS_RecipientInfo_type(ri) == CMS_RECIPINFO_AGREE + && wrap_cipher) { + EVP_CIPHER_CTX *wctx; + wctx = CMS_RecipientInfo_kari_get0_ctx(ri); + EVP_EncryptInit_ex(wctx, wrap_cipher, NULL, NULL, NULL); + } + } + if (secret_key) { if (!CMS_add0_recipient_key(cms, NID_undef, secret_key, secret_keylen, @@ -880,8 +974,11 @@ int MAIN(int argc, char **argv) flags |= CMS_REUSE_DIGEST; for (i = 0; i < sk_OPENSSL_STRING_num(sksigners); i++) { CMS_SignerInfo *si; + cms_key_param *kparam; + int tflags = flags; 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) @@ -890,9 +987,21 @@ int MAIN(int argc, char **argv) "signing key file"); if (!key) goto end; - si = CMS_add1_signer(cms, signer, key, sign_md, flags); + for (kparam = key_first; kparam; kparam = kparam->next) { + if (kparam->idx == i) { + tflags |= CMS_KEY_PARAM; + break; + } + } + si = CMS_add1_signer(cms, signer, key, sign_md, tflags); if (!si) goto end; + if (kparam) { + EVP_PKEY_CTX *pctx; + pctx = CMS_SignerInfo_get0_pkey_ctx(si); + if (!cms_set_pkey_param(pctx, kparam->param)) + goto end; + } if (rr && !CMS_add1_ReceiptRequest(si, rr)) goto end; X509_free(signer); @@ -1047,6 +1156,13 @@ int MAIN(int argc, char **argv) sk_OPENSSL_STRING_free(rr_to); if (rr_from) sk_OPENSSL_STRING_free(rr_from); + for (key_param = key_first; key_param;) { + cms_key_param *tparam; + sk_OPENSSL_STRING_free(key_param->param); + tparam = key_param->next; + OPENSSL_free(key_param); + key_param = tparam; + } X509_STORE_free(store); X509_free(cert); X509_free(recip); @@ -1220,4 +1336,22 @@ static CMS_ReceiptRequest *make_receipt_request(STACK_OF(OPENSSL_STRING) return NULL; } +static int cms_set_pkey_param(EVP_PKEY_CTX *pctx, + STACK_OF(OPENSSL_STRING) *param) +{ + char *keyopt; + int i; + if (sk_OPENSSL_STRING_num(param) <= 0) + return 1; + for (i = 0; i < sk_OPENSSL_STRING_num(param); i++) { + keyopt = sk_OPENSSL_STRING_value(param, i); + if (pkey_ctrl_string(pctx, keyopt) <= 0) { + BIO_printf(bio_err, "parameter error \"%s\"\n", keyopt); + ERR_print_errors(bio_err); + return 0; + } + } + return 1; +} + #endif @@ -96,7 +96,6 @@ static const char *crl_usage[] = { NULL }; -static X509_CRL *load_crl(char *file, int format); static BIO *bio_out = NULL; int MAIN(int, char **); @@ -106,10 +105,10 @@ int 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; + int ret = 1, i, num, badops = 0, badsig = 0; BIO *out = NULL; - int informat, outformat; - char *infile = NULL, *outfile = NULL; + int informat, outformat, keyformat; + char *infile = NULL, *outfile = NULL, *crldiff = NULL, *keyfile = NULL; int hash = 0, issuer = 0, lastupdate = 0, nextupdate = 0, noout = 0, text = 0; #ifndef OPENSSL_NO_MD5 @@ -147,6 +146,7 @@ int MAIN(int argc, char **argv) informat = FORMAT_PEM; outformat = FORMAT_PEM; + keyformat = FORMAT_PEM; argc--; argv++; @@ -173,6 +173,18 @@ int MAIN(int argc, char **argv) if (--argc < 1) goto bad; infile = *(++argv); + } else if (strcmp(*argv, "-gendelta") == 0) { + if (--argc < 1) + goto bad; + crldiff = *(++argv); + } else if (strcmp(*argv, "-key") == 0) { + if (--argc < 1) + goto bad; + keyfile = *(++argv); + } else if (strcmp(*argv, "-keyform") == 0) { + if (--argc < 1) + goto bad; + keyformat = str2fmt(*(++argv)); } else if (strcmp(*argv, "-out") == 0) { if (--argc < 1) goto bad; @@ -214,6 +226,8 @@ int MAIN(int argc, char **argv) fingerprint = ++num; else if (strcmp(*argv, "-crlnumber") == 0) crlnumber = ++num; + else if (strcmp(*argv, "-badsig") == 0) + badsig = 1; else if ((md_alg = EVP_get_digestbyname(*argv + 1))) { /* ok */ digest = md_alg; @@ -281,6 +295,33 @@ int MAIN(int argc, char **argv) BIO_printf(bio_err, "verify OK\n"); } + if (crldiff) { + X509_CRL *newcrl, *delta; + if (!keyfile) { + BIO_puts(bio_err, "Missing CRL signing key\n"); + goto end; + } + newcrl = load_crl(crldiff, informat); + if (!newcrl) + goto end; + pkey = load_key(bio_err, keyfile, keyformat, 0, NULL, NULL, + "CRL signing key"); + if (!pkey) { + X509_CRL_free(newcrl); + goto end; + } + delta = X509_CRL_diff(x, newcrl, pkey, digest, 0); + X509_CRL_free(newcrl); + EVP_PKEY_free(pkey); + if (delta) { + X509_CRL_free(x); + x = delta; + } else { + BIO_puts(bio_err, "Error creating delta CRL\n"); + goto end; + } + } + if (num) { for (i = 1; i <= num; i++) { if (issuer == i) { @@ -369,6 +410,9 @@ int MAIN(int argc, char **argv) goto end; } + if (badsig) + x->signature->data[x->signature->length - 1] ^= 0x1; + if (outformat == FORMAT_ASN1) i = (int)i2d_X509_CRL_bio(out, x); else if (outformat == FORMAT_PEM) @@ -383,6 +427,8 @@ int MAIN(int argc, char **argv) } ret = 0; end: + if (ret != 0) + ERR_print_errors(bio_err); BIO_free_all(out); BIO_free_all(bio_out); bio_out = NULL; @@ -394,41 +440,3 @@ int MAIN(int argc, char **argv) apps_shutdown(); OPENSSL_EXIT(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/apps/dgst.c b/apps/dgst.c index ad2f234..95e5fa3 100644 --- a/apps/dgst.c +++ b/apps/dgst.c @@ -103,7 +103,7 @@ int MAIN(int, char **); int MAIN(int argc, char **argv) { - ENGINE *e = NULL; + ENGINE *e = NULL, *impl = NULL; unsigned char *buf = NULL; int i, err = 1; const EVP_MD *md = NULL, *m; @@ -124,6 +124,7 @@ int MAIN(int argc, char **argv) char *passargin = NULL, *passin = NULL; #ifndef OPENSSL_NO_ENGINE char *engine = NULL; + int engine_impl = 0; #endif char *hmac_key = NULL; char *mac_name = NULL; @@ -199,7 +200,8 @@ int MAIN(int argc, char **argv) break; engine = *(++argv); e = setup_engine(bio_err, engine, 0); - } + } else if (strcmp(*argv, "-engine_impl") == 0) + engine_impl = 1; #endif else if (strcmp(*argv, "-hex") == 0) out_bin = 0; @@ -284,6 +286,10 @@ int MAIN(int argc, char **argv) EVP_MD_do_all_sorted(list_md_fn, bio_err); goto end; } +#ifndef OPENSSL_NO_ENGINE + if (engine_impl) + impl = e; +#endif in = BIO_new(BIO_s_file()); bmd = BIO_new(BIO_f_md()); @@ -357,7 +363,7 @@ int MAIN(int argc, char **argv) if (mac_name) { EVP_PKEY_CTX *mac_ctx = NULL; int r = 0; - if (!init_gen_str(bio_err, &mac_ctx, mac_name, e, 0)) + if (!init_gen_str(bio_err, &mac_ctx, mac_name, impl, 0)) goto mac_end; if (macopts) { char *macopt; @@ -391,7 +397,7 @@ int MAIN(int argc, char **argv) } if (hmac_key) { - sigkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, e, + sigkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, impl, (unsigned char *)hmac_key, -1); if (!sigkey) goto end; @@ -407,9 +413,9 @@ int MAIN(int argc, char **argv) goto end; } if (do_verify) - r = EVP_DigestVerifyInit(mctx, &pctx, md, NULL, sigkey); + r = EVP_DigestVerifyInit(mctx, &pctx, md, impl, sigkey); else - r = EVP_DigestSignInit(mctx, &pctx, md, NULL, sigkey); + r = EVP_DigestSignInit(mctx, &pctx, md, impl, sigkey); if (!r) { BIO_printf(bio_err, "Error setting context\n"); ERR_print_errors(bio_err); @@ -429,9 +435,15 @@ int MAIN(int argc, char **argv) } /* we use md as a filter, reading from 'in' */ else { + EVP_MD_CTX *mctx = NULL; + if (!BIO_get_md_ctx(bmd, &mctx)) { + BIO_printf(bio_err, "Error getting context\n"); + ERR_print_errors(bio_err); + goto end; + } if (md == NULL) md = EVP_md5(); - if (!BIO_set_md(bmd, md)) { + if (!EVP_DigestInit_ex(mctx, md, impl)) { BIO_printf(bio_err, "Error setting digest %s\n", pname); ERR_print_errors(bio_err); goto end; @@ -483,7 +495,8 @@ int MAIN(int argc, char **argv) EVP_PKEY_asn1_get0_info(NULL, NULL, NULL, NULL, &sig_name, ameth); } - md_name = EVP_MD_name(md); + if (md) + md_name = EVP_MD_name(md); } err = 0; for (i = 0; i < argc; i++) { @@ -581,9 +594,12 @@ int do_fp(BIO *out, unsigned char *buf, BIO *bp, int sep, int binout, 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) + if (sig_name) { + BIO_puts(out, sig_name); + if (md_name) + BIO_printf(out, "-%s", md_name); + BIO_printf(out, "(%s)= ", file); + } else if (md_name) BIO_printf(out, "%s(%s)= ", md_name, file); else BIO_printf(out, "(%s)= ", file); diff --git a/apps/dhparam.c b/apps/dhparam.c index d3b6d58..57199a8 100644 --- a/apps/dhparam.c +++ b/apps/dhparam.c @@ -489,9 +489,12 @@ int MAIN(int argc, char **argv) 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 { + else if (outformat == FORMAT_PEM) { + if (dh->q) + i = PEM_write_bio_DHxparams(out, dh); + else + i = PEM_write_bio_DHparams(out, dh); + } else { BIO_printf(bio_err, "bad output format specified for outfile\n"); goto end; } diff --git a/apps/ecparam.c b/apps/ecparam.c index 1f340a9..06ac77b 100644 --- a/apps/ecparam.c +++ b/apps/ecparam.c @@ -370,6 +370,9 @@ int MAIN(int argc, char **argv) } else nid = OBJ_sn2nid(curve_name); + if (nid == 0) + nid = EC_curve_nist2nid(curve_name); + if (nid == 0) { BIO_printf(bio_err, "unknown curve name (%s)\n", curve_name); goto end; diff --git a/apps/genrsa.c b/apps/genrsa.c index 2eabadc..91e6550 100644 --- a/apps/genrsa.c +++ b/apps/genrsa.c @@ -80,7 +80,7 @@ # include <openssl/pem.h> # include <openssl/rand.h> -# define DEFBITS 1024 +# define DEFBITS 2048 # undef PROG # define PROG genrsa_main diff --git a/apps/ocsp.c b/apps/ocsp.c index 572f064..926083d 100644 --- a/apps/ocsp.c +++ b/apps/ocsp.c @@ -110,16 +110,17 @@ static int print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req, 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); + EVP_PKEY *rkey, const EVP_MD *md, + STACK_OF(X509) *rother, unsigned long flags, + int nmin, int ndays, int badsig); static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser); -static BIO *init_responder(char *port); +static BIO *init_responder(const char *port); static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio, - char *port); + const 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, +static OCSP_RESPONSE *query_responder(BIO *err, BIO *cbio, const char *path, + const STACK_OF(CONF_VALUE) *headers, OCSP_REQUEST *req, int req_timeout); # undef PROG @@ -154,12 +155,14 @@ int MAIN(int argc, char **argv) long nsec = MAX_VALIDITY_PERIOD, maxage = -1; char *CAfile = NULL, *CApath = NULL; X509_STORE *store = NULL; + X509_VERIFY_PARAM *vpm = 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 badsig = 0; int i; int ignore_err = 0; STACK_OF(OPENSSL_STRING) *reqnames = NULL; @@ -170,7 +173,7 @@ int MAIN(int argc, char **argv) char *rca_filename = NULL; CA_DB *rdb = NULL; int nmin = 0, ndays = -1; - const EVP_MD *cert_id_md = NULL; + const EVP_MD *cert_id_md = NULL, *rsign_md = NULL; if (bio_err == NULL) bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); @@ -206,6 +209,7 @@ int MAIN(int argc, char **argv) OPENSSL_free(tport); if (tpath) OPENSSL_free(tpath); + thost = tport = tpath = NULL; if (args[1]) { args++; if (!OCSP_parse_url(*args, &host, &port, &path, &use_ssl)) { @@ -264,6 +268,8 @@ int MAIN(int argc, char **argv) verify_flags |= OCSP_TRUSTOTHER; else if (!strcmp(*args, "-no_intern")) verify_flags |= OCSP_NOINTERN; + else if (!strcmp(*args, "-badsig")) + badsig = 1; else if (!strcmp(*args, "-text")) { req_text = 1; resp_text = 1; @@ -320,6 +326,10 @@ int MAIN(int argc, char **argv) CApath = *args; } else badarg = 1; + } else if (args_verify(&args, NULL, &badarg, bio_err, &vpm)) { + if (badarg) + goto end; + continue; } else if (!strcmp(*args, "-validity_period")) { if (args[1]) { args++; @@ -465,6 +475,14 @@ int MAIN(int argc, char **argv) rcertfile = *args; } else badarg = 1; + } else if (!strcmp(*args, "-rmd")) { + if (args[1]) { + args++; + rsign_md = EVP_get_digestbyname(*args); + if (!rsign_md) + badarg = 1; + } else + badarg = 1; } else if ((cert_id_md = EVP_get_digestbyname((*args) + 1)) == NULL) { badarg = 1; } @@ -584,7 +602,10 @@ int MAIN(int argc, char **argv) add_nonce = 0; if (!req && reqin) { - derbio = BIO_new_file(reqin, "rb"); + if (!strcmp(reqin, "-")) + derbio = BIO_new_fp(stdin, BIO_NOCLOSE); + else + derbio = BIO_new_file(reqin, "rb"); if (!derbio) { BIO_printf(bio_err, "Error Opening OCSP request file\n"); goto end; @@ -681,7 +702,10 @@ int MAIN(int argc, char **argv) OCSP_REQUEST_print(out, req, 0); if (reqout) { - derbio = BIO_new_file(reqout, "wb"); + if (!strcmp(reqout, "-")) + derbio = BIO_new_fp(stdout, BIO_NOCLOSE); + else + derbio = BIO_new_file(reqout, "wb"); if (!derbio) { BIO_printf(bio_err, "Error opening file %s\n", reqout); goto end; @@ -706,7 +730,7 @@ int MAIN(int argc, char **argv) if (rdb) { i = make_ocsp_response(&resp, req, rdb, rca_cert, rsigner, rkey, - rother, rflags, nmin, ndays); + rsign_md, rother, rflags, nmin, ndays, badsig); if (cbio) send_ocsp_response(cbio, resp); } else if (host) { @@ -721,7 +745,10 @@ int MAIN(int argc, char **argv) goto end; # endif } else if (respin) { - derbio = BIO_new_file(respin, "rb"); + if (!strcmp(respin, "-")) + derbio = BIO_new_fp(stdin, BIO_NOCLOSE); + else + derbio = BIO_new_file(respin, "rb"); if (!derbio) { BIO_printf(bio_err, "Error Opening OCSP response file\n"); goto end; @@ -741,7 +768,10 @@ int MAIN(int argc, char **argv) done_resp: if (respout) { - derbio = BIO_new_file(respout, "wb"); + if (!strcmp(respout, "-")) + derbio = BIO_new_fp(stdout, BIO_NOCLOSE); + else + derbio = BIO_new_file(respout, "wb"); if (!derbio) { BIO_printf(bio_err, "Error opening file %s\n", respout); goto end; @@ -778,6 +808,10 @@ int MAIN(int argc, char **argv) resp = NULL; goto redo_accept; } + ret = 0; + goto end; + } else if (ridx_filename) { + ret = 0; goto end; } @@ -785,6 +819,8 @@ int MAIN(int argc, char **argv) store = setup_verify(bio_err, CAfile, CApath); if (!store) goto end; + if (vpm) + X509_STORE_set1_param(store, vpm); if (verify_certfile) { verify_other = load_certs(bio_err, verify_certfile, FORMAT_PEM, NULL, e, "validator certificate"); @@ -799,37 +835,38 @@ int MAIN(int argc, char **argv) goto end; } + ret = 0; + 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"); + ret = 1; 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); + ret = 1; } else BIO_printf(bio_err, "Response verify OK\n"); } if (!print_ocsp_summary(out, bs, req, reqnames, ids, nsec, maxage)) - goto end; - - ret = 0; + ret = 1; end: ERR_print_errors(bio_err); X509_free(signer); X509_STORE_free(store); + if (vpm) + X509_VERIFY_PARAM_free(vpm); EVP_PKEY_free(key); EVP_PKEY_free(rkey); X509_free(issuer); @@ -984,8 +1021,9 @@ static int print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req, 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) + EVP_PKEY *rkey, const EVP_MD *rmd, + STACK_OF(X509) *rother, unsigned long flags, + int nmin, int ndays, int badsig) { ASN1_TIME *thisupd = NULL, *nextupd = NULL; OCSP_CERTID *cid, *ca_id = NULL; @@ -1069,7 +1107,10 @@ static int make_ocsp_response(OCSP_RESPONSE **resp, OCSP_REQUEST *req, OCSP_copy_nonce(bs, req); - OCSP_basic_sign(bs, rcert, rkey, NULL, rother, flags); + OCSP_basic_sign(bs, rcert, rkey, rmd, rother, flags); + + if (badsig) + bs->signature->data[bs->signature->length - 1] ^= 0x1; *resp = OCSP_response_create(OCSP_RESPONSE_STATUS_SUCCESSFUL, bs); @@ -1105,7 +1146,7 @@ static char **lookup_serial(CA_DB *db, ASN1_INTEGER *ser) /* Quick and dirty OCSP server: read in and parse input request */ -static BIO *init_responder(char *port) +static BIO *init_responder(const char *port) { BIO *acbio = NULL, *bufbio = NULL; bufbio = BIO_new(BIO_f_buffer()); @@ -1137,7 +1178,7 @@ static BIO *init_responder(char *port) } static int do_responder(OCSP_REQUEST **preq, BIO **pcbio, BIO *acbio, - char *port) + const char *port) { int have_post = 0, len; OCSP_REQUEST *req = NULL; @@ -1198,8 +1239,8 @@ static int send_ocsp_response(BIO *cbio, OCSP_RESPONSE *resp) return 1; } -static OCSP_RESPONSE *query_responder(BIO *err, BIO *cbio, char *path, - STACK_OF(CONF_VALUE) *headers, +static OCSP_RESPONSE *query_responder(BIO *err, BIO *cbio, const char *path, + const STACK_OF(CONF_VALUE) *headers, OCSP_REQUEST *req, int req_timeout) { int fd; @@ -1286,8 +1327,9 @@ static OCSP_RESPONSE *query_responder(BIO *err, BIO *cbio, char *path, } OCSP_RESPONSE *process_responder(BIO *err, OCSP_REQUEST *req, - char *host, char *path, char *port, - int use_ssl, STACK_OF(CONF_VALUE) *headers, + const char *host, const char *path, + const char *port, int use_ssl, + const STACK_OF(CONF_VALUE) *headers, int req_timeout) { BIO *cbio = NULL; diff --git a/apps/openssl.cnf b/apps/openssl.cnf index 18760c6..1eb86c4 100644 --- a/apps/openssl.cnf +++ b/apps/openssl.cnf @@ -103,7 +103,7 @@ emailAddress = optional #################################################################### [ req ] -default_bits = 1024 +default_bits = 2048 default_keyfile = privkey.pem distinguished_name = req_distinguished_name attributes = req_attributes diff --git a/apps/pkcs8.c b/apps/pkcs8.c index 5c7290e..5099e18 100644 --- a/apps/pkcs8.c +++ b/apps/pkcs8.c @@ -124,6 +124,16 @@ int MAIN(int argc, char **argv) } } else badarg = 1; + } else if (!strcmp(*args, "-v2prf")) { + if (args[1]) { + args++; + pbe_nid = OBJ_txt2nid(*args); + if (!EVP_PBE_find(EVP_PBE_TYPE_PRF, pbe_nid, NULL, NULL, 0)) { + BIO_printf(bio_err, "Unknown PRF algorithm %s\n", *args); + badarg = 1; + } + } else + badarg = 1; } else if (!strcmp(*args, "-inform")) { if (args[1]) { args++; diff --git a/apps/s_apps.h b/apps/s_apps.h index 2769b89..5b54bfd 100644 --- a/apps/s_apps.h +++ b/apps/s_apps.h @@ -152,15 +152,21 @@ typedef fd_mask fd_set; #define PROTOCOL "tcp" int do_server(int port, int type, int *ret, - int (*cb) (char *hostname, int s, unsigned char *context), - unsigned char *context); + int (*cb) (char *hostname, int s, int stype, + unsigned char *context), unsigned char *context, + int naccept); #ifdef HEADER_X509_H int MS_CALLBACK 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); +int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key, + STACK_OF(X509) *chain, int build_chain); +int ssl_print_sigalgs(BIO *out, SSL *s); +int ssl_print_point_formats(BIO *out, SSL *s); +int ssl_print_curves(BIO *out, SSL *s, int noshared); #endif +int ssl_print_tmp_key(BIO *out, SSL *s); int init_client(int *sock, char *server, int port, int type); int should_retry(int i); int extract_port(char *str, short *port_ptr); @@ -182,3 +188,24 @@ int MS_CALLBACK generate_cookie_callback(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len); int MS_CALLBACK verify_cookie_callback(SSL *ssl, unsigned char *cookie, unsigned int cookie_len); + +typedef struct ssl_excert_st SSL_EXCERT; + +void ssl_ctx_set_excert(SSL_CTX *ctx, SSL_EXCERT *exc); +void ssl_excert_free(SSL_EXCERT *exc); +int args_excert(char ***pargs, int *pargc, + int *badarg, BIO *err, SSL_EXCERT **pexc); +int load_excert(SSL_EXCERT **pexc, BIO *err); +void print_ssl_summary(BIO *bio, SSL *s); +#ifdef HEADER_SSL_H +int args_ssl(char ***pargs, int *pargc, SSL_CONF_CTX *cctx, + int *badarg, BIO *err, STACK_OF(OPENSSL_STRING) **pstr); +int args_ssl_call(SSL_CTX *ctx, BIO *err, SSL_CONF_CTX *cctx, + STACK_OF(OPENSSL_STRING) *str, int no_ecdhe, int no_jpake); +int ssl_ctx_add_crls(SSL_CTX *ctx, STACK_OF(X509_CRL) *crls, + int crl_download); +int ssl_load_stores(SSL_CTX *ctx, const char *vfyCApath, + const char *vfyCAfile, const char *chCApath, + const char *chCAfile, STACK_OF(X509_CRL) *crls, + int crl_download); +#endif diff --git a/apps/s_cb.c b/apps/s_cb.c index fabf9cf..dd3aa74 100644 --- a/apps/s_cb.c +++ b/apps/s_cb.c @@ -111,7 +111,7 @@ #include <stdio.h> #include <stdlib.h> -#include <string.h> /* for memcpy() */ +#include <string.h> /* for memcpy() and strcmp() */ #define USE_SOCKETS #define NON_MAIN #include "apps.h" @@ -126,6 +126,7 @@ #define COOKIE_SECRET_LENGTH 16 int verify_depth = 0; +int verify_quiet = 0; int verify_error = X509_V_OK; int verify_return_error = 0; unsigned char cookie_secret[COOKIE_SECRET_LENGTH]; @@ -140,13 +141,16 @@ int MS_CALLBACK verify_callback(int ok, X509_STORE_CTX *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 (!verify_quiet || !ok) { + 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)); @@ -179,13 +183,14 @@ int MS_CALLBACK verify_callback(int ok, X509_STORE_CTX *ctx) BIO_printf(bio_err, "\n"); break; case X509_V_ERR_NO_EXPLICIT_POLICY: - policies_print(bio_err, ctx); + if (!verify_quiet) + policies_print(bio_err, ctx); break; } - if (err == X509_V_OK && ok == 2) + if (err == X509_V_OK && ok == 2 && !verify_quiet) policies_print(bio_err, ctx); - - BIO_printf(bio_err, "verify return:%d\n", ok); + if (ok && !verify_quiet) + BIO_printf(bio_err, "verify return:%d\n", ok); return (ok); } @@ -246,8 +251,10 @@ int set_cert_stuff(SSL_CTX *ctx, char *cert_file, char *key_file) return (1); } -int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key) +int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key, + STACK_OF(X509) *chain, int build_chain) { + int chflags = chain ? SSL_BUILD_CHAIN_FLAG_CHECK : 0; if (cert == NULL) return 1; if (SSL_CTX_use_certificate(ctx, cert) <= 0) { @@ -255,6 +262,7 @@ int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key) 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); @@ -269,6 +277,263 @@ int set_cert_key_stuff(SSL_CTX *ctx, X509 *cert, EVP_PKEY *key) "Private key does not match the certificate public key\n"); return 0; } + if (chain && !SSL_CTX_set1_chain(ctx, chain)) { + BIO_printf(bio_err, "error setting certificate chain\n"); + ERR_print_errors(bio_err); + return 0; + } + if (build_chain && !SSL_CTX_build_cert_chain(ctx, chflags)) { + BIO_printf(bio_err, "error building certificate chain\n"); + ERR_print_errors(bio_err); + return 0; + } + return 1; +} + +static void ssl_print_client_cert_types(BIO *bio, SSL *s) +{ + const unsigned char *p; + int i; + int cert_type_num = SSL_get0_certificate_types(s, &p); + if (!cert_type_num) + return; + BIO_puts(bio, "Client Certificate Types: "); + for (i = 0; i < cert_type_num; i++) { + unsigned char cert_type = p[i]; + char *cname; + switch (cert_type) { + case TLS_CT_RSA_SIGN: + cname = "RSA sign"; + break; + + case TLS_CT_DSS_SIGN: + cname = "DSA sign"; + break; + + case TLS_CT_RSA_FIXED_DH: + cname = "RSA fixed DH"; + break; + + case TLS_CT_DSS_FIXED_DH: + cname = "DSS fixed DH"; + break; + + case TLS_CT_ECDSA_SIGN: + cname = "ECDSA sign"; + break; + + case TLS_CT_RSA_FIXED_ECDH: + cname = "RSA fixed ECDH"; + break; + + case TLS_CT_ECDSA_FIXED_ECDH: + cname = "ECDSA fixed ECDH"; + break; + + case TLS_CT_GOST94_SIGN: + cname = "GOST94 Sign"; + break; + + case TLS_CT_GOST01_SIGN: + cname = "GOST01 Sign"; + break; + + default: + cname = NULL; + } + + if (i) + BIO_puts(bio, ", "); + + if (cname) + BIO_puts(bio, cname); + else + BIO_printf(bio, "UNKNOWN (%d),", cert_type); + } + BIO_puts(bio, "\n"); +} + +static int do_print_sigalgs(BIO *out, SSL *s, int shared) +{ + int i, nsig, client; + client = SSL_is_server(s) ? 0 : 1; + if (shared) + nsig = SSL_get_shared_sigalgs(s, -1, NULL, NULL, NULL, NULL, NULL); + else + nsig = SSL_get_sigalgs(s, -1, NULL, NULL, NULL, NULL, NULL); + if (nsig == 0) + return 1; + + if (shared) + BIO_puts(out, "Shared "); + + if (client) + BIO_puts(out, "Requested "); + BIO_puts(out, "Signature Algorithms: "); + for (i = 0; i < nsig; i++) { + int hash_nid, sign_nid; + unsigned char rhash, rsign; + const char *sstr = NULL; + if (shared) + SSL_get_shared_sigalgs(s, i, &sign_nid, &hash_nid, NULL, + &rsign, &rhash); + else + SSL_get_sigalgs(s, i, &sign_nid, &hash_nid, NULL, &rsign, &rhash); + if (i) + BIO_puts(out, ":"); + if (sign_nid == EVP_PKEY_RSA) + sstr = "RSA"; + else if (sign_nid == EVP_PKEY_DSA) + sstr = "DSA"; + else if (sign_nid == EVP_PKEY_EC) + sstr = "ECDSA"; + if (sstr) + BIO_printf(out, "%s+", sstr); + else + BIO_printf(out, "0x%02X+", (int)rsign); + if (hash_nid != NID_undef) + BIO_printf(out, "%s", OBJ_nid2sn(hash_nid)); + else + BIO_printf(out, "0x%02X", (int)rhash); + } + BIO_puts(out, "\n"); + return 1; +} + +int ssl_print_sigalgs(BIO *out, SSL *s) +{ + int mdnid; + if (!SSL_is_server(s)) + ssl_print_client_cert_types(out, s); + do_print_sigalgs(out, s, 0); + do_print_sigalgs(out, s, 1); + if (SSL_get_peer_signature_nid(s, &mdnid)) + BIO_printf(out, "Peer signing digest: %s\n", OBJ_nid2sn(mdnid)); + return 1; +} + +#ifndef OPENSSL_NO_EC +int ssl_print_point_formats(BIO *out, SSL *s) +{ + int i, nformats; + const char *pformats; + nformats = SSL_get0_ec_point_formats(s, &pformats); + if (nformats <= 0) + return 1; + BIO_puts(out, "Supported Elliptic Curve Point Formats: "); + for (i = 0; i < nformats; i++, pformats++) { + if (i) + BIO_puts(out, ":"); + switch (*pformats) { + case TLSEXT_ECPOINTFORMAT_uncompressed: + BIO_puts(out, "uncompressed"); + break; + + case TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime: + BIO_puts(out, "ansiX962_compressed_prime"); + break; + + case TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2: + BIO_puts(out, "ansiX962_compressed_char2"); + break; + + default: + BIO_printf(out, "unknown(%d)", (int)*pformats); + break; + + } + } + if (nformats <= 0) + BIO_puts(out, "NONE"); + BIO_puts(out, "\n"); + return 1; +} + +int ssl_print_curves(BIO *out, SSL *s, int noshared) +{ + int i, ncurves, *curves, nid; + const char *cname; + ncurves = SSL_get1_curves(s, NULL); + if (ncurves <= 0) + return 1; + curves = OPENSSL_malloc(ncurves * sizeof(int)); + if (!curves) { + BIO_puts(out, "Malloc error getting supported curves\n"); + return 0; + } + SSL_get1_curves(s, curves); + + + BIO_puts(out, "Supported Elliptic Curves: "); + for (i = 0; i < ncurves; i++) { + if (i) + BIO_puts(out, ":"); + nid = curves[i]; + /* If unrecognised print out hex version */ + if (nid & TLSEXT_nid_unknown) + BIO_printf(out, "0x%04X", nid & 0xFFFF); + else { + /* Use NIST name for curve if it exists */ + cname = EC_curve_nid2nist(nid); + if (!cname) + cname = OBJ_nid2sn(nid); + BIO_printf(out, "%s", cname); + } + } + if (ncurves == 0) + BIO_puts(out, "NONE"); + OPENSSL_free(curves); + if (noshared) { + BIO_puts(out, "\n"); + return 1; + } + BIO_puts(out, "\nShared Elliptic curves: "); + ncurves = SSL_get_shared_curve(s, -1); + for (i = 0; i < ncurves; i++) { + if (i) + BIO_puts(out, ":"); + nid = SSL_get_shared_curve(s, i); + cname = EC_curve_nid2nist(nid); + if (!cname) + cname = OBJ_nid2sn(nid); + BIO_printf(out, "%s", cname); + } + if (ncurves == 0) + BIO_puts(out, "NONE"); + BIO_puts(out, "\n"); + return 1; +} +#endif +int ssl_print_tmp_key(BIO *out, SSL *s) +{ + EVP_PKEY *key; + if (!SSL_get_server_tmp_key(s, &key)) + return 1; + BIO_puts(out, "Server Temp Key: "); + switch (EVP_PKEY_id(key)) { + case EVP_PKEY_RSA: + BIO_printf(out, "RSA, %d bits\n", EVP_PKEY_bits(key)); + break; + + case EVP_PKEY_DH: + BIO_printf(out, "DH, %d bits\n", EVP_PKEY_bits(key)); + break; +#ifndef OPENSSL_NO_ECDH + case EVP_PKEY_EC: + { + EC_KEY *ec = EVP_PKEY_get1_EC_KEY(key); + int nid; + const char *cname; + nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec)); + EC_KEY_free(ec); + cname = EC_curve_nid2nist(nid); + if (!cname) + cname = OBJ_nid2sn(nid); + BIO_printf(out, "ECDH, %s, %d bits\n", cname, EVP_PKEY_bits(key)); + } +#endif + } + EVP_PKEY_free(key); return 1; } @@ -884,3 +1149,504 @@ int MS_CALLBACK verify_cookie_callback(SSL *ssl, unsigned char *cookie, return 0; } + +/* + * Example of extended certificate handling. Where the standard support of + * one certificate per algorithm is not sufficient an application can decide + * which certificate(s) to use at runtime based on whatever criteria it deems + * appropriate. + */ + +/* Linked list of certificates, keys and chains */ +struct ssl_excert_st { + int certform; + const char *certfile; + int keyform; + const char *keyfile; + const char *chainfile; + X509 *cert; + EVP_PKEY *key; + STACK_OF(X509) *chain; + int build_chain; + struct ssl_excert_st *next, *prev; +}; + +struct chain_flags { + int flag; + const char *name; +}; + +struct chain_flags chain_flags_list[] = { + {CERT_PKEY_VALID, "Overall Validity"}, + {CERT_PKEY_SIGN, "Sign with EE key"}, + {CERT_PKEY_EE_SIGNATURE, "EE signature"}, + {CERT_PKEY_CA_SIGNATURE, "CA signature"}, + {CERT_PKEY_EE_PARAM, "EE key parameters"}, + {CERT_PKEY_CA_PARAM, "CA key parameters"}, + {CERT_PKEY_EXPLICIT_SIGN, "Explicity sign with EE key"}, + {CERT_PKEY_ISSUER_NAME, "Issuer Name"}, + {CERT_PKEY_CERT_TYPE, "Certificate Type"}, + {0, NULL} +}; + +static void print_chain_flags(BIO *out, SSL *s, int flags) +{ + struct chain_flags *ctmp = chain_flags_list; + while (ctmp->name) { + BIO_printf(out, "\t%s: %s\n", ctmp->name, + flags & ctmp->flag ? "OK" : "NOT OK"); + ctmp++; + } + BIO_printf(out, "\tSuite B: "); + if (SSL_set_cert_flags(s, 0) & SSL_CERT_FLAG_SUITEB_128_LOS) + BIO_puts(out, flags & CERT_PKEY_SUITEB ? "OK\n" : "NOT OK\n"); + else + BIO_printf(out, "not tested\n"); +} + +/* + * Very basic selection callback: just use any certificate chain reported as + * valid. More sophisticated could prioritise according to local policy. + */ +static int set_cert_cb(SSL *ssl, void *arg) +{ + int i, rv; + SSL_EXCERT *exc = arg; +#ifdef CERT_CB_TEST_RETRY + static int retry_cnt; + if (retry_cnt < 5) { + retry_cnt++; + fprintf(stderr, "Certificate callback retry test: count %d\n", + retry_cnt); + return -1; + } +#endif + SSL_certs_clear(ssl); + + if (!exc) + return 1; + + /* + * Go to end of list and traverse backwards since we prepend newer + * entries this retains the original order. + */ + while (exc->next) + exc = exc->next; + + i = 0; + + while (exc) { + i++; + rv = SSL_check_chain(ssl, exc->cert, exc->key, exc->chain); + BIO_printf(bio_err, "Checking cert chain %d:\nSubject: ", i); + X509_NAME_print_ex(bio_err, X509_get_subject_name(exc->cert), 0, + XN_FLAG_ONELINE); + BIO_puts(bio_err, "\n"); + + print_chain_flags(bio_err, ssl, rv); + if (rv & CERT_PKEY_VALID) { + SSL_use_certificate(ssl, exc->cert); + SSL_use_PrivateKey(ssl, exc->key); + /* + * NB: we wouldn't normally do this as it is not efficient + * building chains on each connection better to cache the chain + * in advance. + */ + if (exc->build_chain) { + if (!SSL_build_cert_chain(ssl, 0)) + return 0; + } else if (exc->chain) + SSL_set1_chain(ssl, exc->chain); + } + exc = exc->prev; + } + return 1; +} + +void ssl_ctx_set_excert(SSL_CTX *ctx, SSL_EXCERT *exc) +{ + SSL_CTX_set_cert_cb(ctx, set_cert_cb, exc); +} + +static int ssl_excert_prepend(SSL_EXCERT **pexc) +{ + SSL_EXCERT *exc; + exc = OPENSSL_malloc(sizeof(SSL_EXCERT)); + if (!exc) + return 0; + exc->certfile = NULL; + exc->keyfile = NULL; + exc->chainfile = NULL; + exc->cert = NULL; + exc->key = NULL; + exc->chain = NULL; + exc->prev = NULL; + exc->build_chain = 0; + + exc->next = *pexc; + *pexc = exc; + + if (exc->next) { + exc->certform = exc->next->certform; + exc->keyform = exc->next->keyform; + exc->next->prev = exc; + } else { + exc->certform = FORMAT_PEM; + exc->keyform = FORMAT_PEM; + } + return 1; + +} + +void ssl_excert_free(SSL_EXCERT *exc) +{ + SSL_EXCERT *curr; + while (exc) { + if (exc->cert) + X509_free(exc->cert); + if (exc->key) + EVP_PKEY_free(exc->key); + if (exc->chain) + sk_X509_pop_free(exc->chain, X509_free); + curr = exc; + exc = exc->next; + OPENSSL_free(curr); + } +} + +int load_excert(SSL_EXCERT **pexc, BIO *err) +{ + SSL_EXCERT *exc = *pexc; + if (!exc) + return 1; + /* If nothing in list, free and set to NULL */ + if (!exc->certfile && !exc->next) { + ssl_excert_free(exc); + *pexc = NULL; + return 1; + } + for (; exc; exc = exc->next) { + if (!exc->certfile) { + BIO_printf(err, "Missing filename\n"); + return 0; + } + exc->cert = load_cert(err, exc->certfile, exc->certform, + NULL, NULL, "Server Certificate"); + if (!exc->cert) + return 0; + if (exc->keyfile) { + exc->key = load_key(err, exc->keyfile, exc->keyform, + 0, NULL, NULL, "Server Key"); + } else { + exc->key = load_key(err, exc->certfile, exc->certform, + 0, NULL, NULL, "Server Key"); + } + if (!exc->key) + return 0; + if (exc->chainfile) { + exc->chain = load_certs(err, + exc->chainfile, FORMAT_PEM, + NULL, NULL, "Server Chain"); + if (!exc->chain) + return 0; + } + } + return 1; +} + +int args_excert(char ***pargs, int *pargc, + int *badarg, BIO *err, SSL_EXCERT **pexc) +{ + char *arg = **pargs, *argn = (*pargs)[1]; + SSL_EXCERT *exc = *pexc; + int narg = 2; + if (!exc) { + if (ssl_excert_prepend(&exc)) + *pexc = exc; + else { + BIO_printf(err, "Error initialising xcert\n"); + *badarg = 1; + goto err; + } + } + if (strcmp(arg, "-xcert") == 0) { + if (!argn) { + *badarg = 1; + return 1; + } + if (exc->certfile && !ssl_excert_prepend(&exc)) { + BIO_printf(err, "Error adding xcert\n"); + *badarg = 1; + goto err; + } + exc->certfile = argn; + } else if (strcmp(arg, "-xkey") == 0) { + if (!argn) { + *badarg = 1; + return 1; + } + if (exc->keyfile) { + BIO_printf(err, "Key already specified\n"); + *badarg = 1; + return 1; + } + exc->keyfile = argn; + } else if (strcmp(arg, "-xchain") == 0) { + if (!argn) { + *badarg = 1; + return 1; + } + if (exc->chainfile) { + BIO_printf(err, "Chain already specified\n"); + *badarg = 1; + return 1; + } + exc->chainfile = argn; + } else if (strcmp(arg, "-xchain_build") == 0) { + narg = 1; + exc->build_chain = 1; + } else if (strcmp(arg, "-xcertform") == 0) { + if (!argn) { + *badarg = 1; + goto err; + } + exc->certform = str2fmt(argn); + } else if (strcmp(arg, "-xkeyform") == 0) { + if (!argn) { + *badarg = 1; + goto err; + } + exc->keyform = str2fmt(argn); + } else + return 0; + + (*pargs) += narg; + + if (pargc) + *pargc -= narg; + + *pexc = exc; + + return 1; + + err: + ERR_print_errors(err); + ssl_excert_free(exc); + *pexc = NULL; + return 1; +} + +static void print_raw_cipherlist(BIO *bio, SSL *s) +{ + const unsigned char *rlist; + static const unsigned char scsv_id[] = { 0, 0, 0xFF }; + size_t i, rlistlen, num; + if (!SSL_is_server(s)) + return; + num = SSL_get0_raw_cipherlist(s, NULL); + rlistlen = SSL_get0_raw_cipherlist(s, &rlist); + BIO_puts(bio, "Client cipher list: "); + for (i = 0; i < rlistlen; i += num, rlist += num) { + const SSL_CIPHER *c = SSL_CIPHER_find(s, rlist); + if (i) + BIO_puts(bio, ":"); + if (c) + BIO_puts(bio, SSL_CIPHER_get_name(c)); + else if (!memcmp(rlist, scsv_id - num + 3, num)) + BIO_puts(bio, "SCSV"); + else { + size_t j; + BIO_puts(bio, "0x"); + for (j = 0; j < num; j++) + BIO_printf(bio, "%02X", rlist[j]); + } + } + BIO_puts(bio, "\n"); +} + +void print_ssl_summary(BIO *bio, SSL *s) +{ + const SSL_CIPHER *c; + X509 *peer; + /* + * const char *pnam = SSL_is_server(s) ? "client" : "server"; + */ + BIO_printf(bio, "Protocol version: %s\n", SSL_get_version(s)); + print_raw_cipherlist(bio, s); + c = SSL_get_current_cipher(s); + BIO_printf(bio, "Ciphersuite: %s\n", SSL_CIPHER_get_name(c)); + do_print_sigalgs(bio, s, 0); + peer = SSL_get_peer_certificate(s); + if (peer) { + int nid; + BIO_puts(bio, "Peer certificate: "); + X509_NAME_print_ex(bio, X509_get_subject_name(peer), + 0, XN_FLAG_ONELINE); + BIO_puts(bio, "\n"); + if (SSL_get_peer_signature_nid(s, &nid)) + BIO_printf(bio, "Hash used: %s\n", OBJ_nid2sn(nid)); + } else + BIO_puts(bio, "No peer certificate\n"); + if (peer) + X509_free(peer); +#ifndef OPENSSL_NO_EC + ssl_print_point_formats(bio, s); + if (SSL_is_server(s)) + ssl_print_curves(bio, s, 1); + else + ssl_print_tmp_key(bio, s); +#else + if (!SSL_is_server(s)) + ssl_print_tmp_key(bio, s); +#endif +} + +int args_ssl(char ***pargs, int *pargc, SSL_CONF_CTX *cctx, + int *badarg, BIO *err, STACK_OF(OPENSSL_STRING) **pstr) +{ + char *arg = **pargs, *argn = (*pargs)[1]; + int rv; + + /* Attempt to run SSL configuration command */ + rv = SSL_CONF_cmd_argv(cctx, pargc, pargs); + /* If parameter not recognised just return */ + if (rv == 0) + return 0; + /* see if missing argument error */ + if (rv == -3) { + BIO_printf(err, "%s needs an argument\n", arg); + *badarg = 1; + goto end; + } + /* Check for some other error */ + if (rv < 0) { + BIO_printf(err, "Error with command: \"%s %s\"\n", + arg, argn ? argn : ""); + *badarg = 1; + goto end; + } + /* Store command and argument */ + /* If only one argument processed store value as NULL */ + if (rv == 1) + argn = NULL; + if (!*pstr) + *pstr = sk_OPENSSL_STRING_new_null(); + if (!*pstr || !sk_OPENSSL_STRING_push(*pstr, arg) || + !sk_OPENSSL_STRING_push(*pstr, argn)) { + BIO_puts(err, "Memory allocation failure\n"); + goto end; + } + + end: + if (*badarg) + ERR_print_errors(err); + + return 1; +} + +int args_ssl_call(SSL_CTX *ctx, BIO *err, SSL_CONF_CTX *cctx, + STACK_OF(OPENSSL_STRING) *str, int no_ecdhe, int no_jpake) +{ + int i; + SSL_CONF_CTX_set_ssl_ctx(cctx, ctx); + for (i = 0; i < sk_OPENSSL_STRING_num(str); i += 2) { + const char *param = sk_OPENSSL_STRING_value(str, i); + const char *value = sk_OPENSSL_STRING_value(str, i + 1); + /* + * If no_ecdhe or named curve already specified don't need a default. + */ + if (!no_ecdhe && !strcmp(param, "-named_curve")) + no_ecdhe = 1; +#ifndef OPENSSL_NO_JPAKE + if (!no_jpake && !strcmp(param, "-cipher")) { + BIO_puts(err, "JPAKE sets cipher to PSK\n"); + return 0; + } +#endif + if (SSL_CONF_cmd(cctx, param, value) <= 0) { + BIO_printf(err, "Error with command: \"%s %s\"\n", + param, value ? value : ""); + ERR_print_errors(err); + return 0; + } + } + /* + * This is a special case to keep existing s_server functionality: if we + * don't have any curve specified *and* we haven't disabled ECDHE then + * use P-256. + */ + if (!no_ecdhe) { + if (SSL_CONF_cmd(cctx, "-named_curve", "P-256") <= 0) { + BIO_puts(err, "Error setting EC curve\n"); + ERR_print_errors(err); + return 0; + } + } +#ifndef OPENSSL_NO_JPAKE + if (!no_jpake) { + if (SSL_CONF_cmd(cctx, "-cipher", "PSK") <= 0) { + BIO_puts(err, "Error setting cipher to PSK\n"); + ERR_print_errors(err); + return 0; + } + } +#endif + if (!SSL_CONF_CTX_finish(cctx)) { + BIO_puts(err, "Error finishing context\n"); + ERR_print_errors(err); + return 0; + } + return 1; +} + +static int add_crls_store(X509_STORE *st, STACK_OF(X509_CRL) *crls) +{ + X509_CRL *crl; + int i; + for (i = 0; i < sk_X509_CRL_num(crls); i++) { + crl = sk_X509_CRL_value(crls, i); + X509_STORE_add_crl(st, crl); + } + return 1; +} + +int ssl_ctx_add_crls(SSL_CTX *ctx, STACK_OF(X509_CRL) *crls, int crl_download) +{ + X509_STORE *st; + st = SSL_CTX_get_cert_store(ctx); + add_crls_store(st, crls); + if (crl_download) + store_setup_crl_download(st); + return 1; +} + +int ssl_load_stores(SSL_CTX *ctx, + const char *vfyCApath, const char *vfyCAfile, + const char *chCApath, const char *chCAfile, + STACK_OF(X509_CRL) *crls, int crl_download) +{ + X509_STORE *vfy = NULL, *ch = NULL; + int rv = 0; + if (vfyCApath || vfyCAfile) { + vfy = X509_STORE_new(); + if (!X509_STORE_load_locations(vfy, vfyCAfile, vfyCApath)) + goto err; + add_crls_store(vfy, crls); + SSL_CTX_set1_verify_cert_store(ctx, vfy); + if (crl_download) + store_setup_crl_download(vfy); + } + if (chCApath || chCAfile) { + ch = X509_STORE_new(); + if (!X509_STORE_load_locations(ch, chCAfile, chCApath)) + goto err; + SSL_CTX_set1_chain_cert_store(ctx, ch); + } + rv = 1; + err: + if (vfy) + X509_STORE_free(vfy); + if (ch) + X509_STORE_free(ch); + return rv; +} diff --git a/apps/s_client.c b/apps/s_client.c index 28737b6..e55f2c5 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -202,6 +202,7 @@ typedef unsigned int u_int; extern int verify_depth; extern int verify_error; extern int verify_return_error; +extern int verify_quiet; #ifdef FIONBIO static int c_nbio = 0; @@ -224,8 +225,10 @@ static void print_stuff(BIO *berr, SSL *con, int full); static int ocsp_resp_cb(SSL *s, void *arg); #endif static BIO *bio_c_out = NULL; +static BIO *bio_c_msg = NULL; static int c_quiet = 0; static int c_ign_eof = 0; +static int c_brief = 0; #ifndef OPENSSL_NO_PSK /* Default PSK identity and key */ @@ -304,6 +307,12 @@ static void sc_usage(void) 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_host host - check peer certificate matches \"host\"\n"); + BIO_printf(bio_err, + " -verify_email email - check peer certificate matches \"email\"\n"); + BIO_printf(bio_err, + " -verify_ip ipaddr - check peer certificate matches \"ipaddr\"\n"); BIO_printf(bio_err, " -verify arg - turn on peer certificate verification\n"); @@ -413,12 +422,16 @@ static void sc_usage(void) " -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, + " -serverinfo types - send empty ClientHello extensions (comma-separated numbers)\n"); +#endif +#ifndef OPENSSL_NO_NEXTPROTONEG BIO_printf(bio_err, " -nextprotoneg arg - enable NPN extension, considering named protocols supported (comma-separated list)\n"); -# endif #endif BIO_printf(bio_err, + " -alpn arg - enable ALPN extension, considering named protocols supported (comma-separated list)\n"); + BIO_printf(bio_err, " -legacy_renegotiation - enable use of legacy renegotiation (dangerous)\n"); #ifndef OPENSSL_NO_SRTP BIO_printf(bio_err, @@ -605,6 +618,27 @@ static int next_proto_cb(SSL *s, unsigned char **out, unsigned char *outlen, return SSL_TLSEXT_ERR_OK; } # endif /* ndef OPENSSL_NO_NEXTPROTONEG */ + +static int serverinfo_cli_parse_cb(SSL *s, unsigned int ext_type, + const unsigned char *in, size_t inlen, + int *al, void *arg) +{ + char pem_name[100]; + unsigned char ext_buf[4 + 65536]; + + /* Reconstruct the type/len fields prior to extension data */ + ext_buf[0] = ext_type >> 8; + ext_buf[1] = ext_type & 0xFF; + ext_buf[2] = inlen >> 8; + ext_buf[3] = inlen & 0xFF; + memcpy(ext_buf + 4, in, inlen); + + BIO_snprintf(pem_name, sizeof(pem_name), "SERVERINFO FOR EXTENSION %d", + ext_type); + PEM_write_bio(bio_c_out, pem_name, "", ext_buf, 4 + inlen); + return 1; +} + #endif enum { @@ -620,7 +654,7 @@ int MAIN(int, char **); int MAIN(int argc, char **argv) { - unsigned int off = 0, clr = 0; + int build_chain = 0; SSL *con = NULL; #ifndef OPENSSL_NO_KRB5 KSSL_CTX *kctx; @@ -633,13 +667,16 @@ int MAIN(int argc, char **argv) short port = PORT; int full_log = 1; char *host = SSL_HOST_NAME; - char *cert_file = NULL, *key_file = NULL; + char *cert_file = NULL, *key_file = NULL, *chain_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; + STACK_OF(X509) *chain = NULL; + char *CApath = NULL, *CAfile = NULL; + char *chCApath = NULL, *chCAfile = NULL; + char *vfyCApath = NULL, *vfyCAfile = NULL; + int reconnect = 0, badop = 0, verify = SSL_VERIFY_NONE; int crlf = 0; int write_tty, read_tty, write_ssl, read_ssl, tty_on, ssl_pending; SSL_CTX *ctx = NULL; @@ -672,6 +709,10 @@ int MAIN(int argc, char **argv) # ifndef OPENSSL_NO_NEXTPROTONEG const char *next_proto_neg_in = NULL; # endif + const char *alpn_in = NULL; +# define MAX_SI_TYPES 100 + unsigned short serverinfo_types[MAX_SI_TYPES]; + int serverinfo_types_count = 0; #endif char *sess_in = NULL; char *sess_out = NULL; @@ -681,13 +722,25 @@ int MAIN(int argc, char **argv) int enable_timeouts = 0; long socket_mtu = 0; #ifndef OPENSSL_NO_JPAKE - char *jpake_secret = NULL; + static char *jpake_secret = NULL; +# define no_jpake !jpake_secret +#else +# define no_jpake 1 #endif #ifndef OPENSSL_NO_SRP char *srppass = NULL; int srp_lateuser = 0; SRP_ARG srp_arg = { NULL, NULL, 0, 0, 0, 1024 }; #endif + SSL_EXCERT *exc = NULL; + + SSL_CONF_CTX *cctx = NULL; + STACK_OF(OPENSSL_STRING) *ssl_args = NULL; + + char *crl_file = NULL; + int crl_format = FORMAT_PEM; + int crl_download = 0; + STACK_OF(X509_CRL) *crls = NULL; meth = SSLv23_client_method(); @@ -705,6 +758,12 @@ int MAIN(int argc, char **argv) if (!load_config(bio_err, NULL)) goto end; + cctx = SSL_CONF_CTX_new(); + if (!cctx) + goto end; + SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CLIENT); + SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CMDLINE); + if (((cbuf = OPENSSL_malloc(BUFSIZZ)) == NULL) || ((sbuf = OPENSSL_malloc(BUFSIZZ)) == NULL) || ((mbuf = OPENSSL_malloc(BUFSIZZ)) == NULL)) { @@ -741,12 +800,19 @@ int MAIN(int argc, char **argv) if (--argc < 1) goto bad; verify_depth = atoi(*(++argv)); - BIO_printf(bio_err, "verify depth is %d\n", verify_depth); + if (!c_quiet) + 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) { + } else if (strcmp(*argv, "-CRL") == 0) { + if (--argc < 1) + goto bad; + crl_file = *(++argv); + } else if (strcmp(*argv, "-crl_download") == 0) + crl_download = 1; + else if (strcmp(*argv, "-sess_out") == 0) { if (--argc < 1) goto bad; sess_out = *(++argv); @@ -758,13 +824,31 @@ int MAIN(int argc, char **argv) if (--argc < 1) goto bad; cert_format = str2fmt(*(++argv)); + } else if (strcmp(*argv, "-CRLform") == 0) { + if (--argc < 1) + goto bad; + crl_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) + else if (strcmp(*argv, "-verify_quiet") == 0) + verify_quiet = 1; + else if (strcmp(*argv, "-brief") == 0) { + c_brief = 1; + verify_quiet = 1; + c_quiet = 1; + } else if (args_excert(&argv, &argc, &badarg, bio_err, &exc)) { + if (badarg) + goto bad; + continue; + } else if (args_ssl(&argv, &argc, cctx, &badarg, bio_err, &ssl_args)) { + if (badarg) + goto bad; + continue; + } else if (strcmp(*argv, "-prexit") == 0) prexit = 1; else if (strcmp(*argv, "-crlf") == 0) crlf = 1; @@ -791,6 +875,15 @@ int MAIN(int argc, char **argv) #endif else if (strcmp(*argv, "-msg") == 0) c_msg = 1; + else if (strcmp(*argv, "-msgfile") == 0) { + if (--argc < 1) + goto bad; + bio_c_msg = BIO_new_file(*(++argv), "w"); + } +#ifndef OPENSSL_NO_SSL_TRACE + else if (strcmp(*argv, "-trace") == 0) + c_msg = 2; +#endif else if (strcmp(*argv, "-showcerts") == 0) c_showcerts = 1; else if (strcmp(*argv, "-nbio_test") == 0) @@ -859,11 +952,15 @@ int MAIN(int argc, char **argv) meth = TLSv1_client_method(); #endif #ifndef OPENSSL_NO_DTLS1 - else if (strcmp(*argv, "-dtls1") == 0) { + else if (strcmp(*argv, "-dtls") == 0) { + meth = DTLS_client_method(); + socket_type = SOCK_DGRAM; + } else if (strcmp(*argv, "-dtls1") == 0) { meth = DTLSv1_client_method(); socket_type = SOCK_DGRAM; - } else if (strcmp(*argv, "-fallback_scsv") == 0) { - fallback_scsv = 1; + } else if (strcmp(*argv, "-dtls1_2") == 0) { + meth = DTLSv1_2_client_method(); + socket_type = SOCK_DGRAM; } else if (strcmp(*argv, "-timeout") == 0) enable_timeouts = 1; else if (strcmp(*argv, "-mtu") == 0) { @@ -872,9 +969,9 @@ int MAIN(int argc, char **argv) socket_mtu = atol(*(++argv)); } #endif - else if (strcmp(*argv, "-bugs") == 0) - bugs = 1; - else if (strcmp(*argv, "-keyform") == 0) { + else if (strcmp(*argv, "-fallback_scsv") == 0) { + fallback_scsv = 1; + } else if (strcmp(*argv, "-keyform") == 0) { if (--argc < 1) goto bad; key_format = str2fmt(*(++argv)); @@ -882,6 +979,10 @@ int MAIN(int argc, char **argv) if (--argc < 1) goto bad; passarg = *(++argv); + } else if (strcmp(*argv, "-cert_chain") == 0) { + if (--argc < 1) + goto bad; + chain_file = *(++argv); } else if (strcmp(*argv, "-key") == 0) { if (--argc < 1) goto bad; @@ -892,27 +993,30 @@ int MAIN(int argc, char **argv) if (--argc < 1) goto bad; CApath = *(++argv); - } else if (strcmp(*argv, "-CAfile") == 0) { + } else if (strcmp(*argv, "-chainCApath") == 0) { + if (--argc < 1) + goto bad; + chCApath = *(++argv); + } else if (strcmp(*argv, "-verifyCApath") == 0) { + if (--argc < 1) + goto bad; + vfyCApath = *(++argv); + } else if (strcmp(*argv, "-build_chain") == 0) + build_chain = 1; + else if (strcmp(*argv, "-CAfile") == 0) { if (--argc < 1) goto bad; CAfile = *(++argv); - } else if (strcmp(*argv, "-no_tls1_2") == 0) - off |= SSL_OP_NO_TLSv1_2; - else if (strcmp(*argv, "-no_tls1_1") == 0) - off |= SSL_OP_NO_TLSv1_1; - else if (strcmp(*argv, "-no_tls1") == 0) - off |= SSL_OP_NO_TLSv1; - else if (strcmp(*argv, "-no_ssl3") == 0) - off |= SSL_OP_NO_SSLv3; - else if (strcmp(*argv, "-no_ssl2") == 0) - off |= SSL_OP_NO_SSLv2; - else if (strcmp(*argv, "-no_comp") == 0) { - off |= SSL_OP_NO_COMPRESSION; + } else if (strcmp(*argv, "-chainCAfile") == 0) { + if (--argc < 1) + goto bad; + chCAfile = *(++argv); + } else if (strcmp(*argv, "-verifyCAfile") == 0) { + if (--argc < 1) + goto bad; + vfyCAfile = *(++argv); } #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) @@ -920,20 +1024,32 @@ int MAIN(int argc, char **argv) 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) - off |= SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION; - 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) { + else if (strcmp(*argv, "-alpn") == 0) { + if (--argc < 1) + goto bad; + alpn_in = *(++argv); + } else if (strcmp(*argv, "-serverinfo") == 0) { + char *c; + int start = 0; + int len; + if (--argc < 1) goto bad; - cipher = *(++argv); + c = *(++argv); + serverinfo_types_count = 0; + len = strlen(c); + for (i = 0; i <= len; ++i) { + if (i == len || c[i] == ',') { + serverinfo_types[serverinfo_types_count] + = atoi(c + start); + serverinfo_types_count++; + start = i + 1; + } + if (serverinfo_types_count == MAX_SI_TYPES) + break; + } } +#endif #ifdef FIONBIO else if (strcmp(*argv, "-nbio") == 0) { c_nbio = 1; @@ -1024,11 +1140,6 @@ int MAIN(int argc, char **argv) goto end; } psk_identity = "JPAKE"; - if (cipher) { - BIO_printf(bio_err, "JPAKE sets cipher to PSK\n"); - goto end; - } - cipher = "PSK"; } #endif @@ -1087,6 +1198,33 @@ int MAIN(int argc, char **argv) } } + if (chain_file) { + chain = load_certs(bio_err, chain_file, FORMAT_PEM, + NULL, e, "client certificate chain"); + if (!chain) + goto end; + } + + if (crl_file) { + X509_CRL *crl; + crl = load_crl(crl_file, crl_format); + if (!crl) { + BIO_puts(bio_err, "Error loading CRL\n"); + ERR_print_errors(bio_err); + goto end; + } + crls = sk_X509_CRL_new_null(); + if (!crls || !sk_X509_CRL_push(crls, crl)) { + BIO_puts(bio_err, "Error adding CRL\n"); + ERR_print_errors(bio_err); + X509_CRL_free(crl); + goto end; + } + } + + if (!load_excert(&exc, bio_err)) + goto end; + if (!app_RAND_load_file(NULL, bio_err, 1) && inrand == NULL && !RAND_status()) { BIO_printf(bio_err, @@ -1097,8 +1235,10 @@ int MAIN(int argc, char **argv) app_RAND_load_files(inrand)); if (bio_c_out == NULL) { - if (c_quiet && !c_debug && !c_msg) { + if (c_quiet && !c_debug) { bio_c_out = BIO_new(BIO_s_null()); + if (c_msg && !bio_c_msg) + bio_c_msg = BIO_new_fp(stdout, BIO_NOCLOSE); } else { if (bio_c_out == NULL) bio_c_out = BIO_new_fp(stdout, BIO_NOCLOSE); @@ -1120,6 +1260,17 @@ int MAIN(int argc, char **argv) if (vpm) SSL_CTX_set1_param(ctx, vpm); + if (!args_ssl_call(ctx, bio_err, cctx, ssl_args, 1, no_jpake)) { + ERR_print_errors(bio_err); + goto end; + } + + if (!ssl_load_stores(ctx, vfyCApath, vfyCAfile, chCApath, chCAfile, + crls, crl_download)) { + BIO_printf(bio_err, "Error loading store locations\n"); + ERR_print_errors(bio_err); + goto end; + } #ifndef OPENSSL_NO_ENGINE if (ssl_client_engine) { if (!SSL_CTX_set_client_cert_engine(ctx, ssl_client_engine)) { @@ -1149,35 +1300,43 @@ int MAIN(int argc, char **argv) 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 (exc) + ssl_ctx_set_excert(ctx, exc); - if (clr) - SSL_CTX_clear_options(ctx, clr); - -#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) +#if !defined(OPENSSL_NO_TLSEXT) +# if !defined(OPENSSL_NO_NEXTPROTONEG) if (next_proto.data) SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &next_proto); +# endif + if (alpn_in) { + unsigned short alpn_len; + unsigned char *alpn = next_protos_parse(&alpn_len, alpn_in); + + if (alpn == NULL) { + BIO_printf(bio_err, "Error parsing -alpn argument\n"); + goto end; + } + SSL_CTX_set_alpn_protos(ctx, alpn, alpn_len); + OPENSSL_free(alpn); + } +#endif +#ifndef OPENSSL_NO_TLSEXT + for (i = 0; i < serverinfo_types_count; i++) { + SSL_CTX_add_client_custom_ext(ctx, + serverinfo_types[i], + NULL, NULL, NULL, + serverinfo_cli_parse_cb, NULL); + } #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; - } #if 0 - else - SSL_CTX_set_cipher_list(ctx, getenv("SSL_CIPHER")); + else + SSL_CTX_set_cipher_list(ctx, getenv("SSL_CIPHER")); #endif SSL_CTX_set_verify(ctx, verify, verify_callback); - if (!set_cert_key_stuff(ctx, cert, key)) - goto end; if ((CAfile || CApath) && !SSL_CTX_load_verify_locations(ctx, CAfile, CApath)) { @@ -1186,6 +1345,11 @@ int MAIN(int argc, char **argv) if (!SSL_CTX_set_default_verify_paths(ctx)) { ERR_print_errors(bio_err); } + + ssl_ctx_add_crls(ctx, crls, crl_download); + if (!set_cert_key_stuff(ctx, cert, key, chain, build_chain)) + goto end; + #ifndef OPENSSL_NO_TLSEXT if (servername != NULL) { tlsextcbp.biodebug = bio_err; @@ -1277,7 +1441,7 @@ int MAIN(int argc, char **argv) if (c_Pause & 0x01) SSL_set_debug(con, 1); - if (SSL_version(con) == DTLS1_VERSION) { + if (socket_type == SOCK_DGRAM) { sbio = BIO_new_dgram(s, BIO_NOCLOSE); if (getsockname(s, &peer, (void *)&peerlen) < 0) { @@ -1331,8 +1495,13 @@ int MAIN(int argc, char **argv) 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_SSL_TRACE + if (c_msg == 2) + SSL_set_msg_callback(con, SSL_trace); + else +#endif + SSL_set_msg_callback(con, msg_cb); + SSL_set_msg_callback_arg(con, bio_c_msg ? bio_c_msg : bio_c_out); } #ifndef OPENSSL_NO_TLSEXT if (c_tlsextdebug) { @@ -1515,6 +1684,11 @@ int MAIN(int argc, char **argv) BIO_printf(bio_err, "Error writing session file %s\n", sess_out); } + if (c_brief) { + BIO_puts(bio_err, "CONNECTION ESTABLISHED\n"); + print_ssl_summary(bio_err, con); + } + print_stuff(bio_c_out, con, full_log); if (full_log > 0) full_log--; @@ -1780,7 +1954,10 @@ int MAIN(int argc, char **argv) break; case SSL_ERROR_SYSCALL: ret = get_last_socket_error(); - BIO_printf(bio_err, "read:errno=%d\n", ret); + if (c_brief) + BIO_puts(bio_err, "CONNECTION CLOSED BY SERVER\n"); + else + BIO_printf(bio_err, "read:errno=%d\n", ret); goto shut; case SSL_ERROR_ZERO_RETURN: BIO_printf(bio_c_out, "closed\n"); @@ -1880,12 +2057,25 @@ int MAIN(int argc, char **argv) SSL_CTX_free(ctx); if (cert) X509_free(cert); + if (crls) + sk_X509_CRL_pop_free(crls, X509_CRL_free); if (key) EVP_PKEY_free(key); + if (chain) + sk_X509_pop_free(chain, X509_free); if (pass) OPENSSL_free(pass); if (vpm) X509_VERIFY_PARAM_free(vpm); + ssl_excert_free(exc); + if (ssl_args) + sk_OPENSSL_STRING_free(ssl_args); + if (cctx) + SSL_CONF_CTX_free(cctx); +#ifndef OPENSSL_NO_JPAKE + if (jpake_secret && psk_key) + OPENSSL_free(psk_key); +#endif if (cbuf != NULL) { OPENSSL_cleanse(cbuf, BUFSIZZ); OPENSSL_free(cbuf); @@ -1902,6 +2092,10 @@ int MAIN(int argc, char **argv) BIO_free(bio_c_out); bio_c_out = NULL; } + if (bio_c_msg != NULL) { + BIO_free(bio_c_msg); + bio_c_msg = NULL; + } apps_shutdown(); OPENSSL_EXIT(ret); } @@ -1995,6 +2189,9 @@ static void print_stuff(BIO *bio, SSL *s, int full) BIO_write(bio, "\n", 1); } + ssl_print_sigalgs(bio, s); + ssl_print_tmp_key(bio, s); + BIO_printf(bio, "---\nSSL handshake has read %ld bytes and written %ld bytes\n", BIO_number_read(SSL_get_rbio(s)), @@ -2034,7 +2231,8 @@ static void print_stuff(BIO *bio, SSL *s, int full) } #endif -#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) +#if !defined(OPENSSL_NO_TLSEXT) +# if !defined(OPENSSL_NO_NEXTPROTONEG) if (next_proto.status != -1) { const unsigned char *proto; unsigned int proto_len; @@ -2043,6 +2241,18 @@ static void print_stuff(BIO *bio, SSL *s, int full) BIO_write(bio, proto, proto_len); BIO_write(bio, "\n", 1); } +# endif + { + const unsigned char *proto; + unsigned int proto_len; + SSL_get0_alpn_selected(s, &proto, &proto_len); + if (proto_len > 0) { + BIO_printf(bio, "ALPN protocol: "); + BIO_write(bio, proto, proto_len); + BIO_write(bio, "\n", 1); + } else + BIO_printf(bio, "No ALPN negotiated\n"); + } #endif #ifndef OPENSSL_NO_SRTP diff --git a/apps/s_server.c b/apps/s_server.c index b58e5e0..acef382 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -209,14 +209,17 @@ typedef unsigned int u_int; #ifndef OPENSSL_NO_RSA static RSA MS_CALLBACK *tmp_rsa_cb(SSL *s, int is_export, int keylength); #endif -static int sv_body(char *hostname, int s, unsigned char *context); -static int www_body(char *hostname, int s, unsigned char *context); +static int sv_body(char *hostname, int s, int stype, unsigned char *context); +static int www_body(char *hostname, int s, int stype, unsigned char *context); +static int rev_body(char *hostname, int s, int stype, 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); +static void init_session_cache_ctx(SSL_CTX *sctx); +static void free_sessions(void); #ifndef OPENSSL_NO_DH static DH *load_dh_param(const char *dhfile); static DH *get_dh2048(void); @@ -286,16 +289,16 @@ static int accept_socket = -1; #undef PROG #define PROG s_server_main -extern int verify_depth, verify_return_error; +extern int verify_depth, verify_return_error, verify_quiet; -static char *cipher = NULL; static int s_server_verify = SSL_VERIFY_NONE; static int s_server_session_id_context = 1; /* anything will do */ -static const char *s_cert_file = TEST_CERT, *s_key_file = NULL; +static const char *s_cert_file = TEST_CERT, *s_key_file = + NULL, *s_chain_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 char *s_dcert_file = NULL, *s_dkey_file = NULL, *s_dchain_file = NULL; #ifdef FIONBIO static int s_nbio = 0; #endif @@ -308,14 +311,18 @@ static SSL_CTX *ctx2 = NULL; static int www = 0; static BIO *bio_s_out = NULL; +static BIO *bio_s_msg = 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 no_resume_ephemeral = 0; static int s_msg = 0; static int s_quiet = 0; +static int s_ign_eof = 0; +static int s_brief = 0; static char *keymatexportlabel = NULL; static int keymatexportlen = 20; @@ -332,6 +339,12 @@ static long socket_mtu; static int cert_chain = 0; #endif +#ifndef OPENSSL_NO_TLSEXT +static BIO *serverinfo_in = NULL; +static const char *s_serverinfo_file = NULL; + +#endif + #ifndef OPENSSL_NO_PSK static char *psk_identity = "Client_identity"; char *psk_key = NULL; /* by default PSK is not used */ @@ -447,12 +460,13 @@ static int MS_CALLBACK ssl_srp_server_param_cb(SSL *s, int *ad, void *arg) 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_dchain_file = NULL; s_cert_file = TEST_CERT; s_key_file = NULL; + s_chain_file = NULL; # ifndef OPENSSL_NO_TLSEXT s_cert_file2 = TEST_CERT2; s_key_file2 = NULL; @@ -469,6 +483,7 @@ static void s_server_init(void) s_debug = 0; s_msg = 0; s_quiet = 0; + s_brief = 0; hack = 0; # ifndef OPENSSL_NO_ENGINE engine_id = NULL; @@ -482,6 +497,12 @@ static void sv_usage(void) BIO_printf(bio_err, "\n"); BIO_printf(bio_err, " -accept arg - port to accept on (default is %d)\n", PORT); + BIO_printf(bio_err, + " -verify_host host - check peer certificate matches \"host\"\n"); + BIO_printf(bio_err, + " -verify_email email - check peer certificate matches \"email\"\n"); + BIO_printf(bio_err, + " -verify_ip ipaddr - check peer certificate matches \"ipaddr\"\n"); BIO_printf(bio_err, " -context arg - set session ID context\n"); BIO_printf(bio_err, " -verify arg - turn on peer certificate verification\n"); @@ -491,6 +512,16 @@ static void sv_usage(void) " -verify_return_error - return verification errors\n"); BIO_printf(bio_err, " -cert arg - certificate file to use\n"); BIO_printf(bio_err, " (default is %s)\n", TEST_CERT); +#ifndef OPENSSL_NO_TLSEXT + BIO_printf(bio_err, + " -serverinfo arg - PEM serverinfo file for certificate\n"); + BIO_printf(bio_err, + " -auth - send and receive RFC 5878 TLS auth extensions and supplemental data\n"); + BIO_printf(bio_err, + " -auth_require_reneg - Do not send TLS auth extensions until renegotiation\n"); +#endif + BIO_printf(bio_err, + " -no_resumption_on_reneg - set SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION flag\n"); 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"); @@ -569,6 +600,7 @@ static void sv_usage(void) 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, " -dtls1_2 - Just talk DTLSv1.2\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"); @@ -628,6 +660,8 @@ static void sv_usage(void) BIO_printf(bio_err, " -use_srtp profiles - Offer SRTP key management with a colon-separated profile list\n"); # endif + BIO_printf(bio_err, + " -alpn arg - set the advertised protocols for the ALPN extension (comma-separated list)\n"); #endif BIO_printf(bio_err, " -keymatexport label - Export keying material using label\n"); @@ -988,12 +1022,53 @@ static int next_proto_cb(SSL *s, const unsigned char **data, } # endif /* ndef OPENSSL_NO_NEXTPROTONEG */ -#endif +/* This the context that we pass to alpn_cb */ +typedef struct tlsextalpnctx_st { + unsigned char *data; + unsigned short len; +} tlsextalpnctx; + +static int alpn_cb(SSL *s, const unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, void *arg) +{ + tlsextalpnctx *alpn_ctx = arg; + + if (!s_quiet) { + /* We can assume that |in| is syntactically valid. */ + unsigned i; + BIO_printf(bio_s_out, "ALPN protocols advertised by the client: "); + for (i = 0; i < inlen;) { + if (i) + BIO_write(bio_s_out, ", ", 2); + BIO_write(bio_s_out, &in[i + 1], in[i]); + i += in[i] + 1; + } + BIO_write(bio_s_out, "\n", 1); + } + + if (SSL_select_next_proto + ((unsigned char **)out, outlen, alpn_ctx->data, alpn_ctx->len, in, + inlen) != OPENSSL_NPN_NEGOTIATED) { + return SSL_TLSEXT_ERR_NOACK; + } + + if (!s_quiet) { + BIO_printf(bio_s_out, "ALPN protocols selected: "); + BIO_write(bio_s_out, *out, *outlen); + BIO_write(bio_s_out, "\n", 1); + } + + return SSL_TLSEXT_ERR_OK; +} +#endif /* ndef OPENSSL_NO_TLSEXT */ int MAIN(int, char **); #ifndef OPENSSL_NO_JPAKE static char *jpake_secret = NULL; +# define no_jpake !jpake_secret +#else +# define no_jpake 1 #endif #ifndef OPENSSL_NO_SRP static srpsrvparm srp_callback_parm; @@ -1008,18 +1083,14 @@ int MAIN(int argc, char *argv[]) int badarg = 0; short port = PORT; char *CApath = NULL, *CAfile = NULL; + char *chCApath = NULL, *chCAfile = NULL; + char *vfyCApath = NULL, *vfyCAfile = NULL; unsigned char *context = NULL; char *dhfile = NULL; -#ifndef OPENSSL_NO_ECDH - char *named_curve = NULL; -#endif - int badop = 0, bugs = 0; + int badop = 0; int ret = 1; - int off = 0; - int no_tmp_rsa = 0, no_dhe = 0, nocert = 0; -#ifndef OPENSSL_NO_ECDH - int no_ecdhe = 0; -#endif + int build_chain = 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; @@ -1030,16 +1101,20 @@ int MAIN(int argc, char *argv[]) char *dpassarg = NULL, *dpass = NULL; int s_dcert_format = FORMAT_PEM, s_dkey_format = FORMAT_PEM; X509 *s_cert = NULL, *s_dcert = NULL; + STACK_OF(X509) *s_chain = NULL, *s_dchain = NULL; EVP_PKEY *s_key = NULL, *s_dkey = NULL; - int no_cache = 0; + int no_cache = 0, ext_cache = 0; + int rev = 0, naccept = -1; #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; + tlsextnextprotoctx next_proto = { NULL, 0 }; # endif + const char *alpn_in = NULL; + tlsextalpnctx alpn_ctx = { NULL, 0 }; #endif #ifndef OPENSSL_NO_PSK /* by default do not send a PSK identity hint */ @@ -1049,6 +1124,15 @@ int MAIN(int argc, char *argv[]) char *srpuserseed = NULL; char *srp_verifier_file = NULL; #endif + SSL_EXCERT *exc = NULL; + SSL_CONF_CTX *cctx = NULL; + STACK_OF(OPENSSL_STRING) *ssl_args = NULL; + + char *crl_file = NULL; + int crl_format = FORMAT_PEM; + int crl_download = 0; + STACK_OF(X509_CRL) *crls = NULL; + meth = SSLv23_server_method(); local_argc = argc; @@ -1065,6 +1149,12 @@ int MAIN(int argc, char *argv[]) if (!load_config(bio_err, NULL)) goto end; + cctx = SSL_CONF_CTX_new(); + if (!cctx) + goto end; + SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SERVER); + SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CMDLINE); + verify_depth = 0; #ifdef FIONBIO s_nbio = 0; @@ -1080,12 +1170,21 @@ int MAIN(int argc, char *argv[]) goto bad; if (!extract_port(*(++argv), &port)) goto bad; + } else if (strcmp(*argv, "-naccept") == 0) { + if (--argc < 1) + goto bad; + naccept = atol(*(++argv)); + if (naccept <= 0) { + BIO_printf(bio_err, "bad accept value %s\n", *argv); + 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 = atoi(*(++argv)); - BIO_printf(bio_err, "verify depth is %d\n", verify_depth); + if (!s_quiet) + 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 | @@ -1093,9 +1192,10 @@ int MAIN(int argc, char *argv[]) if (--argc < 1) goto bad; verify_depth = atoi(*(++argv)); - BIO_printf(bio_err, - "verify depth is %d, must return a certificate\n", - verify_depth); + if (!s_quiet) + 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; @@ -1104,7 +1204,20 @@ int MAIN(int argc, char *argv[]) if (--argc < 1) goto bad; s_cert_file = *(++argv); - } else if (strcmp(*argv, "-certform") == 0) { + } else if (strcmp(*argv, "-CRL") == 0) { + if (--argc < 1) + goto bad; + crl_file = *(++argv); + } else if (strcmp(*argv, "-crl_download") == 0) + crl_download = 1; +#ifndef OPENSSL_NO_TLSEXT + else if (strcmp(*argv, "-serverinfo") == 0) { + if (--argc < 1) + goto bad; + s_serverinfo_file = *(++argv); + } +#endif + else if (strcmp(*argv, "-certform") == 0) { if (--argc < 1) goto bad; s_cert_format = str2fmt(*(++argv)); @@ -1120,19 +1233,15 @@ int MAIN(int argc, char *argv[]) if (--argc < 1) goto bad; passarg = *(++argv); - } else if (strcmp(*argv, "-dhparam") == 0) { + } else if (strcmp(*argv, "-cert_chain") == 0) { if (--argc < 1) goto bad; - dhfile = *(++argv); - } -#ifndef OPENSSL_NO_ECDH - else if (strcmp(*argv, "-named_curve") == 0) { + s_chain_file = *(++argv); + } else if (strcmp(*argv, "-dhparam") == 0) { if (--argc < 1) goto bad; - named_curve = *(++argv); - } -#endif - else if (strcmp(*argv, "-dcertform") == 0) { + dhfile = *(++argv); + } else if (strcmp(*argv, "-dcertform") == 0) { if (--argc < 1) goto bad; s_dcert_format = str2fmt(*(++argv)); @@ -1152,32 +1261,62 @@ int MAIN(int argc, char *argv[]) if (--argc < 1) goto bad; s_dkey_file = *(++argv); + } else if (strcmp(*argv, "-dcert_chain") == 0) { + if (--argc < 1) + goto bad; + s_dchain_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, "-chainCApath") == 0) { + if (--argc < 1) + goto bad; + chCApath = *(++argv); + } else if (strcmp(*argv, "-verifyCApath") == 0) { + if (--argc < 1) + goto bad; + vfyCApath = *(++argv); } else if (strcmp(*argv, "-no_cache") == 0) no_cache = 1; - else if (args_verify(&argv, &argc, &badarg, bio_err, &vpm)) { + else if (strcmp(*argv, "-ext_cache") == 0) + ext_cache = 1; + else if (strcmp(*argv, "-CRLform") == 0) { + if (--argc < 1) + goto bad; + crl_format = str2fmt(*(++argv)); + } else if (args_verify(&argv, &argc, &badarg, bio_err, &vpm)) { + if (badarg) + goto bad; + continue; + } else if (args_excert(&argv, &argc, &badarg, bio_err, &exc)) { + if (badarg) + goto bad; + continue; + } else if (args_ssl(&argv, &argc, cctx, &badarg, bio_err, &ssl_args)) { 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) - off |= SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION; - else if (strcmp(*argv, "-cipher") == 0) { + else if (strcmp(*argv, "-verify_quiet") == 0) + verify_quiet = 1; + else if (strcmp(*argv, "-build_chain") == 0) + build_chain = 1; + else if (strcmp(*argv, "-CAfile") == 0) { if (--argc < 1) goto bad; - cipher = *(++argv); - } else if (strcmp(*argv, "-CAfile") == 0) { + CAfile = *(++argv); + } else if (strcmp(*argv, "-chainCAfile") == 0) { if (--argc < 1) goto bad; - CAfile = *(++argv); + chCAfile = *(++argv); + } else if (strcmp(*argv, "-verifyCAfile") == 0) { + if (--argc < 1) + goto bad; + vfyCAfile = *(++argv); } #ifdef FIONBIO else if (strcmp(*argv, "-nbio") == 0) { @@ -1189,7 +1328,11 @@ int MAIN(int argc, char *argv[]) s_nbio = 1; #endif s_nbio_test = 1; - } else if (strcmp(*argv, "-debug") == 0) { + } else if (strcmp(*argv, "-ign_eof") == 0) + s_ign_eof = 1; + else if (strcmp(*argv, "-no_ign_eof") == 0) + s_ign_eof = 0; + else if (strcmp(*argv, "-debug") == 0) { s_debug = 1; } #ifndef OPENSSL_NO_TLSEXT @@ -1220,7 +1363,17 @@ int MAIN(int argc, char *argv[]) #endif else if (strcmp(*argv, "-msg") == 0) { s_msg = 1; - } else if (strcmp(*argv, "-hack") == 0) { + } else if (strcmp(*argv, "-msgfile") == 0) { + if (--argc < 1) + goto bad; + bio_s_msg = BIO_new_file(*(++argv), "w"); + } +#ifndef OPENSSL_NO_SSL_TRACE + else if (strcmp(*argv, "-trace") == 0) { + s_msg = 2; + } +#endif + else if (strcmp(*argv, "-hack") == 0) { hack = 1; } else if (strcmp(*argv, "-state") == 0) { state = 1; @@ -1228,18 +1381,19 @@ int MAIN(int argc, char *argv[]) s_crlf = 1; } else if (strcmp(*argv, "-quiet") == 0) { s_quiet = 1; - } else if (strcmp(*argv, "-bugs") == 0) { - bugs = 1; + } else if (strcmp(*argv, "-brief") == 0) { + s_quiet = 1; + s_brief = 1; + verify_quiet = 1; } else if (strcmp(*argv, "-no_tmp_rsa") == 0) { no_tmp_rsa = 1; } else if (strcmp(*argv, "-no_dhe") == 0) { no_dhe = 1; - } -#ifndef OPENSSL_NO_ECDH - else if (strcmp(*argv, "-no_ecdhe") == 0) { + } else if (strcmp(*argv, "-no_ecdhe") == 0) { no_ecdhe = 1; + } else if (strcmp(*argv, "-no_resume_ephemeral") == 0) { + no_resume_ephemeral = 1; } -#endif #ifndef OPENSSL_NO_PSK else if (strcmp(*argv, "-psk_hint") == 0) { if (--argc < 1) @@ -1272,32 +1426,18 @@ int MAIN(int argc, char *argv[]) meth = TLSv1_server_method(); } #endif - else if (strcmp(*argv, "-www") == 0) { + else if (strcmp(*argv, "-rev") == 0) { + rev = 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 #ifndef OPENSSL_NO_SSL2 else if (strcmp(*argv, "-ssl2") == 0) { + no_ecdhe = 1; meth = SSLv2_server_method(); } #endif @@ -1316,9 +1456,15 @@ int MAIN(int argc, char *argv[]) } #endif #ifndef OPENSSL_NO_DTLS1 - else if (strcmp(*argv, "-dtls1") == 0) { + else if (strcmp(*argv, "-dtls") == 0) { + meth = DTLS_server_method(); + socket_type = SOCK_DGRAM; + } else if (strcmp(*argv, "-dtls1") == 0) { meth = DTLSv1_server_method(); socket_type = SOCK_DGRAM; + } else if (strcmp(*argv, "-dtls1_2") == 0) { + meth = DTLSv1_2_server_method(); + socket_type = SOCK_DGRAM; } else if (strcmp(*argv, "-timeout") == 0) enable_timeouts = 1; else if (strcmp(*argv, "-mtu") == 0) { @@ -1368,6 +1514,11 @@ int MAIN(int argc, char *argv[]) next_proto_neg_in = *(++argv); } # endif + else if (strcmp(*argv, "-alpn") == 0) { + if (--argc < 1) + goto bad; + alpn_in = *(++argv); + } #endif #if !defined(OPENSSL_NO_JPAKE) && !defined(OPENSSL_NO_PSK) else if (strcmp(*argv, "-jpake") == 0) { @@ -1420,11 +1571,6 @@ int MAIN(int argc, char *argv[]) goto end; } psk_identity = "JPAKE"; - if (cipher) { - BIO_printf(bio_err, "JPAKE sets cipher to PSK\n"); - goto end; - } - cipher = "PSK"; } #endif @@ -1447,6 +1593,9 @@ int MAIN(int argc, char *argv[]) s_key_file2 = s_cert_file2; #endif + if (!load_excert(&exc, bio_err)) + goto end; + if (nocert == 0) { s_key = load_key(bio_err, s_key_file, s_key_format, 0, pass, e, "server certificate private key file"); @@ -1462,6 +1611,12 @@ int MAIN(int argc, char *argv[]) ERR_print_errors(bio_err); goto end; } + if (s_chain_file) { + s_chain = load_certs(bio_err, s_chain_file, FORMAT_PEM, + NULL, e, "server certificate chain"); + if (!s_chain) + goto end; + } #ifndef OPENSSL_NO_TLSEXT if (tlsextcbp.servername) { s_key2 = load_key(bio_err, s_key_file2, s_key_format, 0, pass, e, @@ -1479,9 +1634,10 @@ int MAIN(int argc, char *argv[]) goto end; } } -#endif +#endif /* OPENSSL_NO_TLSEXT */ } -#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) +#if !defined(OPENSSL_NO_TLSEXT) +# if !defined(OPENSSL_NO_NEXTPROTONEG) if (next_proto_neg_in) { unsigned short len; next_proto.data = next_protos_parse(&len, next_proto_neg_in); @@ -1491,8 +1647,34 @@ int MAIN(int argc, char *argv[]) } else { next_proto.data = NULL; } +# endif + alpn_ctx.data = NULL; + if (alpn_in) { + unsigned short len; + alpn_ctx.data = next_protos_parse(&len, alpn_in); + if (alpn_ctx.data == NULL) + goto end; + alpn_ctx.len = len; + } #endif + if (crl_file) { + X509_CRL *crl; + crl = load_crl(crl_file, crl_format); + if (!crl) { + BIO_puts(bio_err, "Error loading CRL\n"); + ERR_print_errors(bio_err); + goto end; + } + crls = sk_X509_CRL_new_null(); + if (!crls || !sk_X509_CRL_push(crls, crl)) { + BIO_puts(bio_err, "Error adding CRL\n"); + ERR_print_errors(bio_err); + X509_CRL_free(crl); + goto end; + } + } + if (s_dcert_file) { if (s_dkey_file == NULL) @@ -1512,6 +1694,12 @@ int MAIN(int argc, char *argv[]) ERR_print_errors(bio_err); goto end; } + if (s_dchain_file) { + s_dchain = load_certs(bio_err, s_dchain_file, FORMAT_PEM, + NULL, e, "second server certificate chain"); + if (!s_dchain) + goto end; + } } @@ -1525,8 +1713,10 @@ int MAIN(int argc, char *argv[]) app_RAND_load_files(inrand)); if (bio_s_out == NULL) { - if (s_quiet && !s_debug && !s_msg) { + if (s_quiet && !s_debug) { bio_s_out = BIO_new(BIO_s_null()); + if (s_msg && !bio_s_msg) + bio_s_msg = BIO_new_fp(stdout, BIO_NOCLOSE); } else { if (bio_s_out == NULL) bio_s_out = BIO_new_fp(stdout, BIO_NOCLOSE); @@ -1566,16 +1756,17 @@ int MAIN(int argc, char *argv[]) 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); + if (exc) + ssl_ctx_set_excert(ctx, exc); 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 if (ext_cache) + init_session_cache_ctx(ctx); else SSL_CTX_sess_set_cache_size(ctx, 128); @@ -1606,6 +1797,17 @@ int MAIN(int argc, char *argv[]) if (vpm) SSL_CTX_set1_param(ctx, vpm); + ssl_ctx_add_crls(ctx, crls, 0); + + if (!args_ssl_call(ctx, bio_err, cctx, ssl_args, no_ecdhe, no_jpake)) + goto end; + + if (!ssl_load_stores(ctx, vfyCApath, vfyCAfile, chCApath, chCAfile, + crls, crl_download)) { + BIO_printf(bio_err, "Error loading store locations\n"); + ERR_print_errors(bio_err); + goto end; + } #ifndef OPENSSL_NO_TLSEXT if (s_cert2) { ctx2 = SSL_CTX_new(meth); @@ -1633,17 +1835,18 @@ int MAIN(int argc, char *argv[]) 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); + if (exc) + ssl_ctx_set_excert(ctx2, exc); 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 if (ext_cache) + init_session_cache_ctx(ctx2); else SSL_CTX_sess_set_cache_size(ctx2, 128); @@ -1653,12 +1856,20 @@ int MAIN(int argc, char *argv[]) } if (vpm) SSL_CTX_set1_param(ctx2, vpm); + + ssl_ctx_add_crls(ctx2, crls, 0); + + if (!args_ssl_call(ctx2, bio_err, cctx, ssl_args, no_ecdhe, no_jpake)) + goto end; + } # ifndef OPENSSL_NO_NEXTPROTONEG if (next_proto.data) SSL_CTX_set_next_protos_advertised_cb(ctx, next_proto_cb, &next_proto); # endif + if (alpn_ctx.data) + SSL_CTX_set_alpn_select_cb(ctx, alpn_cb, &alpn_ctx); #endif #ifndef OPENSSL_NO_DH @@ -1702,54 +1913,21 @@ int MAIN(int argc, char *argv[]) } #endif -#ifndef OPENSSL_NO_ECDH - 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, s_chain, build_chain)) + goto end; +#ifndef OPENSSL_NO_TLSEXT + if (s_serverinfo_file != NULL + && !SSL_CTX_use_serverinfo_file(ctx, s_serverinfo_file)) { + ERR_print_errors(bio_err); + goto end; } #endif - - 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)) + if (ctx2 && !set_cert_key_stuff(ctx2, s_cert2, s_key2, NULL, build_chain)) goto end; #endif if (s_dcert != NULL) { - if (!set_cert_key_stuff(ctx, s_dcert, s_dkey)) + if (!set_cert_key_stuff(ctx, s_dcert, s_dkey, s_dchain, build_chain)) goto end; } #ifndef OPENSSL_NO_RSA @@ -1808,20 +1986,6 @@ int MAIN(int argc, char *argv[]) } #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); @@ -1873,10 +2037,15 @@ int MAIN(int argc, char *argv[]) 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); + if (rev) + do_server(port, socket_type, &accept_socket, rev_body, context, + naccept); + else if (www) + do_server(port, socket_type, &accept_socket, www_body, context, + naccept); else - do_server(port, socket_type, &accept_socket, sv_body, context); + do_server(port, socket_type, &accept_socket, sv_body, context, + naccept); print_stats(bio_s_out, ctx); ret = 0; end: @@ -1884,18 +2053,25 @@ int MAIN(int argc, char *argv[]) SSL_CTX_free(ctx); if (s_cert) X509_free(s_cert); + if (crls) + sk_X509_CRL_pop_free(crls, X509_CRL_free); if (s_dcert) X509_free(s_dcert); if (s_key) EVP_PKEY_free(s_key); if (s_dkey) EVP_PKEY_free(s_dkey); + if (s_chain) + sk_X509_pop_free(s_chain, X509_free); + if (s_dchain) + sk_X509_pop_free(s_dchain, X509_free); if (pass) OPENSSL_free(pass); if (dpass) OPENSSL_free(dpass); if (vpm) X509_VERIFY_PARAM_free(vpm); + free_sessions(); #ifndef OPENSSL_NO_TLSEXT if (tlscstatp.host) OPENSSL_free(tlscstatp.host); @@ -1909,11 +2085,32 @@ int MAIN(int argc, char *argv[]) X509_free(s_cert2); if (s_key2) EVP_PKEY_free(s_key2); + if (serverinfo_in != NULL) + BIO_free(serverinfo_in); +# ifndef OPENSSL_NO_NEXTPROTONEG + if (next_proto.data) + OPENSSL_free(next_proto.data); +# endif + if (alpn_ctx.data) + OPENSSL_free(alpn_ctx.data); +#endif + ssl_excert_free(exc); + if (ssl_args) + sk_OPENSSL_STRING_free(ssl_args); + if (cctx) + SSL_CONF_CTX_free(cctx); +#ifndef OPENSSL_NO_JPAKE + if (jpake_secret && psk_key) + OPENSSL_free(psk_key); #endif if (bio_s_out != NULL) { BIO_free(bio_s_out); bio_s_out = NULL; } + if (bio_s_msg != NULL) { + BIO_free(bio_s_msg); + bio_s_msg = NULL; + } apps_shutdown(); OPENSSL_EXIT(ret); } @@ -1946,7 +2143,7 @@ static void print_stats(BIO *bio, SSL_CTX *ssl_ctx) SSL_CTX_sess_get_cache_size(ssl_ctx)); } -static int sv_body(char *hostname, int s, unsigned char *context) +static int sv_body(char *hostname, int s, int stype, unsigned char *context) { char *buf = NULL; fd_set readfds; @@ -2010,7 +2207,7 @@ static int sv_body(char *hostname, int s, unsigned char *context) # endif #endif - if (SSL_version(con) == DTLS1_VERSION) { + if (stype == SOCK_DGRAM) { sbio = BIO_new_dgram(s, BIO_NOCLOSE); @@ -2069,8 +2266,13 @@ static int sv_body(char *hostname, int s, unsigned char *context) 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_SSL_TRACE + if (s_msg == 2) + SSL_set_msg_callback(con, SSL_trace); + else +#endif + SSL_set_msg_callback(con, msg_cb); + SSL_set_msg_callback_arg(con, bio_s_msg ? bio_s_msg : bio_s_out); } #ifndef OPENSSL_NO_TLSEXT if (s_tlsextdebug) { @@ -2168,7 +2370,7 @@ static int sv_body(char *hostname, int s, unsigned char *context) assert(lf_num == 0); } else i = raw_read_stdin(buf, bufsize); - if (!s_quiet) { + if (!s_quiet && !s_brief) { if ((i <= 0) || (buf[0] == 'Q')) { BIO_printf(bio_s_out, "DONE\n"); SHUTDOWN(s); @@ -2383,6 +2585,16 @@ static int init_ssl_connection(SSL *con) unsigned char *exportedkeymat; i = SSL_accept(con); +#ifdef CERT_CB_TEST_RETRY + { + while (i <= 0 && SSL_get_error(con, i) == SSL_ERROR_WANT_X509_LOOKUP + && SSL_state(con) == SSL3_ST_SR_CLNT_HELLO_C) { + fprintf(stderr, + "LOOKUP from certificate callback during accept\n"); + i = SSL_accept(con); + } + } +#endif #ifndef OPENSSL_NO_SRP while (i <= 0 && SSL_get_error(con, i) == SSL_ERROR_WANT_X509_LOOKUP) { BIO_printf(bio_s_out, "LOOKUP during accept %s\n", @@ -2398,6 +2610,7 @@ static int init_ssl_connection(SSL *con) i = SSL_accept(con); } #endif + if (i <= 0) { if (BIO_sock_should_retry(i)) { BIO_printf(bio_s_out, "DELAY\n"); @@ -2409,11 +2622,15 @@ static int init_ssl_connection(SSL *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); + } + /* Always print any error messages */ + ERR_print_errors(bio_err); return (0); } + if (s_brief) + print_ssl_summary(bio_err, con); + PEM_write_bio_SSL_SESSION(bio_s_out, SSL_get_session(con)); peer = SSL_get_peer_certificate(con); @@ -2430,6 +2647,11 @@ static int init_ssl_connection(SSL *con) 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)); + ssl_print_sigalgs(bio_s_out, con); +#ifndef OPENSSL_NO_EC + ssl_print_point_formats(bio_s_out, con); + ssl_print_curves(bio_s_out, con, 0); +#endif BIO_printf(bio_s_out, "CIPHER is %s\n", (str != NULL) ? str : "(NONE)"); #if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) @@ -2529,7 +2751,7 @@ static int load_CA(SSL_CTX *ctx, char *file) } #endif -static int www_body(char *hostname, int s, unsigned char *context) +static int www_body(char *hostname, int s, int stype, unsigned char *context) { char *buf = NULL; int ret = 1; @@ -2604,8 +2826,13 @@ static int www_body(char *hostname, int s, unsigned char *context) 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_SSL_TRACE + if (s_msg == 2) + SSL_set_msg_callback(con, SSL_trace); + else +#endif + SSL_set_msg_callback(con, msg_cb); + SSL_set_msg_callback_arg(con, bio_s_msg ? bio_s_msg : bio_s_out); } for (;;) { @@ -2724,6 +2951,10 @@ static int www_body(char *hostname, int s, unsigned char *context) } BIO_puts(io, "\n"); } + ssl_print_sigalgs(io, con); +#ifndef OPENSSL_NO_EC + ssl_print_curves(io, con, 0); +#endif BIO_printf(io, (SSL_cache_hit(con) ? "---\nReused, " : "---\nNew, ")); c = SSL_get_current_cipher(con); @@ -2906,6 +3137,140 @@ static int www_body(char *hostname, int s, unsigned char *context) return (ret); } +static int rev_body(char *hostname, int s, int stype, unsigned char *context) +{ + char *buf = NULL; + int i; + int ret = 1; + SSL *con; + BIO *io, *ssl_bio, *sbio; +#ifndef OPENSSL_NO_KRB5 + KSSL_CTX *kctx; +#endif + + buf = OPENSSL_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; + + /* 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 +#ifndef OPENSSL_NO_KRB5 + if ((kctx = kssl_ctx_new()) != NULL) { + kssl_ctx_setstring(kctx, KSSL_SERVICE, KRB5SVC); + kssl_ctx_setstring(kctx, KSSL_KEYTAB, KRB5KEYTAB); + } +#endif /* OPENSSL_NO_KRB5 */ + if (context) + SSL_set_session_id_context(con, context, strlen((char *)context)); + + sbio = BIO_new_socket(s, BIO_NOCLOSE); + SSL_set_bio(con, sbio, sbio); + SSL_set_accept_state(con); + + BIO_set_ssl(ssl_bio, con, BIO_CLOSE); + BIO_push(io, ssl_bio); +#ifdef CHARSET_EBCDIC + io = BIO_push(BIO_new(BIO_f_ebcdic_filter()), io); +#endif + + 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) { +#ifndef OPENSSL_NO_SSL_TRACE + if (s_msg == 2) + SSL_set_msg_callback(con, SSL_trace); + else +#endif + SSL_set_msg_callback(con, msg_cb); + SSL_set_msg_callback_arg(con, bio_s_msg ? bio_s_msg : bio_s_out); + } + + for (;;) { + i = BIO_do_handshake(io); + if (i > 0) + break; + if (!BIO_should_retry(io)) { + BIO_puts(bio_err, "CONNECTION FAILURE\n"); + ERR_print_errors(bio_err); + goto end; + } + } + BIO_printf(bio_err, "CONNECTION ESTABLISHED\n"); + print_ssl_summary(bio_err, con); + + for (;;) { + i = BIO_gets(io, buf, bufsize - 1); + if (i < 0) { /* error */ + if (!BIO_should_retry(io)) { + if (!s_quiet) + ERR_print_errors(bio_err); + goto err; + } else { + BIO_printf(bio_s_out, "read R BLOCK\n"); +#if defined(OPENSSL_SYS_NETWARE) + delay(1000); +#elif !defined(OPENSSL_SYS_MSDOS) && !defined(__DJGPP__) + sleep(1); +#endif + continue; + } + } else if (i == 0) { /* end of input */ + ret = 1; + BIO_printf(bio_err, "CONNECTION CLOSED\n"); + goto end; + } else { + char *p = buf + i - 1; + while (i && (*p == '\n' || *p == '\r')) { + p--; + i--; + } + if (!s_ign_eof && i == 5 && !strncmp(buf, "CLOSE", 5)) { + ret = 1; + BIO_printf(bio_err, "CONNECTION CLOSED\n"); + goto end; + } + BUF_reverse((unsigned char *)buf, NULL, i); + buf[i] = '\n'; + BIO_write(io, buf, i + 1); + for (;;) { + i = BIO_flush(io); + if (i > 0) + break; + if (!BIO_should_retry(io)) + goto end; + } + } + } + end: + /* make sure we re-use sessions */ + SSL_set_shutdown(con, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); + + err: + + if (buf != NULL) + OPENSSL_free(buf); + if (io != NULL) + BIO_free_all(io); + return (ret); +} + #ifndef OPENSSL_NO_RSA static RSA MS_CALLBACK *tmp_rsa_cb(SSL *s, int is_export, int keylength) { @@ -2961,3 +3326,116 @@ static int generate_session_id(const SSL *ssl, unsigned char *id, return 0; return 1; } + +/* + * By default s_server uses an in-memory cache which caches SSL_SESSION + * structures without any serialisation. This hides some bugs which only + * become apparent in deployed servers. By implementing a basic external + * session cache some issues can be debugged using s_server. + */ + +typedef struct simple_ssl_session_st { + unsigned char *id; + unsigned int idlen; + unsigned char *der; + int derlen; + struct simple_ssl_session_st *next; +} simple_ssl_session; + +static simple_ssl_session *first = NULL; + +static int add_session(SSL *ssl, SSL_SESSION *session) +{ + simple_ssl_session *sess; + unsigned char *p; + + sess = OPENSSL_malloc(sizeof(simple_ssl_session)); + if (!sess) { + BIO_printf(bio_err, "Out of memory adding session to external cache\n"); + return 0; + } + + SSL_SESSION_get_id(session, &sess->idlen); + sess->derlen = i2d_SSL_SESSION(session, NULL); + + sess->id = BUF_memdup(SSL_SESSION_get_id(session, NULL), sess->idlen); + + sess->der = OPENSSL_malloc(sess->derlen); + if (!sess->id || !sess->der) { + BIO_printf(bio_err, "Out of memory adding session to external cache\n"); + + if (sess->id) + OPENSSL_free(sess->id); + if (sess->der) + OPENSSL_free(sess->der); + OPENSSL_free(sess); + return 0; + } + p = sess->der; + i2d_SSL_SESSION(session, &p); + + sess->next = first; + first = sess; + BIO_printf(bio_err, "New session added to external cache\n"); + return 0; +} + +static SSL_SESSION *get_session(SSL *ssl, unsigned char *id, int idlen, + int *do_copy) +{ + simple_ssl_session *sess; + *do_copy = 0; + for (sess = first; sess; sess = sess->next) { + if (idlen == (int)sess->idlen && !memcmp(sess->id, id, idlen)) { + const unsigned char *p = sess->der; + BIO_printf(bio_err, "Lookup session: cache hit\n"); + return d2i_SSL_SESSION(NULL, &p, sess->derlen); + } + } + BIO_printf(bio_err, "Lookup session: cache miss\n"); + return NULL; +} + +static void del_session(SSL_CTX *sctx, SSL_SESSION *session) +{ + simple_ssl_session *sess, *prev = NULL; + const unsigned char *id; + unsigned int idlen; + id = SSL_SESSION_get_id(session, &idlen); + for (sess = first; sess; sess = sess->next) { + if (idlen == sess->idlen && !memcmp(sess->id, id, idlen)) { + if (prev) + prev->next = sess->next; + else + first = sess->next; + OPENSSL_free(sess->id); + OPENSSL_free(sess->der); + OPENSSL_free(sess); + return; + } + prev = sess; + } +} + +static void init_session_cache_ctx(SSL_CTX *sctx) +{ + SSL_CTX_set_session_cache_mode(sctx, + SSL_SESS_CACHE_NO_INTERNAL | + SSL_SESS_CACHE_SERVER); + SSL_CTX_sess_set_new_cb(sctx, add_session); + SSL_CTX_sess_set_get_cb(sctx, get_session); + SSL_CTX_sess_set_remove_cb(sctx, del_session); +} + +static void free_sessions(void) +{ + simple_ssl_session *sess, *tsess; + for (sess = first; sess;) { + OPENSSL_free(sess->id); + OPENSSL_free(sess->der); + tsess = sess; + sess = sess->next; + OPENSSL_free(tsess); + } + first = NULL; +} diff --git a/apps/s_socket.c b/apps/s_socket.c index 9e5565d..77a7688 100644 --- a/apps/s_socket.c +++ b/apps/s_socket.c @@ -290,8 +290,9 @@ static int init_client_ip(int *sock, unsigned char ip[4], int port, int type) } int do_server(int port, int type, int *ret, - int (*cb) (char *hostname, int s, unsigned char *context), - unsigned char *context) + int (*cb) (char *hostname, int s, int stype, + unsigned char *context), unsigned char *context, + int naccept) { int sock; char *name = NULL; @@ -313,12 +314,14 @@ int do_server(int port, int type, int *ret, } } else sock = accept_socket; - i = (*cb) (name, sock, context); + i = (*cb) (name, sock, type, context); if (name != NULL) OPENSSL_free(name); if (type == SOCK_STREAM) SHUTDOWN2(sock); - if (i < 0) { + if (naccept != -1) + naccept--; + if (i < 0 || naccept == 0) { SHUTDOWN2(accept_socket); return (i); } diff --git a/apps/smime.c b/apps/smime.c index 53e43c5..6044ccf 100644 --- a/apps/smime.c +++ b/apps/smime.c @@ -634,6 +634,12 @@ int MAIN(int argc, char **argv) p7 = PKCS7_sign(NULL, NULL, other, in, flags); if (!p7) goto end; + if (flags & PKCS7_NOCERTS) { + for (i = 0; i < sk_X509_num(other); i++) { + X509 *x = sk_X509_value(other, i); + PKCS7_add_certificate(p7, x); + } + } } else flags |= PKCS7_REUSE_DIGEST; for (i = 0; i < sk_OPENSSL_STRING_num(sksigners); i++) { diff --git a/apps/speed.c b/apps/speed.c index 7d9fd8a..3697b71 100644 --- a/apps/speed.c +++ b/apps/speed.c @@ -366,6 +366,8 @@ static void *KDF1_SHA1(const void *in, size_t inlen, void *out, } # endif /* OPENSSL_NO_ECDH */ +static void multiblock_speed(const EVP_CIPHER *evp_cipher); + int MAIN(int, char **); int MAIN(int argc, char **argv) @@ -646,6 +648,7 @@ int MAIN(int argc, char **argv) # ifndef NO_FORK int multi = 0; # endif + int multiblock = 0; # ifndef TIMES usertime = -1; @@ -776,6 +779,9 @@ int MAIN(int argc, char **argv) mr = 1; j--; /* Otherwise, -mr gets confused with an * algorithm. */ + } else if (argc > 0 && !strcmp(*argv, "-mb")) { + multiblock = 1; + j--; } else # ifndef OPENSSL_NO_MD2 if (strcmp(*argv, "md2") == 0) @@ -1941,6 +1947,20 @@ int MAIN(int argc, char **argv) # endif if (doit[D_EVP]) { +# ifdef EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK + if (multiblock && evp_cipher) { + if (! + (EVP_CIPHER_flags(evp_cipher) & + EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK)) { + fprintf(stderr, "%s is not multi-block capable\n", + OBJ_nid2ln(evp_cipher->nid)); + goto end; + } + multiblock_speed(evp_cipher); + mret = 0; + goto end; + } +# endif for (j = 0; j < SIZE_NUM; j++) { if (evp_cipher) { EVP_CIPHER_CTX ctx; @@ -2742,4 +2762,113 @@ static int do_multi(int multi) return 1; } # endif + +static void multiblock_speed(const EVP_CIPHER *evp_cipher) +{ + static int mblengths[] = + { 8 * 1024, 2 * 8 * 1024, 4 * 8 * 1024, 8 * 8 * 1024, 8 * 16 * 1024 }; + int j, count, num = sizeof(lengths) / sizeof(lengths[0]); + const char *alg_name; + unsigned char *inp, *out, no_key[32], no_iv[16]; + EVP_CIPHER_CTX ctx; + double d = 0.0; + + inp = OPENSSL_malloc(mblengths[num - 1]); + out = OPENSSL_malloc(mblengths[num - 1] + 1024); + if (!inp || !out) { + BIO_printf(bio_err,"Out of memory\n"); + goto end; + } + + + EVP_CIPHER_CTX_init(&ctx); + EVP_EncryptInit_ex(&ctx, evp_cipher, NULL, no_key, no_iv); + EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_AEAD_SET_MAC_KEY, sizeof(no_key), + no_key); + alg_name = OBJ_nid2ln(evp_cipher->nid); + + for (j = 0; j < num; j++) { + print_message(alg_name, 0, mblengths[j]); + Time_F(START); + for (count = 0, run = 1; run && count < 0x7fffffff; count++) { + unsigned char aad[EVP_AEAD_TLS1_AAD_LEN]; + EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM mb_param; + size_t len = mblengths[j]; + int packlen; + + memset(aad, 0, 8); /* avoid uninitialized values */ + aad[8] = 23; /* SSL3_RT_APPLICATION_DATA */ + aad[9] = 3; /* version */ + aad[10] = 2; + aad[11] = 0; /* length */ + aad[12] = 0; + mb_param.out = NULL; + mb_param.inp = aad; + mb_param.len = len; + mb_param.interleave = 8; + + packlen = EVP_CIPHER_CTX_ctrl(&ctx, + EVP_CTRL_TLS1_1_MULTIBLOCK_AAD, + sizeof(mb_param), &mb_param); + + if (packlen > 0) { + mb_param.out = out; + mb_param.inp = inp; + mb_param.len = len; + EVP_CIPHER_CTX_ctrl(&ctx, + EVP_CTRL_TLS1_1_MULTIBLOCK_ENCRYPT, + sizeof(mb_param), &mb_param); + } else { + int pad; + + RAND_bytes(out, 16); + len += 16; + aad[11] = len >> 8; + aad[12] = len; + pad = EVP_CIPHER_CTX_ctrl(&ctx, + EVP_CTRL_AEAD_TLS1_AAD, + EVP_AEAD_TLS1_AAD_LEN, aad); + EVP_Cipher(&ctx, out, inp, len + pad); + } + } + d = Time_F(STOP); + BIO_printf(bio_err, + mr ? "+R:%d:%s:%f\n" + : "%d %s's in %.2fs\n", count, "evp", d); + results[D_EVP][j] = ((double)count) / d * mblengths[j]; + } + + if (mr) { + fprintf(stdout, "+H"); + for (j = 0; j < num; j++) + fprintf(stdout, ":%d", mblengths[j]); + fprintf(stdout, "\n"); + fprintf(stdout, "+F:%d:%s", D_EVP, alg_name); + for (j = 0; j < num; j++) + fprintf(stdout, ":%.2f", results[D_EVP][j]); + fprintf(stdout, "\n"); + } else { + fprintf(stdout, + "The 'numbers' are in 1000s of bytes per second processed.\n"); + fprintf(stdout, "type "); + for (j = 0; j < num; j++) + fprintf(stdout, "%7d bytes", mblengths[j]); + fprintf(stdout, "\n"); + fprintf(stdout, "%-24s", alg_name); + + for (j = 0; j < num; j++) { + if (results[D_EVP][j] > 10000) + fprintf(stdout, " %11.2fk", results[D_EVP][j] / 1e3); + else + fprintf(stdout, " %11.2f ", results[D_EVP][j]); + } + fprintf(stdout, "\n"); + } + +end: + if (inp) + OPENSSL_free(inp); + if (out) + OPENSSL_free(out); +} #endif diff --git a/apps/verify.c b/apps/verify.c index e29f9bb..78e729f 100644 --- a/apps/verify.c +++ b/apps/verify.c @@ -88,6 +88,7 @@ int MAIN(int argc, char **argv) X509_STORE *cert_ctx = NULL; X509_LOOKUP *lookup = NULL; X509_VERIFY_PARAM *vpm = NULL; + int crl_download = 0; #ifndef OPENSSL_NO_ENGINE char *engine = NULL; #endif @@ -136,7 +137,8 @@ int MAIN(int argc, char **argv) if (argc-- < 1) goto end; crlfile = *(++argv); - } + } else if (strcmp(*argv, "-crl_download") == 0) + crl_download = 1; #ifndef OPENSSL_NO_ENGINE else if (strcmp(*argv, "-engine") == 0) { if (--argc < 1) @@ -214,6 +216,9 @@ int MAIN(int argc, char **argv) } ret = 0; + + if (crl_download) + store_setup_crl_download(cert_ctx); if (argc < 1) { if (1 != check(cert_ctx, NULL, untrusted, trusted, crls, e)) ret = -1; diff --git a/apps/x509.c b/apps/x509.c index 929359b..864a60d 100644 --- a/apps/x509.c +++ b/apps/x509.c @@ -150,6 +150,9 @@ static const char *x509_usage[] = { " -engine e - use engine e, possibly a hardware device.\n", #endif " -certopt arg - various certificate text options\n", + " -checkhost host - check certificate matches \"host\"\n", + " -checkemail email - check certificate matches \"email\"\n", + " -checkip ipaddr - check certificate matches \"ipaddr\"\n", NULL }; @@ -163,6 +166,9 @@ static int x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest, char *section, ASN1_INTEGER *sno); static int purpose_print(BIO *bio, X509 *cert, X509_PURPOSE *pt); static int reqfile = 0; +#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL +static int force_version = 2; +#endif int MAIN(int, char **); @@ -174,15 +180,16 @@ int MAIN(int argc, char **argv) X509 *x = NULL, *xca = NULL; ASN1_OBJECT *objtmp; STACK_OF(OPENSSL_STRING) *sigopts = NULL; - EVP_PKEY *Upkey = NULL, *CApkey = NULL; + EVP_PKEY *Upkey = NULL, *CApkey = NULL, *fkey = NULL; ASN1_INTEGER *sno = NULL; - int i, num, badops = 0; + int i, num, badops = 0, badsig = 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 *fkeyfile = NULL; char *alias = NULL; int text = 0, serial = 0, subject = 0, issuer = 0, startdate = 0, enddate = 0; @@ -208,6 +215,9 @@ int MAIN(int argc, char **argv) int need_rand = 0; int checkend = 0, checkoffset = 0; unsigned long nmflag = 0, certflag = 0; + char *checkhost = NULL; + char *checkemail = NULL; + char *checkip = NULL; #ifndef OPENSSL_NO_ENGINE char *engine = NULL; #endif @@ -274,7 +284,15 @@ int MAIN(int argc, char **argv) sigopts = sk_OPENSSL_STRING_new_null(); if (!sigopts || !sk_OPENSSL_STRING_push(sigopts, *(++argv))) goto bad; - } else if (strcmp(*argv, "-days") == 0) { + } +#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL + else if (strcmp(*argv, "-force_version") == 0) { + if (--argc < 1) + goto bad; + force_version = atoi(*(++argv)) - 1; + } +#endif + else if (strcmp(*argv, "-days") == 0) { if (--argc < 1) goto bad; days = atoi(*(++argv)); @@ -327,6 +345,10 @@ int MAIN(int argc, char **argv) goto bad; if (!(sno = s2i_ASN1_INTEGER(NULL, *(++argv)))) goto bad; + } else if (strcmp(*argv, "-force_pubkey") == 0) { + if (--argc < 1) + goto bad; + fkeyfile = *(++argv); } else if (strcmp(*argv, "-addtrust") == 0) { if (--argc < 1) goto bad; @@ -424,6 +446,18 @@ int MAIN(int argc, char **argv) goto bad; checkoffset = atoi(*(++argv)); checkend = 1; + } else if (strcmp(*argv, "-checkhost") == 0) { + if (--argc < 1) + goto bad; + checkhost = *(++argv); + } else if (strcmp(*argv, "-checkemail") == 0) { + if (--argc < 1) + goto bad; + checkemail = *(++argv); + } else if (strcmp(*argv, "-checkip") == 0) { + if (--argc < 1) + goto bad; + checkip = *(++argv); } else if (strcmp(*argv, "-noout") == 0) noout = ++num; else if (strcmp(*argv, "-trustout") == 0) @@ -447,6 +481,8 @@ int MAIN(int argc, char **argv) #endif else if (strcmp(*argv, "-ocspid") == 0) ocspid = ++num; + else if (strcmp(*argv, "-badsig") == 0) + badsig = 1; else if ((md_alg = EVP_get_digestbyname(*argv + 1))) { /* ok */ digest = md_alg; @@ -484,6 +520,13 @@ int MAIN(int argc, char **argv) goto end; } + if (fkeyfile) { + fkey = load_pubkey(bio_err, fkeyfile, keyformat, 0, + NULL, e, "Forced key"); + if (fkey == NULL) + goto end; + } + if ((CAkeyfile == NULL) && (CA_flag) && (CAformat == FORMAT_PEM)) { CAkeyfile = CAfile; } else if ((CA_flag) && (CAkeyfile == NULL)) { @@ -605,10 +648,13 @@ int MAIN(int argc, char **argv) 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); + if (fkey) + X509_set_pubkey(x, fkey); + else { + 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"); @@ -937,11 +983,16 @@ int MAIN(int argc, char **argv) goto end; } + print_cert_checks(STDout, x, checkhost, checkemail, checkip); + if (noout) { ret = 0; goto end; } + if (badsig) + x->signature->data[x->signature->length - 1] ^= 0x1; + if (outformat == FORMAT_ASN1) i = i2d_X509_bio(out, x); else if (outformat == FORMAT_PEM) { @@ -982,6 +1033,7 @@ int MAIN(int argc, char **argv) X509_free(xca); EVP_PKEY_free(Upkey); EVP_PKEY_free(CApkey); + EVP_PKEY_free(fkey); if (sigopts) sk_OPENSSL_STRING_free(sigopts); X509_REQ_free(rq); @@ -1101,7 +1153,11 @@ static int x509_certify(X509_STORE *ctx, char *CAfile, const EVP_MD *digest, if (conf) { X509V3_CTX ctx2; +#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL + X509_set_version(x, force_version); +#else X509_set_version(x, 2); /* version 3 certificate */ +#endif X509V3_set_ctx(&ctx2, xca, x, NULL, NULL, 0); X509V3_set_nconf(&ctx2, conf); if (!X509V3_EXT_add_nconf(conf, &ctx2, section, x)) @@ -1186,7 +1242,11 @@ static int sign(X509 *x, EVP_PKEY *pkey, int days, int clrext, } if (conf) { X509V3_CTX ctx; +#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL + X509_set_version(x, force_version); +#else X509_set_version(x, 2); /* version 3 certificate */ +#endif X509V3_set_ctx(&ctx, x, x, NULL, NULL, 0); X509V3_set_nconf(&ctx, conf); if (!X509V3_EXT_add_nconf(conf, &ctx, section, x)) |