-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlab3sslget.cpp
209 lines (190 loc) · 6.47 KB
/
lab3sslget.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
/* Souce: lab3sslget.cpp
* Written by: Gordon Griesel
* Date: Winter 2019
* Purpose: Example of HTTP request using SSL.
* Used to contact a web server and receive a page as text.
* Modified by: Benjamin A Garza III
* Modified Date: February 7, 2019
* --------------------------------------------------------------------
* Some code in this program comes from samples at the following sources:
* http://fm4dd.com/openssl/sslconnect.htm
* https://ubuntuforums.org/showthread.php?t=2217101
*
* Build:
* gcc -olab3sslget lab3sslget.c -lssl -lcrypto
* Usage:
* ./lab3sslget <host> <page>
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
/* optional includes.
These includes were removed during development.
#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>
#include <errno.h>
#include <sys/time.h>
#include <stdlib.h>
#include <memory.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <netinet/in.h>
#include <stdarg.h>
*/
#define PORT 443
#define USERAGENT "CMPS-3350"
//Corrected to in from no type
const int MAX_READ_ERRORS = 100;
int serverConnect(int argc, char *argv) {
BIO *ssl_setup_bio(void);
void show_cert_data(SSL *ssl, BIO *outbio, const char *hostname);
void set_non_blocking(const int sock);
int sd;
struct hostent *host;
struct sockaddr_in addr;
BIO *outbio = NULL;
SSL_CTX *ctx;
SSL *ssl;
char req[1000];
int req_len;
char hostname[256] = "odin.cs.csub.edu";
char pagename[256] = "/~saustin/public_html/3350/highScores.php?param=HiImWorking";
int port = PORT;
int bytes, nreads, nerrs;
char buf[256];
int ret;
//Setup the SSL BIO
outbio = ssl_setup_bio();
//Initialize the SSL library
if (SSL_library_init() < 0)
BIO_printf(outbio, "Could not initialize the OpenSSL library !\n");
//Const added to match const assigned to const
const SSL_METHOD *method = SSLv23_client_method();
ctx = SSL_CTX_new(method);
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
//next 2 lines of code are not currently needed.
//SSL_MODE_AUTO_RETRY flag of the SSL_CTX_set_mode call.
//SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
//Setup the socket used for connection.
host = gethostbyname(hostname);
sd = socket(AF_INET, SOCK_STREAM, 0);
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = *(long*)(host->h_addr);
if (connect(sd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
BIO_printf(outbio, "%s: Cannot connect to host %s [%s] on port %d.\n",
argv[0], hostname, inet_ntoa(addr.sin_addr), port);
}
//Connect using the SSL certificate.
ssl = SSL_new(ctx);
SSL_set_fd(ssl, sd);
SSL_connect(ssl);
//Show the certificate data
show_cert_data(ssl, outbio, hostname);
//A non-blocking socket will make the ssl_read() not block.
set_non_blocking(sd);
//Send the http request to the host server.
sprintf(req, "GET /%s HTTP/1.1\r\nHost: %s\r\nUser-Agent: %s\r\n\r\n",
pagename, hostname, USERAGENT);
req_len = strlen(req);
ret = SSL_write(ssl, req, req_len);
//Correction: two statments were were separated into two lines and bracketed
if (ret <= 0) {
fprintf(stderr, "ERROR: SSL_write\n");
fflush(stderr);
}
//Get data returned from the server.
//First, do priming read.
//We can take this approach because our socket is non-blocking.
//Start with an error condition.
bytes = -1;
memset(buf, '\0', sizeof(buf));
while (bytes <= 0) {
bytes = SSL_read(ssl, buf, sizeof(buf));
//A slight pause can cause fewer reads to be needed.
usleep(10000);
}
//A successful priming read was accomplished.
//Now read all the data.
nreads = 1;
//Allow for some read errors to happen, while getting the complete data.
nerrs = 0;
while (bytes >= 0 && nerrs < MAX_READ_ERRORS) {
write(STDOUT_FILENO, buf, bytes);
memset(buf, '\0', sizeof(buf));
++nreads;
bytes = SSL_read(ssl, buf, sizeof(buf));
if (bytes == 0)
++nerrs;
else
nerrs = 0;
//A slight pause can cause fewer reads to be needed.
usleep(20000);
}
printf("\nn calls to ssl_read(): %i\n", nreads); fflush(stdout);
//Cleanup.
SSL_free(ssl);
close(sd);
SSL_CTX_free(ctx);
return 0;
}
BIO *ssl_setup_bio(void) {
//Setup the ssl BIO, basic I/O abstraction.
//https://www.openssl.org/docs/man1.1.0/man3/bio.html
BIO *bio = NULL;
OpenSSL_add_all_algorithms();
ERR_load_BIO_strings();
ERR_load_crypto_strings();
SSL_load_error_strings();
bio = BIO_new(BIO_s_file());
bio = BIO_new_fp(stdout, BIO_NOCLOSE);
return bio;
}
void show_cert_data(SSL *ssl, BIO *outbio, const char *hostname) {
//Display ssl certificate data here.
//Get the remote certificate into the X509 structure
printf("--------------------------------------------------------------\n");
printf("Certificate data...\n");
X509 *cert;
X509_NAME *certname;
printf("calling SSL_get_peer_certificate(ssl)\n");
cert = SSL_get_peer_certificate(ssl);
if (cert == NULL)
printf("Error: Could not get a certificate from: %s.\n", hostname);
else
printf("Retrieved the server's certificate from: %s.\n", hostname);
//extract various certificate information
certname = X509_NAME_new();
certname = X509_get_subject_name(cert);
//display the cert subject here
if (BIO_printf(outbio, "Displaying the certificate subject data:\n") < 0)
fprintf(stderr, "ERROR: BIO_printf\n");
X509_NAME_print_ex(outbio, certname, 0, 0);
if (BIO_printf(outbio, "\n\n") < 0)
fprintf(stderr, "ERROR: BIO_printf\n");
printf("--------------------------------------------------------------\n");
}
void set_non_blocking(const int sock) {
//Set a socket to be non-blocking.
int opts;
opts = fcntl(sock, F_GETFL);
if (opts < 0) {
perror("ERROR: fcntl(F_GETFL)");
exit(EXIT_FAILURE);
}
opts = (opts | O_NONBLOCK);
if (fcntl(sock, F_SETFL, opts) < 0) {
perror("ERROR: fcntl(O_NONBLOCK)");
exit(EXIT_FAILURE);
}
}