ucspi-ssl  0.12.7
ucspi-ssl
sslclient.c
Go to the documentation of this file.
1 
6 #include <unistd.h>
7 #include <sys/types.h>
8 #include <sys/param.h>
9 #include <netdb.h>
10 #include <arpa/inet.h>
11 #include "ucspissl.h"
12 #include "sig.h"
13 #include "exit.h"
14 #include "getoptb.h"
15 #include "uint_t.h"
16 #include "fmt.h"
17 #include "scan.h"
18 #include "str.h"
19 #include "ip.h"
20 #include "socket_if.h"
21 #include "fd.h"
22 #include "stralloc.h"
23 #include "buffer.h"
24 #include "getln.h"
25 #include "logmsg.h"
26 #include "pathexec.h"
27 #include "timeoutconn.h"
28 #include "remoteinfo.h"
29 #include "dnsresolv.h"
30 #include "byte.h"
31 #include "ndelay.h"
32 #include "wait.h"
33 #include "auto_cafile.h"
34 #include "auto_cadir.h"
35 #include "auto_ciphers.h"
36 
37 #define WHO "sslclient"
38 
39 void nomem(void) {
40  logmsg(WHO,111,FATAL,"out of memory");
41 }
42 void env(const char *s,const char *t) {
43  if (!pathexec_env(s,t)) nomem();
44 }
45 
46 void usage(void) {
47  logmsg(WHO,100,USAGE,"sslclient \
48 [ -463hHrRdDiqQveEsSnNxX ] \
49 [ -i localip ] \
50 [ -p localport ] \
51 [ -T timeoutconn ] \
52 [ -l localname ] \
53 [ -t timeoutinfo ] \
54 [ -I interface ] \
55 [ -a cafile ] \
56 [ -A cadir ] \
57 [ -c certfile ] \
58 [ -z ciphers ] \
59 [ -k keyfile ] \
60 [ -V verifydepth ] \
61 [ -w progtimeout ] \
62 host port program");
63 }
64 
65 int verbosity = 1;
66 int flagdelay = 0;
69 int flag3 = 0;
70 int flagsslenv = 0;
71 int flagtcpenv = 0;
72 int flagsni = 0;
73 unsigned long itimeout = 26;
74 unsigned long ctimeout[2] = { 2, 58 };
75 unsigned int progtimeout = 3600;
76 uint32 netif = 0;
77 
78 const char *loopback = "127.0.0.1";
79 char iplocal[16] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
80 uint16 portlocal = 0;
81 const char *forcelocal = 0;
82 
83 char ipremote[16];
84 uint16 portremote;
85 
86 const char *hostname;
87 int flagname = 1;
89 static stralloc addresses;
90 static stralloc certname;
91 static stralloc moreaddresses;
92 
93 static stralloc tmp;
94 static stralloc fqdn;
95 static char strnum[FMT_ULONG];
96 static char ipstr[IP6_FMT];
97 
98 char seed[128];
99 
100 char bspace[16];
101 buffer b;
102 
103 SSL_CTX *ctx;
104 const char *certfile = 0;
105 const char *keyfile = 0;
106 const char *cafile = auto_cafile;
107 const char *cadir = auto_cadir;
108 const char *ciphers = auto_ciphers;
109 stralloc password = {0};
110 int match = 0;
111 int verifydepth = 1;
112 
113 int pi[2];
114 int po[2];
115 int pt[2];
116 
117 void read_passwd() {
118  if (!password.len) {
119  buffer_init(&b,buffer_unixread,3,bspace,sizeof(bspace));
120  if (getln(&b,&password,&match,'\0') == -1)
121  logmsg(WHO,111,ERROR,"unable to read password");
122  close(3);
123  if (match) --password.len;
124  }
125 }
126 
127 int passwd_cb(char *buf,int size,int rwflag,void *userdata) {
128  if (size < password.len)
129  logmsg(WHO,111,ERROR,"password too long");
130 
131  byte_copy(buf,password.len,password.s);
132  return password.len;
133 }
134 
135 int main(int argc,char * const *argv) {
136  unsigned long u;
137  int opt;
138  const char *x;
139  int j;
140  int s;
141  int r;
142  int cloop;
143  SSL *ssl;
144  int wstat;
145  int ipflag = 0;
146 
147  dns_random_init(seed);
148 
149  close(6);
150  close(7);
151  sig_ignore(sig_pipe);
152 
153  while ((opt = getopt(argc,argv,"dDvqQhHrRimM:p:t:T:l:a:A:c:z:k:V:346eEsSnN0xXw:")) != opteof)
154  switch(opt) {
155  case '4': ipflag = 1; break;
156  case '6': ipflag = 0; break;
157  case 'd': flagdelay = 1; break;
158  case 'D': flagdelay = 0; break;
159  case 'm': flagsni = 1; break;
160  case 'M': flagsni = 0; break;
161  case 'v': verbosity = 2; break;
162  case 'q': verbosity = 0; break;
163  case 'Q': verbosity = 1; break;
164  case 'l': forcelocal = optarg; break;
165  case 'H': flagremotehost = 0; break;
166  case 'h': flagremotehost = 1; break;
167  case 'R': flagremoteinfo = 0; break;
168  case 'r': flagremoteinfo = 1; break;
169  case 't': scan_ulong(optarg,&itimeout); break;
170  case 'T': j = scan_ulong(optarg,&ctimeout[0]);
171  if (optarg[j] == '+') ++j;
172  scan_ulong(optarg + j,&ctimeout[1]);
173  break;
174  case 'w': scan_uint(optarg,&progtimeout); break;
175  case 'i': if (!ip6_scan(optarg,iplocal)) usage(); break;
176  case 'I': netif = socket_getifidx(optarg); break;
177  case 'p': scan_ulong(optarg,&u); portlocal = u; break;
178  case 'a': cafile = optarg; break;
179  case 'A': cadir = optarg; break;
180  case 'c': certfile = optarg; break;
181  case 'z': ciphers = optarg; break;
182  case 'k': keyfile = optarg; break;
183  case 'V': scan_ulong(optarg,&u); verifydepth = u; break;
184  case '3': flag3 = 1; break;
185  case 'S': flagsslenv = 0; break;
186  case 's': flagsslenv = 1; break;
187  case 'E': flagtcpenv = 0; break;
188  case 'e': flagtcpenv = 1; break;
189  case 'N': flagname = 0; break;
190  case 'n': flagname = 1; break;
191  case 'x': flagservercert = 1; break;
192  case 'X': flagservercert = 0; break;
193  default: usage();
194  }
195  argv += optind;
196 
197  if (!verbosity)
198  buffer_2->fd = -1;
199 
200  hostname = *argv;
201  if (!hostname || str_equal((char *)hostname,"")) usage();
202  if (str_equal((char *)hostname,"0")) hostname = loopback;
203 
204  x = *++argv;
205  if (!x) usage();
206  if (!x[scan_ulong(x,&u)])
207  portremote = u;
208  else {
209  struct servent *se;
210  se = getservbyname(x,"tcp");
211  if (!se)
212  logmsg(WHO,111,FATAL,B("unable to figure out port number for ",x));
213  uint16_unpack_big((char*)&se->s_port,&portremote);
214  }
215 
216  if (flag3) read_passwd();
217 
218  if (cafile && str_equal(cafile,"")) cafile = 0;
219  if (cadir && str_equal(cadir,"")) cadir= 0;
220  if (ciphers && str_equal(ciphers,"")) ciphers= 0;
221 
222  if (certfile && str_equal(certfile,"")) certfile = 0;
223  if (keyfile && str_equal(keyfile,"")) keyfile = 0;
224 
225  if (!*++argv) usage();
226 
227  if (!stralloc_copys(&tmp,hostname)) nomem();
228  dns_ip_qualify(&addresses,&fqdn,&tmp);
229  if (addresses.len < 16)
230  logmsg(WHO,111,ERROR,B("No IP address for: ",hostname));
231 
232  if (addresses.len == 16) {
233  ctimeout[0] += ctimeout[1];
234  ctimeout[1] = 0;
235  }
236 
237  for (cloop = 0; cloop < 2; ++cloop) {
238  if (!stralloc_copys(&moreaddresses,"")) nomem();
239  for (j = 0; j + 16 <= addresses.len; j += 16) {
240  if (ipflag == 1 || ip6_isv4mapped(addresses.s + j)) {
241  s = socket_tcp4();
242  if (s == -1) logmsg(WHO,111,FATAL,"unable to create socket");
243  r = socket_bind4(s,iplocal,portlocal);
244  } else {
245  s = socket_tcp6();
246  if (s == -1) logmsg(WHO,111,FATAL,"unable to create socket");
247  r = socket_bind6(s,iplocal,portlocal,netif);
248  }
249  if (r == -1) logmsg(WHO,111,FATAL,"unable to bind socket");
250  if (timeoutconn(s,addresses.s + j,portremote,ctimeout[cloop],netif) == 0)
251  goto CONNECTED;
252  close(s);
253  if (!cloop && ctimeout[1] && (errno == ETIMEDOUT)) {
254  if (!stralloc_catb(&moreaddresses,addresses.s + j,16)) nomem();
255  }
256  else {
257  strnum[fmt_ulong(strnum,portremote)] = 0;
258  if (ip6_isv4mapped(addresses.s + j))
259  ipstr[ip4_fmt(ipstr,addresses.s + j + 12)] = 0;
260  else
261  ipstr[ip6_fmt(ipstr,addresses.s + j)] = 0;
262  }
263  }
264  if (!stralloc_copy(&addresses,&moreaddresses)) nomem();
265  }
266  logmsg(WHO,110,DROP,B("unable to connect to: ",ipstr," port: ",strnum));
267 
268  _exit(111);
269 
270 
271  CONNECTED:
272 
273  /* Local */
274 
275  if (socket_local(s,iplocal,&portlocal,&netif) == -1)
276  logmsg(WHO,111,FATAL,"unable to get local address");
277 
278  if (ip6_isv4mapped(iplocal)) {
279  env("PROTO","TCP6");
280  ipstr[ip4_fmt(ipstr,iplocal + 12)] = 0;
281  } else {
282  env("PROTO","TCP6");
283  if (flagtcpenv && netif) env("TCP6INTERFACE",socket_getifname(netif));
284  ipstr[ip6_fmt(ipstr,iplocal)] = 0;
285  }
286 
287  env("SSLLOCALIP",ipstr);
288  if (flagtcpenv) env("TCPLOCALIP",ipstr);
289 
290  strnum[fmt_ulong(strnum,portlocal)] = 0;
291  env("SSLLOCALPORT",strnum);
292  if (flagtcpenv) env("TCPLOCALPORT",strnum);
293 
294  x = forcelocal;
295  if (!x)
296  if (dns_name(&tmp,iplocal) >= 0) {
297  if (!stralloc_0(&tmp)) nomem();
298  x = tmp.s;
299  }
300  env("SSLLOCALHOST",x);
301  if (flagtcpenv) env("TCPLOCALHOST",x);
302 
303  /* Remote */
304 
305  if (socket_remote(s,ipremote,&portremote,&netif) == -1)
306  logmsg(WHO,111,FATAL,"unable to get remote address");
307 
308  if (ip6_isv4mapped(ipremote))
309  ipstr[ip4_fmt(ipstr,ipremote + 12)] = 0;
310  else
311  ipstr[ip6_fmt(ipstr,ipremote)] = 0;
312 
313  env("SSLREMOTEIP",ipstr);
314  if (flagtcpenv) env("TCPREMOTEIP",ipstr);
315 
316  strnum[fmt_ulong(strnum,portremote)] = 0;
317  env("SSLREMOTEPORT",strnum);
318  if (flagtcpenv) env("TCPREMOTEPORT",strnum);
319 
320  x = 0;
321  if (flagremotehost)
322  if (dns_name(&tmp,ipremote) >= 0) {
323  if (!stralloc_0(&tmp)) nomem();
324  x = tmp.s;
325  }
326 
327  env("SSLREMOTEHOST",x);
328  if (flagtcpenv) env("TCPREMOTEHOST",x);
329 
330  x = 0;
331  if (flagremoteinfo)
333  if (!stralloc_0(&tmp)) nomem();
334  x = tmp.s;
335  }
336  env("SSLREMOTEINFO",x);
337  if (flagtcpenv) env("TCPREMOTEINFO",x);
338 
339  /* Context */
340 
341  ctx = ssl_client();
342  ssl_errstr();
343  if (!ctx)
344  logmsg(WHO,111,FATAL,"unable to create TLS context");
345 
347  case -1: logmsg(WHO,111,ERROR,"unable to load certificate");
348  case -2: logmsg(WHO,111,ERROR,"unable to load key pair");
349  case -3: logmsg(WHO,111,ERROR,"key does not match certificate");
350  default: break;
351  }
352 
354  logmsg(WHO,111,ERROR,"unable to load CA list");
355 
356  if (!ssl_ciphers(ctx,ciphers))
357  logmsg(WHO,111,ERROR,"unable to set cipher list");
358 
359  ssl = ssl_new(ctx,s);
360  if (!ssl) logmsg(WHO,111,FATAL,"unable to create TLS instance");
361 
362  if (flagsni)
363  if (!SSL_set_tlsext_host_name(ssl,hostname))
364  logmsg(WHO,111,FATAL,B("unable to set TLS SNI extensions for hostname: ",(char *)hostname));
365 
366  for (cloop = 0; cloop < 2; ++cloop) {
367  if (!ssl_timeoutconn(ssl,ctimeout[cloop])) goto SSLCONNECTED;
368  if (!cloop && ctimeout[1]) continue;
369  logmsg(WHO,111,FATAL,"unable to TLS connect");
370  }
371 
372  _exit(111);
373 
374  SSLCONNECTED:
375 
376  ndelay_off(s);
377 
378  if (flagservercert)
379  switch(ssl_verify(ssl,hostname,&certname)) {
380  case -1:
381  logmsg(WHO,110,ERROR,"no server certificate");
382  case -2:
383  logmsg(WHO,110,ERROR,"missing credentials (CA) or unable to validate server certificate");
384  case -3:
385  if (!stralloc_0(&certname)) nomem();
386  if (flagname)
387  logmsg(WHO,110,ERROR,B("server hostname does not match certificate: ",(char *)hostname," <=> ",certname.s));
388  default: break;
389  }
390 
391  if (verbosity >= 2)
392  log_who(WHO,B("tls connected to: ",ipstr," port: ",strnum));
393 
394  if (!flagdelay)
395  socket_tcpnodelay(s); /* if it fails, bummer */
396 
397  if (pipe(pi) == -1) logmsg(WHO,111,FATAL,"unable to create pipe");
398  if (pipe(po) == -1) logmsg(WHO,111,FATAL,"unable to create pipe");
399  if (pi[0] == 7) {
400  if (pipe(pt) == -1) logmsg(WHO,111,FATAL,"unable to create pipe");
401  close(pi[0]); close(pi[1]);
402  pi[0] = pt[0]; pi[1] = pt[1];
403  }
404  if (po[1] == 6) {
405  if (pipe(pt) == -1) logmsg(WHO,111,FATAL,"unable to create pipe");
406  close(po[0]); close(po[1]);
407  po[0] = pt[0]; po[1] = pt[1];
408  }
409 
410  switch (opt = fork()) {
411  case -1:
412  logmsg(WHO,111,FATAL,"unable to fork");
413  case 0:
414  break;
415  default:
416  close(pi[0]); close(po[1]);
417  if (ssl_io(ssl,pi[1],po[0],progtimeout)) {
418  logmsg(WHO,110,DROP,"unable to speak TLS");
419  ssl_close(ssl);
420  wait_pid(&wstat,opt);
421  _exit(111);
422  }
423  ssl_close(ssl);
424  if (wait_pid(&wstat,opt) > 0)
425  _exit(wait_exitcode(wstat));
426  _exit(0);
427  }
428  ssl_close(ssl); close(pi[1]); close(po[0]);
429 
430  if (flagsslenv && !ssl_client_env(ssl,0)) nomem();
431 
432  if (fd_move(6,pi[0]) == -1)
433  logmsg(WHO,111,FATAL,"unable to set up descriptor 6");
434  if (fd_move(7,po[1]) == -1)
435  logmsg(WHO,111,FATAL,"unable to set up descriptor 7");
436  sig_uncatch(sig_pipe);
437 
438  pathexec(argv);
439  logmsg(WHO,111,FATAL,B("unable to run: ",*argv));
440  return 0; /* never happens, but avoids compile warning */
441 }
const char auto_cadir[]
Definition: auto_cadir.c:1
const char auto_cafile[]
Definition: auto_cafile.c:1
const char auto_ciphers[]
Definition: auto_ciphers.c:1
void _exit()
int remoteinfo(stralloc *out, char ipremote[16], uint16 portremote, char iplocal[16], uint16 portlocal, unsigned int timeout, uint32 netif)
Definition: remoteinfo.c:86
int ssl_ca(SSL_CTX *ctx, const char *certfile, const char *certdir, int d)
Definition: ssl_ca.c:3
int ssl_certkey(SSL_CTX *ctx, const char *certfile, const char *keyfile, pem_password_cb *passwd_cb)
Definition: ssl_certkey.c:3
int ssl_ciphers(SSL_CTX *ctx, const char *ciphers)
Definition: ssl_ciphers.c:3
int ssl_client_env(SSL *ssl, stralloc *sa)
Definition: ssl_env.c:409
int ssl_io(SSL *ssl, int fdleft, int fdright, unsigned int timeout)
Definition: ssl_io.c:20
SSL * ssl_new(SSL_CTX *ctx, int s)
Definition: ssl_new.c:4
int ssl_timeoutconn(SSL *ssl, unsigned int timeout)
Definition: ssl_timeout.c:61
int ssl_verify(SSL *ssl, const char *hostname, stralloc *dnsout)
Definition: ssl_verify.c:10
#define WHO
Definition: sslclient.c:37
uint16 portremote
Definition: sslclient.c:84
stralloc password
Definition: sslclient.c:109
const char * certfile
Definition: sslclient.c:104
int verbosity
Definition: sslclient.c:65
uint16 portlocal
Definition: sslclient.c:80
const char * ciphers
Definition: sslclient.c:108
int flag3
Definition: sslclient.c:69
char iplocal[16]
Definition: sslclient.c:79
int flagsni
Definition: sslclient.c:72
unsigned long ctimeout[2]
Definition: sslclient.c:74
int pt[2]
Definition: sslclient.c:115
unsigned long itimeout
Definition: sslclient.c:73
const char * cadir
Definition: sslclient.c:107
int flagremotehost
Definition: sslclient.c:68
unsigned int progtimeout
Definition: sslclient.c:75
int flagremoteinfo
Definition: sslclient.c:67
const char * forcelocal
Definition: sslclient.c:81
buffer b
Definition: sslclient.c:101
const char * cafile
Definition: sslclient.c:106
char ipremote[16]
Definition: sslclient.c:83
void nomem(void)
Definition: sslclient.c:39
int flagservercert
Definition: sslclient.c:88
void env(const char *s, const char *t)
Definition: sslclient.c:42
const char * keyfile
Definition: sslclient.c:105
const char * hostname
Definition: sslclient.c:86
const char * loopback
Definition: sslclient.c:78
void read_passwd()
Definition: sslclient.c:117
int flagdelay
Definition: sslclient.c:66
int passwd_cb(char *buf, int size, int rwflag, void *userdata)
Definition: sslclient.c:127
uint32 netif
Definition: sslclient.c:76
int match
Definition: sslclient.c:110
int main(int argc, char *const *argv)
Definition: sslclient.c:135
int pi[2]
Definition: sslclient.c:113
SSL_CTX * ctx
Definition: sslclient.c:103
int flagtcpenv
Definition: sslclient.c:71
int flagname
Definition: sslclient.c:87
char bspace[16]
Definition: sslclient.c:100
char seed[128]
Definition: sslclient.c:98
void usage(void)
Definition: sslclient.c:46
int verifydepth
Definition: sslclient.c:111
int flagsslenv
Definition: sslclient.c:70
int po[2]
Definition: sslclient.c:114
char buf[SSL_NAME_LEN]
Definition: sslhandle.c:126
stralloc certname
Definition: sslserver.c:176
Header file to be used with sqmail; previously called ssl.h. (name clash)
#define ssl_client()
Definition: ucspissl.h:35
#define ssl_errstr()
Definition: ucspissl.h:61
#define ssl_close(ssl)
Definition: ucspissl.h:63