#ifndef OPENSSL_NO_OCSP
static int ocsp_resp_cb(SSL *s, void *arg);
#endif
+static int ldap_ExtendedResponse_parse(const char *buf, long rem);
static int saved_errno;
#ifndef OPENSSL_NO_PSK
/* Default PSK identity and key */
static char *psk_identity = "Client_identity";
-/*
- * char *psk_key=NULL; by default PSK is not used
- */
static unsigned int psk_client_cb(SSL *ssl, const char *hint, char *identity,
unsigned int max_identity_len,
psk_key);
return 0;
}
- if (key_len > max_psk_len) {
+ if (max_psk_len > INT_MAX || key_len > (long)max_psk_len) {
BIO_printf(bio_err,
"psk buffer of callback is too small (%d) for key (%ld)\n",
max_psk_len, key_len);
typedef enum OPTION_choice {
OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
OPT_4, OPT_6, OPT_HOST, OPT_PORT, OPT_CONNECT, OPT_UNIX,
- OPT_XMPPHOST, OPT_VERIFY,
+ OPT_XMPPHOST, OPT_VERIFY, OPT_NAMEOPT,
OPT_CERT, OPT_CRL, OPT_CRL_DOWNLOAD, OPT_SESS_OUT, OPT_SESS_IN,
OPT_CERTFORM, OPT_CRLFORM, OPT_VERIFY_RET_ERROR, OPT_VERIFY_QUIET,
OPT_BRIEF, OPT_PREXIT, OPT_CRLF, OPT_QUIET, OPT_NBIO,
OPT_SERVERINFO, OPT_STARTTLS, OPT_SERVERNAME,
OPT_USE_SRTP, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN, OPT_SMTPHOST,
OPT_ASYNC, OPT_SPLIT_SEND_FRAG, OPT_MAX_PIPELINES, OPT_READ_BUF,
- OPT_KEYLOG_FILE,
+ OPT_KEYLOG_FILE, OPT_EARLY_DATA,
OPT_V_ENUM,
OPT_X_ENUM,
OPT_S_ENUM,
{"cert", OPT_CERT, '<', "Certificate file to use, PEM format assumed"},
{"certform", OPT_CERTFORM, 'F',
"Certificate format (PEM or DER) PEM default"},
+ {"nameopt", OPT_NAMEOPT, 's', "Various certificate name options"},
{"key", OPT_KEY, 's', "Private key file to use, if not in -cert file"},
{"keyform", OPT_KEYFORM, 'E', "Key format (PEM, DER or engine) PEM default"},
{"pass", OPT_PASS, 's', "Private key file pass phrase source"},
{"ctlogfile", OPT_CTLOG_FILE, '<', "CT log list CONF file"},
#endif
{"keylogfile", OPT_KEYLOG_FILE, '>', "Write TLS secrets to file"},
+ {"early_data", OPT_EARLY_DATA, '<', "File to send as early data"},
{NULL, OPT_EOF, 0x00, NULL}
};
PROTO_POSTGRES,
PROTO_LMTP,
PROTO_NNTP,
- PROTO_SIEVE
+ PROTO_SIEVE,
+ PROTO_LDAP
} PROTOCOL_CHOICE;
static const OPT_PAIR services[] = {
{"lmtp", PROTO_LMTP},
{"nntp", PROTO_NNTP},
{"sieve", PROTO_SIEVE},
+ {"ldap", PROTO_LDAP},
{NULL, 0}
};
int c_status_req = 0;
#endif
BIO *bio_c_msg = NULL;
- const char *keylog_file = NULL;
+ const char *keylog_file = NULL, *early_data_file = NULL;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
case OPT_CERT:
cert_file = opt_arg();
break;
+ case OPT_NAMEOPT:
+ if (!set_nameopt(opt_arg()))
+ goto end;
+ break;
case OPT_CRL:
crl_file = opt_arg();
break;
case OPT_KEYLOG_FILE:
keylog_file = opt_arg();
break;
+ case OPT_EARLY_DATA:
+ early_data_file = opt_arg();
+ break;
}
}
if (count4or6 >= 2) {
}
}
break;
+ case PROTO_LDAP:
+ {
+ /* StartTLS Operation according to RFC 4511 */
+ static char ldap_tls_genconf[] = "asn1=SEQUENCE:LDAPMessage\n"
+ "[LDAPMessage]\n"
+ "messageID=INTEGER:1\n"
+ "extendedReq=EXPLICIT:23A,IMPLICIT:0C,"
+ "FORMAT:ASCII,OCT:1.3.6.1.4.1.1466.20037\n";
+ long errline = -1;
+ char *genstr = NULL;
+ int result = -1;
+ ASN1_TYPE *atyp = NULL;
+ BIO *ldapbio = BIO_new(BIO_s_mem());
+ CONF *cnf = NCONF_new(NULL);
+
+ if (cnf == NULL) {
+ BIO_free(ldapbio);
+ goto end;
+ }
+ BIO_puts(ldapbio, ldap_tls_genconf);
+ if (NCONF_load_bio(cnf, ldapbio, &errline) <= 0) {
+ BIO_free(ldapbio);
+ NCONF_free(cnf);
+ if (errline <= 0) {
+ BIO_printf(bio_err, "NCONF_load_bio failed\n");
+ goto end;
+ } else {
+ BIO_printf(bio_err, "Error on line %ld\n", errline);
+ goto end;
+ }
+ }
+ BIO_free(ldapbio);
+ genstr = NCONF_get_string(cnf, "default", "asn1");
+ if (genstr == NULL) {
+ NCONF_free(cnf);
+ BIO_printf(bio_err, "NCONF_get_string failed\n");
+ goto end;
+ }
+ atyp = ASN1_generate_nconf(genstr, cnf);
+ if (atyp == NULL) {
+ NCONF_free(cnf);
+ BIO_printf(bio_err, "ASN1_generate_nconf failed\n");
+ goto end;
+ }
+ NCONF_free(cnf);
+
+ /* Send SSLRequest packet */
+ BIO_write(sbio, atyp->value.sequence->data,
+ atyp->value.sequence->length);
+ (void)BIO_flush(sbio);
+ ASN1_TYPE_free(atyp);
+
+ mbuf_len = BIO_read(sbio, mbuf, BUFSIZZ);
+ if (mbuf_len < 0) {
+ BIO_printf(bio_err, "BIO_read failed\n");
+ goto end;
+ }
+ result = ldap_ExtendedResponse_parse(mbuf, mbuf_len);
+ if (result < 0) {
+ BIO_printf(bio_err, "ldap_ExtendedResponse_parse failed\n");
+ goto shut;
+ } else if (result > 0) {
+ BIO_printf(bio_err, "STARTTLS failed, LDAP Result Code: %i\n",
+ result);
+ goto shut;
+ }
+ mbuf_len = 0;
+ }
+ break;
+ }
+
+ if (early_data_file != NULL
+ && SSL_get0_session(con) != NULL
+ && SSL_SESSION_get_max_early_data(SSL_get0_session(con)) > 0) {
+ BIO *edfile = BIO_new_file(early_data_file, "r");
+ size_t readbytes, writtenbytes;
+ int finish = 0;
+
+ if (edfile == NULL) {
+ BIO_printf(bio_err, "Cannot open early data file\n");
+ goto shut;
+ }
+
+ while (!finish) {
+ if (!BIO_read_ex(edfile, cbuf, BUFSIZZ, &readbytes))
+ finish = 1;
+
+ while (!SSL_write_early_data(con, cbuf, readbytes, &writtenbytes)) {
+ switch (SSL_get_error(con, 0)) {
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_ASYNC:
+ case SSL_ERROR_WANT_READ:
+ /* Just keep trying - busy waiting */
+ continue;
+ default:
+ BIO_printf(bio_err, "Error writing early data\n");
+ BIO_free(edfile);
+ goto shut;
+ }
+ }
+ }
+
+ BIO_free(edfile);
}
for (;;) {
BIO_printf(bio_err, "bad select %d\n",
get_last_socket_error());
goto shut;
- /* goto end; */
}
}
BIO_printf(bio_c_out, "DONE\n");
ret = 0;
goto shut;
- /* goto end; */
}
sbuf_len -= i;
case SSL_ERROR_SSL:
ERR_print_errors(bio_err);
goto shut;
- /* break; */
}
}
/* OPENSSL_SYS_MSDOS includes OPENSSL_SYS_WINDOWS */
}
#endif
+ if (SSL_version(s) == TLS1_3_VERSION) {
+ switch (SSL_get_early_data_status(s)) {
+ case SSL_EARLY_DATA_NOT_SENT:
+ BIO_printf(bio, "Early data was not sent\n");
+ break;
+
+ case SSL_EARLY_DATA_REJECTED:
+ BIO_printf(bio, "Early data was rejected\n");
+ break;
+
+ case SSL_EARLY_DATA_ACCEPTED:
+ BIO_printf(bio, "Early data was accepted\n");
+ break;
+
+ }
+ }
+
SSL_SESSION_print(bio, SSL_get_session(s));
if (SSL_get_session(s) != NULL && keymatexportlabel != NULL) {
BIO_printf(bio, "Keying material exporter:\n");
}
# endif
+static int ldap_ExtendedResponse_parse(const char *buf, long rem)
+{
+ const unsigned char *cur, *end;
+ long len;
+ int tag, xclass, inf, ret = -1;
+
+ cur = (const unsigned char *)buf;
+ end = cur + rem;
+
+ /*
+ * From RFC 4511:
+ *
+ * LDAPMessage ::= SEQUENCE {
+ * messageID MessageID,
+ * protocolOp CHOICE {
+ * ...
+ * extendedResp ExtendedResponse,
+ * ... },
+ * controls [0] Controls OPTIONAL }
+ *
+ * ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
+ * COMPONENTS OF LDAPResult,
+ * responseName [10] LDAPOID OPTIONAL,
+ * responseValue [11] OCTET STRING OPTIONAL }
+ *
+ * LDAPResult ::= SEQUENCE {
+ * resultCode ENUMERATED {
+ * success (0),
+ * ...
+ * other (80),
+ * ... },
+ * matchedDN LDAPDN,
+ * diagnosticMessage LDAPString,
+ * referral [3] Referral OPTIONAL }
+ */
+
+ /* pull SEQUENCE */
+ inf = ASN1_get_object(&cur, &len, &tag, &xclass, rem);
+ if (inf != V_ASN1_CONSTRUCTED || tag != V_ASN1_SEQUENCE ||
+ (rem = end - cur, len > rem)) {
+ BIO_printf(bio_err, "Unexpected LDAP response\n");
+ goto end;
+ }
+
+ rem = len; /* ensure that we don't overstep the SEQUENCE */
+
+ /* pull MessageID */
+ inf = ASN1_get_object(&cur, &len, &tag, &xclass, rem);
+ if (inf != V_ASN1_UNIVERSAL || tag != V_ASN1_INTEGER ||
+ (rem = end - cur, len > rem)) {
+ BIO_printf(bio_err, "No MessageID\n");
+ goto end;
+ }
+
+ cur += len; /* shall we check for MessageId match or just skip? */
+
+ /* pull [APPLICATION 24] */
+ rem = end - cur;
+ inf = ASN1_get_object(&cur, &len, &tag, &xclass, rem);
+ if (inf != V_ASN1_CONSTRUCTED || xclass != V_ASN1_APPLICATION ||
+ tag != 24) {
+ BIO_printf(bio_err, "Not ExtendedResponse\n");
+ goto end;
+ }
+
+ /* pull resultCode */
+ rem = end - cur;
+ inf = ASN1_get_object(&cur, &len, &tag, &xclass, rem);
+ if (inf != V_ASN1_UNIVERSAL || tag != V_ASN1_ENUMERATED || len == 0 ||
+ (rem = end - cur, len > rem)) {
+ BIO_printf(bio_err, "Not LDAPResult\n");
+ goto end;
+ }
+
+ /* len should always be one, but just in case... */
+ for (ret = 0, inf = 0; inf < len; inf++) {
+ ret <<= 8;
+ ret |= cur[inf];
+ }
+ /* There is more data, but we don't care... */
+ end:
+ return ret;
+}
+
#endif /* OPENSSL_NO_SOCK */