aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/smugfs/openssl.c
blob: baccd3acd7eb8db99a4b26aa5f624d0a24eb936c (plain)
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
#include <u.h>
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include "a.h"

AUTOLIB(ssl)

static void
httpsinit(void)
{
	ERR_load_crypto_strings();
	ERR_load_SSL_strings();
	SSL_load_error_strings();
	SSL_library_init();
}

struct Pfd
{
	BIO *sbio;
};

static Pfd*
opensslconnect(char *host)
{
	Pfd *pfd;
	BIO *sbio;
	SSL_CTX *ctx;
	SSL *ssl;
	static int didinit;
	char buf[1024];

	if(!didinit){
		httpsinit();
		didinit = 1;
	}

	ctx = SSL_CTX_new(SSLv23_client_method());
	sbio = BIO_new_ssl_connect(ctx);
	BIO_get_ssl(sbio, &ssl);
	SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
	
	snprint(buf, sizeof buf, "%s:https", host);
	BIO_set_conn_hostname(sbio, buf);
	
	if(BIO_do_connect(sbio) <= 0 || BIO_do_handshake(sbio) <= 0){
		ERR_error_string_n(ERR_get_error(), buf, sizeof buf);
		BIO_free_all(sbio);
		werrstr("openssl: %s", buf);
		return nil;
	}

	pfd = emalloc(sizeof *pfd);
	pfd->sbio = sbio;
	return pfd;
}

static void
opensslclose(Pfd *pfd)
{
	if(pfd == nil)
		return;
	BIO_free_all(pfd->sbio);
	free(pfd);
}

static int
opensslwrite(Pfd *pfd, void *v, int n)
{
	int m, total;
	char *p;
	
	p = v;
	total = 0;
	while(total < n){
		if((m = BIO_write(pfd->sbio, p+total, n-total)) <= 0){
			if(total == 0)
				return m;
			return total;
		}
		total += m;
	}
	return total;	
}

static int
opensslread(Pfd *pfd, void *v, int n)
{
	return BIO_read(pfd->sbio, v, n);
}

Protocol https =
{
	opensslconnect,
	opensslread,
	opensslwrite,
	opensslclose
};