static const char *do_verify(const char *hostname, const char *commonName, ...) { #ifdef DISABLED_TEST struct tls ctx; struct tls_cert cert; struct tls_cert_general_name names[20], *alt; union { struct in_addr ip4; struct in6_addr ip6; } addrbuf[20]; int addrpos = 0, ret; va_list ap; const char *aname; memset(&ctx, 0, sizeof(ctx)); memset(&addrbuf, 0, sizeof(addrbuf)); memset(&cert, 0, sizeof(cert)); memset(&names, 0, sizeof(names)); cert.subject.common_name = commonName; cert.subject_alt_names = names; va_start(ap, commonName); while (1) { aname = va_arg(ap, char *); if (!aname) break; alt = &names[cert.subject_alt_name_count++]; if (!memcmp(aname, "dns:", 4)) { alt->name_type = TLS_CERT_GNAME_DNS; alt->name_value = aname + 4; } else if (!memcmp(aname, "ip4:", 4)) { alt->name_type = TLS_CERT_GNAME_IPv4; alt->name_value = &addrbuf[addrpos++]; if (inet_pton(AF_INET, aname + 4, (void*)alt->name_value) != 1) return aname; } else if (!memcmp(aname, "ip6:", 4)) { alt->name_type = TLS_CERT_GNAME_IPv6; alt->name_value = &addrbuf[addrpos++]; if (inet_pton(AF_INET6, aname + 4, (void*)alt->name_value) != 1) return aname; } else { return aname; } } va_end(ap); ret = tls_check_servername(&ctx, &cert, hostname); if (ctx.errmsg) free(ctx.errmsg); if (ret == 0) return "OK"; if (ret == -1) return "FAIL"; #endif return "Unexpected code"; }
int tls_connect_fds(struct tls *ctx, int fd_read, int fd_write, const char *servername) { union { struct in_addr ip4; struct in6_addr ip6; } addrbuf; X509 *cert = NULL; int ret, err; if (ctx->flags & TLS_CONNECTING) goto connecting; if ((ctx->flags & TLS_CLIENT) == 0) { tls_set_error(ctx, "not a client context"); goto err; } if (fd_read < 0 || fd_write < 0) { tls_set_error(ctx, "invalid file descriptors"); return (-1); } if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) { tls_set_error(ctx, "ssl context failure"); goto err; } if (tls_configure_ssl(ctx) != 0) goto err; if (ctx->config->verify_name) { if (servername == NULL) { tls_set_error(ctx, "server name not specified"); goto err; } } if (ctx->config->verify_cert) { SSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_PEER, NULL); if (ctx->config->ca_mem != NULL) { if (ctx->config->ca_len > INT_MAX) { tls_set_error(ctx, "ca too long"); goto err; } if (SSL_CTX_load_verify_mem(ctx->ssl_ctx, ctx->config->ca_mem, ctx->config->ca_len) != 1) { tls_set_error(ctx, "ssl verify memory setup failure"); goto err; } } else if (SSL_CTX_load_verify_locations(ctx->ssl_ctx, ctx->config->ca_file, ctx->config->ca_path) != 1) { tls_set_error(ctx, "ssl verify setup failure"); goto err; } if (ctx->config->verify_depth >= 0) SSL_CTX_set_verify_depth(ctx->ssl_ctx, ctx->config->verify_depth); } if ((ctx->ssl_conn = SSL_new(ctx->ssl_ctx)) == NULL) { tls_set_error(ctx, "ssl connection failure"); goto err; } if (SSL_set_rfd(ctx->ssl_conn, fd_read) != 1 || SSL_set_wfd(ctx->ssl_conn, fd_write) != 1) { tls_set_error(ctx, "ssl file descriptor failure"); goto err; } /* * RFC4366 (SNI): Literal IPv4 and IPv6 addresses are not * permitted in "HostName". */ if (servername != NULL && inet_pton(AF_INET, servername, &addrbuf) != 1 && inet_pton(AF_INET6, servername, &addrbuf) != 1) { if (SSL_set_tlsext_host_name(ctx->ssl_conn, servername) == 0) { tls_set_error(ctx, "server name indication failure"); goto err; } } connecting: if ((ret = SSL_connect(ctx->ssl_conn)) != 1) { err = tls_ssl_error(ctx, ret, "connect"); if (err == TLS_READ_AGAIN || err == TLS_WRITE_AGAIN) { ctx->flags |= TLS_CONNECTING; return (err); } goto err; } ctx->flags &= ~TLS_CONNECTING; if (ctx->config->verify_name) { cert = SSL_get_peer_certificate(ctx->ssl_conn); if (cert == NULL) { tls_set_error(ctx, "no server certificate"); goto err; } if ((ret = tls_check_servername(ctx, cert, servername)) != 0) { if (ret != -2) tls_set_error(ctx, "name `%s' not present in" " server certificate", servername); goto err; } } return (0); err: X509_free(cert); return (-1); }