提交 ceea4bf0 编写于 作者: G Geoff Thorpe

Remove demos/tunala

This has been unmaintained for a long time. If it's still of interest
to anyone, it can be obtained easily enough by reverting this commit.
(It could join other demo code in some other repository, perhaps.) In
any case we don't want it taking up space in the baseline source
package, so <snip>.
Signed-off-by: NGeoff Thorpe <geoff@openssl.org>
上级 7a2b5450
tunala
*.flc
semantic.cache
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 2 (0x2)
Signature Algorithm: md5WithRSAEncryption
Issuer: C=NZ, L=Wellington, O=Really Irresponsible Authorisation Authority (RIAA), OU=Cert-stamping, CN=Jackov al-Trades/Email=none@fake.domain
Validity
Not Before: Jan 16 05:19:30 2002 GMT
Not After : Jan 14 05:19:30 2012 GMT
Subject: C=NZ, L=Auckland, O=Mordor, OU=SSL grunt things, CN=tunala-client/Email=client@fake.domain
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:b0:d3:56:5c:c8:7f:fb:f4:95:9d:04:84:4f:82:
b7:a2:75:5c:81:48:8c:56:5d:52:ee:38:e1:5c:c8:
9a:70:8e:72:f2:00:1c:17:ef:df:b7:06:59:82:04:
f1:f6:49:11:12:a6:4d:cb:1e:ed:ac:59:1c:4a:d0:
3d:de:e6:f2:8d:cd:39:c2:0f:e0:46:2f:db:cb:9f:
47:f7:56:e7:f8:16:5f:68:71:fb:3a:e3:ab:d2:e5:
05:b7:da:65:61:fe:6d:30:e4:12:a8:b5:c1:71:24:
6b:aa:80:05:41:17:a0:8b:6e:8b:e6:04:cf:85:7b:
2a:ac:a1:79:7d:f4:96:6e:77
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Comment:
OpenSSL Generated Certificate
X509v3 Subject Key Identifier:
F8:43:CB:4F:4D:4F:BC:6E:52:1A:FD:F9:7B:E1:12:3F:A7:A3:BA:93
X509v3 Authority Key Identifier:
keyid:49:FB:45:72:12:C4:CC:E1:45:A1:D3:08:9E:95:C4:2C:6D:55:3F:17
DirName:/C=NZ/L=Wellington/O=Really Irresponsible Authorisation Authority (RIAA)/OU=Cert-stamping/CN=Jackov al-Trades/Email=none@fake.domain
serial:00
Signature Algorithm: md5WithRSAEncryption
8f:5f:0e:43:da:9d:61:43:7e:03:38:9a:e6:50:9d:42:e8:95:
34:49:75:ec:04:8d:5c:85:99:94:70:a0:e7:1f:1e:a0:8b:0f:
d6:e2:cb:f7:35:d9:96:72:bd:a6:e9:8d:4e:b1:e2:ac:97:7f:
2f:70:01:9d:aa:04:bc:d4:01:2b:63:77:a5:de:63:3c:a8:f5:
f2:72:af:ec:11:12:c0:d4:70:cf:71:a6:fb:e9:1d:b3:27:07:
aa:f2:b1:f3:87:d6:ab:8b:ce:c2:08:1b:3c:f9:ba:ff:77:71:
86:09:ef:9e:4e:04:06:63:44:e9:93:20:90:c7:2d:50:c6:50:
f8:66
-----BEGIN CERTIFICATE-----
MIID9TCCA16gAwIBAgIBAjANBgkqhkiG9w0BAQQFADCBtDELMAkGA1UEBhMCTlox
EzARBgNVBAcTCldlbGxpbmd0b24xPDA6BgNVBAoTM1JlYWxseSBJcnJlc3BvbnNp
YmxlIEF1dGhvcmlzYXRpb24gQXV0aG9yaXR5IChSSUFBKTEWMBQGA1UECxMNQ2Vy
dC1zdGFtcGluZzEZMBcGA1UEAxMQSmFja292IGFsLVRyYWRlczEfMB0GCSqGSIb3
DQEJARYQbm9uZUBmYWtlLmRvbWFpbjAeFw0wMjAxMTYwNTE5MzBaFw0xMjAxMTQw
NTE5MzBaMIGHMQswCQYDVQQGEwJOWjERMA8GA1UEBxMIQXVja2xhbmQxDzANBgNV
BAoTBk1vcmRvcjEZMBcGA1UECxMQU1NMIGdydW50IHRoaW5nczEWMBQGA1UEAxMN
dHVuYWxhLWNsaWVudDEhMB8GCSqGSIb3DQEJARYSY2xpZW50QGZha2UuZG9tYWlu
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCw01ZcyH/79JWdBIRPgreidVyB
SIxWXVLuOOFcyJpwjnLyABwX79+3BlmCBPH2SRESpk3LHu2sWRxK0D3e5vKNzTnC
D+BGL9vLn0f3Vuf4Fl9ocfs646vS5QW32mVh/m0w5BKotcFxJGuqgAVBF6CLbovm
BM+FeyqsoXl99JZudwIDAQABo4IBQDCCATwwCQYDVR0TBAIwADAsBglghkgBhvhC
AQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFPhD
y09NT7xuUhr9+XvhEj+no7qTMIHhBgNVHSMEgdkwgdaAFEn7RXISxMzhRaHTCJ6V
xCxtVT8XoYG6pIG3MIG0MQswCQYDVQQGEwJOWjETMBEGA1UEBxMKV2VsbGluZ3Rv
bjE8MDoGA1UEChMzUmVhbGx5IElycmVzcG9uc2libGUgQXV0aG9yaXNhdGlvbiBB
dXRob3JpdHkgKFJJQUEpMRYwFAYDVQQLEw1DZXJ0LXN0YW1waW5nMRkwFwYDVQQD
ExBKYWNrb3YgYWwtVHJhZGVzMR8wHQYJKoZIhvcNAQkBFhBub25lQGZha2UuZG9t
YWluggEAMA0GCSqGSIb3DQEBBAUAA4GBAI9fDkPanWFDfgM4muZQnULolTRJdewE
jVyFmZRwoOcfHqCLD9biy/c12ZZyvabpjU6x4qyXfy9wAZ2qBLzUAStjd6XeYzyo
9fJyr+wREsDUcM9xpvvpHbMnB6rysfOH1quLzsIIGzz5uv93cYYJ755OBAZjROmT
IJDHLVDGUPhm
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQCw01ZcyH/79JWdBIRPgreidVyBSIxWXVLuOOFcyJpwjnLyABwX
79+3BlmCBPH2SRESpk3LHu2sWRxK0D3e5vKNzTnCD+BGL9vLn0f3Vuf4Fl9ocfs6
46vS5QW32mVh/m0w5BKotcFxJGuqgAVBF6CLbovmBM+FeyqsoXl99JZudwIDAQAB
AoGAU4chbqbPvkclPYzaq2yGLlneHrwUft+KwzlfS6L/QVgo+CQRIUWQmjaHpaGM
YtjVFcg1S1QK1bUqZjTEZT0XKhfbYmqW8yYTfbcDEbnY7esoYlvIlW8qRlPRlTBE
utKrtZafmVhLgoNawYGD0aLZofPqpYjbGUlrC7nrem2vNJECQQDVLD3Qb+OlEMET
73ApnJhYsK3e+G2LTrtjrS8y5zS4+Xv61XUqvdV7ogzRl0tpvSAmMOItVyoYadkB
S3xSIWX9AkEA1Fm1FhkQSZwGG5rf4c6gMN71jJ6JE3/kocdVa0sUjRevIupo4XQ2
Vkykxi84MRP8cfHqyjewq7Ozv3op2MGWgwJBAKemsb66IJjzAkaBav7u70nhOf0/
+Dc1Zl7QF2y7NVW8sGrnccx5m+ot2lMD4AV6/kvK6jaqdKrapBZGnbGiHqkCQQDI
T1r33mqz1R8Z2S2Jtzz6/McKf930a/dC+GLGVEutkILf39lRmytKmv/wB0jtWtoO
rlJ5sLDSNzC+1cE1u997AkEAu3IrtGmLKiuS6kDj6W47m+iiTIsuSJtTJb1SbUaK
fIoBNFxbvJYW6rUU9+PxpMRaEhzh5s24/jBOE+mlb17mRQ==
-----END RSA PRIVATE KEY-----
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: md5WithRSAEncryption
Issuer: C=NZ, L=Wellington, O=Really Irresponsible Authorisation Authority (RIAA), OU=Cert-stamping, CN=Jackov al-Trades/Email=none@fake.domain
Validity
Not Before: Jan 16 05:14:06 2002 GMT
Not After : Jan 14 05:14:06 2012 GMT
Subject: C=NZ, L=Wellington, O=Middle Earth, OU=SSL dev things, CN=tunala-server/Email=server@fake.domain
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
00:a9:3e:62:87:97:13:6b:de:8f:bc:1d:0a:3f:65:
0c:f9:76:a3:53:ce:97:30:27:0d:c6:df:72:1f:8d:
5a:ce:58:23:6a:65:e5:e3:72:1a:8d:7f:fe:90:01:
ea:42:f1:9f:6e:7b:0a:bd:eb:52:15:7b:f4:3d:9c:
4e:db:74:29:2b:d1:81:9d:b9:9e:18:2b:87:e1:da:
50:20:3c:59:6c:c9:83:3e:2c:11:0b:78:1e:03:f4:
56:3a:db:95:6a:75:33:85:a9:7b:cc:3c:4a:67:96:
f2:24:b2:a0:cb:2e:cc:52:18:16:6f:44:d9:29:64:
07:2e:fb:56:cc:7c:dc:a2:d7
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Comment:
OpenSSL Generated Certificate
X509v3 Subject Key Identifier:
70:AC:7A:B5:6E:97:C2:82:AF:11:9E:32:CB:8D:48:49:93:B7:DC:22
X509v3 Authority Key Identifier:
keyid:49:FB:45:72:12:C4:CC:E1:45:A1:D3:08:9E:95:C4:2C:6D:55:3F:17
DirName:/C=NZ/L=Wellington/O=Really Irresponsible Authorisation Authority (RIAA)/OU=Cert-stamping/CN=Jackov al-Trades/Email=none@fake.domain
serial:00
Signature Algorithm: md5WithRSAEncryption
2e:cb:a3:cd:6d:a8:9d:d1:dc:e5:f0:e0:27:7e:4b:5a:90:a8:
85:43:f0:05:f7:04:43:d7:5f:d1:a5:8f:5c:58:eb:fc:da:c6:
7c:e0:0b:2b:98:72:95:f6:79:48:96:7a:fa:0c:6b:09:ec:c6:
8c:91:74:45:9f:8f:0f:16:78:e3:66:14:fa:1e:f4:f0:23:ec:
cd:a9:52:77:20:4d:c5:05:2c:52:b6:7b:f3:42:33:fd:90:1f:
3e:88:6f:9b:23:61:c8:80:3b:e6:57:84:2e:f7:26:c7:35:ed:
00:8b:08:30:9b:aa:21:83:b6:6d:b8:7c:8a:9b:2a:ef:79:3d:
96:31
-----BEGIN CERTIFICATE-----
MIID+zCCA2SgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBtDELMAkGA1UEBhMCTlox
EzARBgNVBAcTCldlbGxpbmd0b24xPDA6BgNVBAoTM1JlYWxseSBJcnJlc3BvbnNp
YmxlIEF1dGhvcmlzYXRpb24gQXV0aG9yaXR5IChSSUFBKTEWMBQGA1UECxMNQ2Vy
dC1zdGFtcGluZzEZMBcGA1UEAxMQSmFja292IGFsLVRyYWRlczEfMB0GCSqGSIb3
DQEJARYQbm9uZUBmYWtlLmRvbWFpbjAeFw0wMjAxMTYwNTE0MDZaFw0xMjAxMTQw
NTE0MDZaMIGNMQswCQYDVQQGEwJOWjETMBEGA1UEBxMKV2VsbGluZ3RvbjEVMBMG
A1UEChMMTWlkZGxlIEVhcnRoMRcwFQYDVQQLEw5TU0wgZGV2IHRoaW5nczEWMBQG
A1UEAxMNdHVuYWxhLXNlcnZlcjEhMB8GCSqGSIb3DQEJARYSc2VydmVyQGZha2Uu
ZG9tYWluMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpPmKHlxNr3o+8HQo/
ZQz5dqNTzpcwJw3G33IfjVrOWCNqZeXjchqNf/6QAepC8Z9uewq961IVe/Q9nE7b
dCkr0YGduZ4YK4fh2lAgPFlsyYM+LBELeB4D9FY625VqdTOFqXvMPEpnlvIksqDL
LsxSGBZvRNkpZAcu+1bMfNyi1wIDAQABo4IBQDCCATwwCQYDVR0TBAIwADAsBglg
hkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0O
BBYEFHCserVul8KCrxGeMsuNSEmTt9wiMIHhBgNVHSMEgdkwgdaAFEn7RXISxMzh
RaHTCJ6VxCxtVT8XoYG6pIG3MIG0MQswCQYDVQQGEwJOWjETMBEGA1UEBxMKV2Vs
bGluZ3RvbjE8MDoGA1UEChMzUmVhbGx5IElycmVzcG9uc2libGUgQXV0aG9yaXNh
dGlvbiBBdXRob3JpdHkgKFJJQUEpMRYwFAYDVQQLEw1DZXJ0LXN0YW1waW5nMRkw
FwYDVQQDExBKYWNrb3YgYWwtVHJhZGVzMR8wHQYJKoZIhvcNAQkBFhBub25lQGZh
a2UuZG9tYWluggEAMA0GCSqGSIb3DQEBBAUAA4GBAC7Lo81tqJ3R3OXw4Cd+S1qQ
qIVD8AX3BEPXX9Glj1xY6/zaxnzgCyuYcpX2eUiWevoMawnsxoyRdEWfjw8WeONm
FPoe9PAj7M2pUncgTcUFLFK2e/NCM/2QHz6Ib5sjYciAO+ZXhC73Jsc17QCLCDCb
qiGDtm24fIqbKu95PZYx
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCpPmKHlxNr3o+8HQo/ZQz5dqNTzpcwJw3G33IfjVrOWCNqZeXj
chqNf/6QAepC8Z9uewq961IVe/Q9nE7bdCkr0YGduZ4YK4fh2lAgPFlsyYM+LBEL
eB4D9FY625VqdTOFqXvMPEpnlvIksqDLLsxSGBZvRNkpZAcu+1bMfNyi1wIDAQAB
AoGANCwqHZhiAU/TyW6+WPqivEhpYw19p/dyFMuPF9DwnEmpaUROUQY8z0AUznn4
qHhp6Jn/nrprTHowucl0ucweYIYVxZoUiUDFpxdFUbzMdFvo6HcyV1Pe4Rt81HaY
KYWrTZ6PaPtN65hLms8NhPEdGcGAFlY1owYv4QNGq2bU1JECQQDd32LM0NSfyGmK
4ziajqGcvzK9NO2XyV/nJsGlJZNgMh2zm1t7yR28l/6Q2uyU49cCN+2aYULZCAfs
taNvxBspAkEAw0alNub+xj2AVQvaxOB1sGfKzsJjHCzKIxUXn/tJi3j0+2asmkBZ
Umx1MWr9jKQBnCMciCRUbnMEZiElOxCN/wJAfAeQl6Z19gx206lJzzzEo3dOye54
k02DSxijT8q9pBzf9bN3ZK987BybtiZr8p+bZiYVsSOF1wViSLURdD1QYQJAIaMU
qH1n24wShBPTrmAfxbBLTgxL+Dl65Eoo1KT7iSvfv0JzbuqwuDL4iPeuD0DdCiE+
M/FWHeRwGIuTFzaFzwJBANKwx0jZS/h093w9g0Clw6UzeA1P5VcAt9y+qMC9hO3c
4KXwIxQAt9yRaFLpiIR9do5bjjKNnMguf3aO/XRSDQM=
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIID9zCCA2CgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBtDELMAkGA1UEBhMCTlox
EzARBgNVBAcTCldlbGxpbmd0b24xPDA6BgNVBAoTM1JlYWxseSBJcnJlc3BvbnNp
YmxlIEF1dGhvcmlzYXRpb24gQXV0aG9yaXR5IChSSUFBKTEWMBQGA1UECxMNQ2Vy
dC1zdGFtcGluZzEZMBcGA1UEAxMQSmFja292IGFsLVRyYWRlczEfMB0GCSqGSIb3
DQEJARYQbm9uZUBmYWtlLmRvbWFpbjAeFw0wMjAxMTYwNTA5NTlaFw0xMjAxMTQw
NTA5NTlaMIG0MQswCQYDVQQGEwJOWjETMBEGA1UEBxMKV2VsbGluZ3RvbjE8MDoG
A1UEChMzUmVhbGx5IElycmVzcG9uc2libGUgQXV0aG9yaXNhdGlvbiBBdXRob3Jp
dHkgKFJJQUEpMRYwFAYDVQQLEw1DZXJ0LXN0YW1waW5nMRkwFwYDVQQDExBKYWNr
b3YgYWwtVHJhZGVzMR8wHQYJKoZIhvcNAQkBFhBub25lQGZha2UuZG9tYWluMIGf
MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7QdDfFIrJn3X24hKmpkyk3TG0Ivxd
K2wWmDPXq1wjr8lUTwrA6hM5Ba9N36jLieWpXhviLOWu9DBza5GmtgCuXloATKTC
94xOdKHlciTVujG3wDlLDB5e710Kar84nnj6VueL1RyZ0bmP5PANa4mbGW9Tqc7J
CkBTTW2y9d0SgQIDAQABo4IBFTCCAREwHQYDVR0OBBYEFEn7RXISxMzhRaHTCJ6V
xCxtVT8XMIHhBgNVHSMEgdkwgdaAFEn7RXISxMzhRaHTCJ6VxCxtVT8XoYG6pIG3
MIG0MQswCQYDVQQGEwJOWjETMBEGA1UEBxMKV2VsbGluZ3RvbjE8MDoGA1UEChMz
UmVhbGx5IElycmVzcG9uc2libGUgQXV0aG9yaXNhdGlvbiBBdXRob3JpdHkgKFJJ
QUEpMRYwFAYDVQQLEw1DZXJ0LXN0YW1waW5nMRkwFwYDVQQDExBKYWNrb3YgYWwt
VHJhZGVzMR8wHQYJKoZIhvcNAQkBFhBub25lQGZha2UuZG9tYWluggEAMAwGA1Ud
EwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAYQo95V/NY+eKxYxkhibZiUQygph+
gTfgbDG20MsnH6+8//w5ArHauFCgDrf0P2VyACgq+N4pBTWFGaAaLwbjKy9HCe2E
j9C91tO1CqDS4MJkDB5AP13FTkK6fP1ZCiTQranOAp3DlGWTTWsFVyW5kVfQ9diS
ZOyJZ9Fit5XM2X0=
-----END CERTIFICATE-----
There are two ways to build this code;
(1) Manually
(2) Using all-singing all-dancing (all-confusing) autotools, ie. autoconf,
automake, and their little friends (autoheader, etc).
=================
Building Manually
=================
There is a basic "Makefile" in this directory that gets moved out of the way and
ignored when building with autoconf et al. This Makefile is suitable for
building tunala on Linux using gcc. Any other platform probably requires some
tweaking. Here are the various bits you might need to do if you want to build
this way and the default Makefile isn't sufficient;
* Compiler: Edit the "CC" definition in Makefile
* Headers, features: tunala.h controls what happens in the non-autoconf world.
It, by default, assumes the system has *everything* (except autoconf's
"config.h") so if a target system is missing something it must define the
appropriate "NO_***" symbols in CFLAGS. These include;
- NO_HAVE_UNISTD_H, NO_HAVE_FCNTL_H, NO_HAVE_LIMITS_H
Indicates the compiling system doesn't have (or need) these header files.
- NO_HAVE_STRSTR, NO_HAVE_STRTOUL
Indicates the compiling system doesn't have these functions. Replacements
are compiled and used in breakage.c
- NO_HAVE_SELECT, NO_HAVE_SOCKET
Pointless symbols - these indicate select() and/or socket() are missing in
which case the program won't compile anyway.
If you want to specify any of these, add them with "-D" prefixed to each in
the CFLAGS definition in Makefile.
* Compilation flags: edit DEBUG_FLAGS and/or CFLAGS directly to control the
flags passed to the compiler. This can also be used to change the degree of
optimisation.
* Linker flags: some systems (eg. Solaris) require extra linker flags such as;
-ldl, -lsocket, -lnsl, etc. If unsure, bring up the man page for whichever
function is "undefined" when the linker fails - that usually indicates what
you need to add. Make changes to the LINK_FLAGS symbol.
* Linker command: if a different linker syntax or even a different program is
required to link, edit the linker line directly in the "tunala:" target
definition - it currently assumes the "CC" (compiler) program is used to link.
======================
Building Automagically
======================
Automagic building is handled courtesy of autoconf, automake, etc. There are in
fact two steps required to build, and only the first has to be done on a system
with these tools installed (and if I was prepared to bloat out the CVS
repository, I could store these extra files, but I'm not).
First step: "autogunk.sh"
-------------------------
The "./autogunk.sh" script will call all the necessary autotool commands to
create missing files and run automake and autoconf. The result is that a
"./configure" script should be generated and a "Makefile.in" generated from the
supplied "Makefile.am". NB: This script also moves the "manual" Makefile (see
above) out of the way and calls it "Makefile.plain" - the "ungunk" script
reverses this to leave the directory it was previously.
Once "ungunk" has been run, the resulting directory should be able to build on
other systems without autoconf, automake, or libtool. Which is what the second
step describes;
Second step: "./configure"
--------------------------
The second step is to run the generated "./configure" script to create a
config.h header for your system and to generate a "Makefile" (generated from
"Makefile.in") tweaked to compile on your system. This is the standard sort of
thing you see in GNU packages, for example, and the standard tricks also work.
Eg. to override "configure"'s choice of compiler, set the CC environment
variable prior to running configure, eg.
CC=gcc ./configure
would cause "gcc" to be used even if there is an otherwise preferable (to
autoconf) native compiler on your system.
After this run "make" and it should build the "tunala" executable.
Notes
-----
- Some versions of autoconf (or automake?) generate a Makefile syntax that gives
trouble to some "make" programs on some systems (eg. OpenBSD). If this
happens, either build 'Manually' (see above) or use "gmake" instead of "make".
I don't like this either but like even less the idea of sifting into all the
script magic crud that's involved.
- On a solaris system I tried, the "configure" script specified some broken
compiler flags in the resulting Makefile that don't even get echoed to
stdout/err when the error happens (evil!). If this happens, go into the
generated Makefile, find the two affected targets ("%.o:" and "%.lo"), and
remove the offending hidden option in the $(COMPILE) line all the sludge after
the two first lines of script (ie. after the "echo" and the "COMPILE" lines).
NB: This will probably only function if "--disable-shared" was used, otherwise
who knows what would result ...
# Edit these to suit
#
# Oh yeah, and please read the README too.
SSL_HOMEDIR=../..
SSL_INCLUDEDIR=$(SSL_HOMEDIR)/include
SSL_LIBDIR=$(SSL_HOMEDIR)
RM=rm -f
CC=gcc
DEBUG_FLAGS=-g -ggdb3 -Wall -Wshadow
INCLUDE_FLAGS=-I$(SSL_INCLUDEDIR)
CFLAGS=$(DEBUG_FLAGS) $(INCLUDE_FLAGS) -DNO_CONFIG_H
COMPILE=$(CC) $(CFLAGS) -c
# Edit, particularly the "-ldl" if not building with "dlfcn" support
LINK_FLAGS=-L$(SSL_LIBDIR) -lssl -lcrypto -ldl
SRCS=buffer.c cb.c ip.c sm.c tunala.c breakage.c
OBJS=buffer.o cb.o ip.o sm.o tunala.o breakage.o
TARGETS=tunala
default: $(TARGETS)
clean:
$(RM) $(OBJS) $(TARGETS) *.bak core
.c.o:
$(COMPILE) $<
tunala: $(OBJS)
$(CC) -o tunala $(OBJS) $(LINK_FLAGS)
# Extra dependencies, should really use makedepend
buffer.o: buffer.c tunala.h
cb.o: cb.c tunala.h
ip.o: ip.c tunala.h
sm.o: sm.c tunala.h
tunala.o: tunala.c tunala.h
# Our includes come from the OpenSSL build-tree we're in
INCLUDES = -I$(top_builddir)/../../include
bin_PROGRAMS = tunala
tunala_SOURCES = tunala.c buffer.c cb.c ip.c sm.c breakage.c
tunala_LDADD = -L$(top_builddir)/../.. -lssl -lcrypto
This is intended to be an example of a state-machine driven SSL application. It
acts as an SSL tunneler (functioning as either the server or client half,
depending on command-line arguments). *PLEASE* read the comments in tunala.h
before you treat this stuff as anything more than a curiosity - YOU HAVE BEEN
WARNED!! There, that's the draconian bit out of the way ...
Why "tunala"??
--------------
I thought I asked you to read tunala.h?? :-)
Show me
-------
If you want to simply see it running, skip to the end and see some example
command-line arguments to demonstrate with.
Where to look and what to do?
-----------------------------
The code is split up roughly coinciding with the detaching of an "abstract" SSL
state machine (which is the purpose of all this) and its surrounding application
specifics. This is primarily to make it possible for me to know when I could cut
corners and when I needed to be rigorous (or at least maintain the pretense as
such :-).
Network stuff:
Basically, the network part of all this is what is supposed to be abstracted out
of the way. The intention is to illustrate one way to stick OpenSSL's mechanisms
inside a little memory-driven sandbox and operate it like a pure state-machine.
So, the network code is inside both ip.c (general utility functions and gory
IPv4 details) and tunala.c itself, which takes care of application specifics
like the main select() loop. The connectivity between the specifics of this
application (TCP/IP tunneling and the associated network code) and the
underlying abstract SSL state machine stuff is through the use of the "buffer_t"
type, declared in tunala.h and implemented in buffer.c.
State machine:
Which leaves us, generally speaking, with the abstract "state machine" code left
over and this is sitting inside sm.c, with declarations inside tunala.h. As can
be seen by the definition of the state_machine_t structure and the associated
functions to manipulate it, there are the 3 OpenSSL "handles" plus 4 buffer_t
structures dealing with IO on both the encrypted and unencrypted sides ("dirty"
and "clean" respectively). The "SSL" handle is what facilitates the reading and
writing of the unencrypted (tunneled) data. The two "BIO" handles act as the
read and write channels for encrypted tunnel traffic - in other applications
these are often socket BIOs so that the OpenSSL framework operates with the
network layer directly. In this example, those two BIOs are memory BIOs
(BIO_s_mem()) so that the sending and receiving of the tunnel traffic stays
within the state-machine, and we can handle where this gets send to (or read
from) ourselves.
Why?
----
If you take a look at the "state_machine_t" section of tunala.h and the code in
sm.c, you will notice that nothing related to the concept of 'transport' is
involved. The binding to TCP/IP networking occurs in tunala.c, specifically
within the "tunala_item_t" structure that associates a state_machine_t object
with 4 file-descriptors. The way to best see where the bridge between the
outside world (TCP/IP reads, writes, select()s, file-descriptors, etc) and the
state machine is, is to examine the "tunala_item_io()" function in tunala.c.
This is currently around lines 641-732 but of course could be subject to change.
And...?
-------
Well, although that function is around 90 lines of code, it could easily have
been a lot less only I was trying to address an easily missed "gotcha" (item (2)
below). The main() code that drives the select/accept/IO loop initialises new
tunala_item_t structures when connections arrive, and works out which
file-descriptors go where depending on whether we're an SSL client or server
(client --> accepted connection is clean and proxied is dirty, server -->
accepted connection is dirty and proxied is clean). What that tunala_item_io()
function is attempting to do is 2 things;
(1) Perform all reads and writes on the network directly into the
state_machine_t's buffers (based on a previous select() result), and only
then allow the abstact state_machine_t to "churn()" using those buffers.
This will cause the SSL machine to consume as much input data from the two
"IN" buffers as possible, and generate as much output data into the two
"OUT" buffers as possible. Back up in the main() function, the next main
loop loop will examine these output buffers and select() for writability
on the corresponding sockets if the buffers are non-empty.
(2) Handle the complicated tunneling-specific issue of cascading "close"s.
This is the reason for most of the complexity in the logic - if one side
of the tunnel is closed, you can't simply close the other side and throw
away the whole thing - (a) there may still be outgoing data on the other
side of the tunnel that hasn't been sent yet, (b) the close (or things
happening during the close) may cause more data to be generated that needs
sending on the other side. Of course, this logic is complicated yet futher
by the fact that it's different depending on which side closes first :-)
state_machine_close_clean() will indicate to the state machine that the
unencrypted side of the tunnel has closed, so any existing outgoing data
needs to be flushed, and the SSL stream needs to be closed down using the
appropriate shutdown sequence. state_machine_close_dirty() is simpler
because it indicates that the SSL stream has been disconnected, so all
that remains before closing the other side is to flush out anything that
remains and wait for it to all be sent.
Anyway, with those things in mind, the code should be a little easier to follow
in terms of "what is *this* bit supposed to achieve??!!".
How might this help?
--------------------
Well, the reason I wrote this is that there seemed to be rather a flood of
questions of late on the openssl-dev and openssl-users lists about getting this
whole IO logic thing sorted out, particularly by those who were trying to either
use non-blocking IO, or wanted SSL in an environment where "something else" was
handling the network already and they needed to operate in memory only. This
code is loosely based on some other stuff I've been working on, although that
stuff is far more complete, far more dependant on a whole slew of other
network/framework code I don't want to incorporate here, and far harder to look
at for 5 minutes and follow where everything is going. I will be trying over
time to suck in a few things from that into this demo in the hopes it might be
more useful, and maybe to even make this demo usable as a utility of its own.
Possible things include:
* controlling multiple processes/threads - this can be used to combat
latencies and get passed file-descriptor limits on some systems, and it uses
a "controller" process/thread that maintains IPC links with the
processes/threads doing the real work.
* cert verification rules - having some say over which certs get in or out :-)
* control over SSL protocols and cipher suites
* A few other things you can already do in s_client and s_server :-)
* Support (and control over) session resuming, particularly when functioning
as an SSL client.
If you have a particular environment where this model might work to let you "do
SSL" without having OpenSSL be aware of the transport, then you should find you
could use the state_machine_t structure (or your own variant thereof) and hook
it up to your transport stuff in much the way tunala.c matches it up with those
4 file-descriptors. The state_machine_churn(), state_machine_close_clean(), and
state_machine_close_dirty() functions are the main things to understand - after
that's done, you just have to ensure you're feeding and bleeding the 4
state_machine buffers in a logical fashion. This state_machine loop handles not
only handshakes and normal streaming, but also renegotiates - there's no special
handling required beyond keeping an eye on those 4 buffers and keeping them in
sync with your outer "loop" logic. Ie. if one of the OUT buffers is not empty,
you need to find an opportunity to try and forward its data on. If one of the IN
buffers is not full, you should keep an eye out for data arriving that should be
placed there.
This approach could hopefully also allow you to run the SSL protocol in very
different environments. As an example, you could support encrypted event-driven
IPC where threads/processes pass messages to each other inside an SSL layer;
each IPC-message's payload would be in fact the "dirty" content, and the "clean"
payload coming out of the tunnel at each end would be the real intended message.
Likewise, this could *easily* be made to work across unix domain sockets, or
even entirely different network/comms protocols.
This is also a quick and easy way to do VPN if you (and the remote network's
gateway) support virtual network devices that are encapsulted in a single
network connection, perhaps PPP going through an SSL tunnel?
Suggestions
-----------
Please let me know if you find this useful, or if there's anything wrong or
simply too confusing about it. Patches are also welcome, but please attach a
description of what it changes and why, and "diff -urN" format is preferred.
Mail to geoff@openssl.org should do the trick.
Example
-------
Here is an example of how to use "tunala" ...
First, it's assumed that OpenSSL has already built, and that you are building
inside the ./demos/tunala/ directory. If not - please correct the paths and
flags inside the Makefile. Likewise, if you want to tweak the building, it's
best to try and do so in the makefile (eg. removing the debug flags and adding
optimisation flags).
Secondly, this code has mostly only been tested on Linux. However, some
autoconf/etc support has been added and the code has been compiled on openbsd
and solaris using that.
Thirdly, if you are Win32, you probably need to do some *major* rewriting of
ip.c to stand a hope in hell. Good luck, and please mail me the diff if you do
this, otherwise I will take a look at another time. It can certainly be done,
but it's very non-POSIXy.
See the INSTALL document for details on building.
Now, if you don't have an executable "tunala" compiled, go back to "First,...".
Rinse and repeat.
Inside one console, try typing;
(i) ./tunala -listen localhost:8080 -proxy localhost:8081 -cacert CA.pem \
-cert A-client.pem -out_totals -v_peer -v_strict
In another console, type;
(ii) ./tunala -listen localhost:8081 -proxy localhost:23 -cacert CA.pem \
-cert A-server.pem -server 1 -out_totals -v_peer -v_strict
Now if you open another console and "telnet localhost 8080", you should be
tunneled through to the telnet service on your local machine (if it's running -
you could change it to port "22" and tunnel ssh instead if you so desired). When
you logout of the telnet session, the tunnel should cleanly shutdown and show
you some traffic stats in both consoles. Feel free to experiment. :-)
Notes:
- the format for the "-listen" argument can skip the host part (eg. "-listen
8080" is fine). If you do, the listening socket will listen on all interfaces
so you can connect from other machines for example. Using the "localhost"
form listens only on 127.0.0.1 so you can only connect locally (unless, of
course, you've set up weird stuff with your networking in which case probably
none of the above applies).
- ./tunala -? gives you a list of other command-line options, but tunala.c is
also a good place to look :-)
#!/bin/sh
# This script tries to follow the "GNU way" w.r.t. the autobits.
# This does of course generate a number of irritating files.
# Try to get over it (I am getting there myself).
# This should generate any missing crud, and then run autoconf which should turn
# configure.in into a "./configure" script and "Makefile.am" into a
# "Makefile.in". Then running "./configure" should turn "Makefile.in" into
# "Makefile" and should generate the config.h containing your systems various
# settings. I know ... what a hassle ...
# Also, sometimes these autobits things generate bizarre output (looking like
# errors). So I direct everything "elsewhere" ...
(aclocal
autoheader
libtoolize --copy --force
automake --foreign --add-missing --copy
autoconf) 1> /dev/null 2>&1
# Move the "no-autotools" Makefile out of the way
if test ! -f Makefile.plain; then
mv Makefile Makefile.plain
fi
#!/bin/sh
# This script tries to clean up as much as is possible from whatever diabolical
# mess has been left in the directory thanks to autoconf, automake, and their
# friends.
if test -f Makefile.plain; then
if test -f Makefile; then
make distclean
fi
mv Makefile.plain Makefile
else
make clean
fi
rm -f aclocal.m4 config.* configure install-sh \
missing mkinstalldirs stamp-h.* Makefile.in \
ltconfig ltmain.sh depcomp
rm -rf autom4te.cache
#include "tunala.h"
int int_strtoul(const char *str, unsigned long *val)
{
#ifdef HAVE_STRTOUL
char *tmp;
unsigned long ret = strtoul(str, &tmp, 10);
if((str == tmp) || (*tmp != '\0'))
/* The value didn't parse cleanly */
return 0;
if(ret == ULONG_MAX)
/* We hit a limit */
return 0;
*val = ret;
return 1;
#else
char buf[2];
unsigned long ret = 0;
buf[1] = '\0';
if(str == '\0')
/* An empty string ... */
return 0;
while(*str != '\0') {
/* We have to multiply 'ret' by 10 before absorbing the next
* digit. If this will overflow, catch it now. */
if(ret && (((ULONG_MAX + 10) / ret) < 10))
return 0;
ret *= 10;
if(!isdigit(*str))
return 0;
buf[0] = *str;
ret += atoi(buf);
str++;
}
*val = ret;
return 1;
#endif
}
#ifndef HAVE_STRSTR
char *int_strstr(const char *haystack, const char *needle)
{
const char *sub_haystack = haystack, *sub_needle = needle;
unsigned int offset = 0;
if(!needle)
return haystack;
if(!haystack)
return NULL;
while((*sub_haystack != '\0') && (*sub_needle != '\0')) {
if(sub_haystack[offset] == sub_needle) {
/* sub_haystack is still a candidate */
offset++;
sub_needle++;
} else {
/* sub_haystack is no longer a possibility */
sub_haystack++;
offset = 0;
sub_needle = needle;
}
}
if(*sub_haystack == '\0')
/* Found nothing */
return NULL;
return sub_haystack;
}
#endif
#include "tunala.h"
#ifndef NO_BUFFER
void buffer_init(buffer_t *buf)
{
buf->used = 0;
buf->total_in = buf->total_out = 0;
}
void buffer_close(buffer_t *buf)
{
/* Our data is static - nothing needs "release", just reset it */
buf->used = 0;
}
/* Code these simple ones in compact form */
unsigned int buffer_used(buffer_t *buf) {
return buf->used; }
unsigned int buffer_unused(buffer_t *buf) {
return (MAX_DATA_SIZE - buf->used); }
int buffer_full(buffer_t *buf) {
return (buf->used == MAX_DATA_SIZE ? 1 : 0); }
int buffer_notfull(buffer_t *buf) {
return (buf->used < MAX_DATA_SIZE ? 1 : 0); }
int buffer_empty(buffer_t *buf) {
return (buf->used == 0 ? 1 : 0); }
int buffer_notempty(buffer_t *buf) {
return (buf->used > 0 ? 1 : 0); }
unsigned long buffer_total_in(buffer_t *buf) {
return buf->total_in; }
unsigned long buffer_total_out(buffer_t *buf) {
return buf->total_out; }
/* These 3 static (internal) functions don't adjust the "total" variables as
* it's not sure when they're called how it should be interpreted. Only the
* higher-level "buffer_[to|from]_[fd|SSL|BIO]" functions should alter these
* values. */
#if 0 /* To avoid "unused" warnings */
static unsigned int buffer_adddata(buffer_t *buf, const unsigned char *ptr,
unsigned int size)
{
unsigned int added = MAX_DATA_SIZE - buf->used;
if(added > size)
added = size;
if(added == 0)
return 0;
memcpy(buf->data + buf->used, ptr, added);
buf->used += added;
buf->total_in += added;
return added;
}
static unsigned int buffer_tobuffer(buffer_t *to, buffer_t *from, int cap)
{
unsigned int moved, tomove = from->used;
if((int)tomove > cap)
tomove = cap;
if(tomove == 0)
return 0;
moved = buffer_adddata(to, from->data, tomove);
if(moved == 0)
return 0;
buffer_takedata(from, NULL, moved);
return moved;
}
#endif
static unsigned int buffer_takedata(buffer_t *buf, unsigned char *ptr,
unsigned int size)
{
unsigned int taken = buf->used;
if(taken > size)
taken = size;
if(taken == 0)
return 0;
if(ptr)
memcpy(ptr, buf->data, taken);
buf->used -= taken;
/* Do we have to scroll? */
if(buf->used > 0)
memmove(buf->data, buf->data + taken, buf->used);
return taken;
}
#ifndef NO_IP
int buffer_from_fd(buffer_t *buf, int fd)
{
int toread = buffer_unused(buf);
if(toread == 0)
/* Shouldn't be called in this case! */
abort();
toread = read(fd, buf->data + buf->used, toread);
if(toread > 0) {
buf->used += toread;
buf->total_in += toread;
}
return toread;
}
int buffer_to_fd(buffer_t *buf, int fd)
{
int towrite = buffer_used(buf);
if(towrite == 0)
/* Shouldn't be called in this case! */
abort();
towrite = write(fd, buf->data, towrite);
if(towrite > 0) {
buffer_takedata(buf, NULL, towrite);
buf->total_out += towrite;
}
return towrite;
}
#endif /* !defined(NO_IP) */
#ifndef NO_OPENSSL
static void int_ssl_check(SSL *s, int ret)
{
int e = SSL_get_error(s, ret);
switch(e) {
/* These seem to be harmless and already "dealt with" by our
* non-blocking environment. NB: "ZERO_RETURN" is the clean
* "error" indicating a successfully closed SSL tunnel. We let
* this happen because our IO loop should not appear to have
* broken on this condition - and outside the IO loop, the
* "shutdown" state is checked. */
case SSL_ERROR_NONE:
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
case SSL_ERROR_WANT_X509_LOOKUP:
case SSL_ERROR_ZERO_RETURN:
return;
/* These seem to be indications of a genuine error that should
* result in the SSL tunnel being regarded as "dead". */
case SSL_ERROR_SYSCALL:
case SSL_ERROR_SSL:
SSL_set_app_data(s, (char *)1);
return;
default:
break;
}
/* For any other errors that (a) exist, and (b) crop up - we need to
* interpret what to do with them - so "politely inform" the caller that
* the code needs updating here. */
abort();
}
void buffer_from_SSL(buffer_t *buf, SSL *ssl)
{
int ret;
if(!ssl || buffer_full(buf))
return;
ret = SSL_read(ssl, buf->data + buf->used, buffer_unused(buf));
if(ret > 0) {
buf->used += ret;
buf->total_in += ret;
}
if(ret < 0)
int_ssl_check(ssl, ret);
}
void buffer_to_SSL(buffer_t *buf, SSL *ssl)
{
int ret;
if(!ssl || buffer_empty(buf))
return;
ret = SSL_write(ssl, buf->data, buf->used);
if(ret > 0) {
buffer_takedata(buf, NULL, ret);
buf->total_out += ret;
}
if(ret < 0)
int_ssl_check(ssl, ret);
}
void buffer_from_BIO(buffer_t *buf, BIO *bio)
{
int ret;
if(!bio || buffer_full(buf))
return;
ret = BIO_read(bio, buf->data + buf->used, buffer_unused(buf));
if(ret > 0) {
buf->used += ret;
buf->total_in += ret;
}
}
void buffer_to_BIO(buffer_t *buf, BIO *bio)
{
int ret;
if(!bio || buffer_empty(buf))
return;
ret = BIO_write(bio, buf->data, buf->used);
if(ret > 0) {
buffer_takedata(buf, NULL, ret);
buf->total_out += ret;
}
}
#endif /* !defined(NO_OPENSSL) */
#endif /* !defined(NO_BUFFER) */
#include "tunala.h"
#ifndef NO_OPENSSL
/* For callbacks generating output, here are their file-descriptors. */
static FILE *fp_cb_ssl_info = NULL;
static FILE *fp_cb_ssl_verify = NULL;
/* Output level:
* 0 = nothing,
* 1 = minimal, just errors,
* 2 = minimal, all steps,
* 3 = detail, all steps */
static unsigned int cb_ssl_verify_level = 1;
/* Other static rubbish (to mirror s_cb.c where required) */
static int int_verify_depth = 10;
/* This function is largely borrowed from the one used in OpenSSL's "s_client"
* and "s_server" utilities. */
void cb_ssl_info(const SSL *s, int where, int ret)
{
const char *str1, *str2;
int w;
if(!fp_cb_ssl_info)
return;
w = where & ~SSL_ST_MASK;
str1 = (w & SSL_ST_CONNECT ? "SSL_connect" : (w & SSL_ST_ACCEPT ?
"SSL_accept" : "undefined")),
str2 = SSL_state_string_long(s);
if (where & SSL_CB_LOOP)
fprintf(fp_cb_ssl_info, "(%s) %s\n", str1, str2);
else if (where & SSL_CB_EXIT) {
if (ret == 0)
fprintf(fp_cb_ssl_info, "(%s) failed in %s\n", str1, str2);
/* In a non-blocking model, we get a few of these "error"s simply because we're
* calling "reads" and "writes" on the state-machine that are virtual NOPs
* simply to avoid wasting the time seeing if we *should* call them. Removing
* this case makes the "-out_state" output a lot easier on the eye. */
#if 0
else if (ret < 0)
fprintf(fp_cb_ssl_info, "%s:error in %s\n", str1, str2);
#endif
}
}
void cb_ssl_info_set_output(FILE *fp)
{
fp_cb_ssl_info = fp;
}
static const char *int_reason_no_issuer = "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT";
static const char *int_reason_not_yet = "X509_V_ERR_CERT_NOT_YET_VALID";
static const char *int_reason_before = "X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD";
static const char *int_reason_expired = "X509_V_ERR_CERT_HAS_EXPIRED";
static const char *int_reason_after = "X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD";
/* Stolen wholesale from apps/s_cb.c :-) And since then, mutilated ... */
int cb_ssl_verify(int ok, X509_STORE_CTX *ctx)
{
char buf1[256]; /* Used for the subject name */
char buf2[256]; /* Used for the issuer name */
const char *reason = NULL; /* Error reason (if any) */
X509 *err_cert;
int err, depth;
if(!fp_cb_ssl_verify || (cb_ssl_verify_level == 0))
return ok;
err_cert = X509_STORE_CTX_get_current_cert(ctx);
err = X509_STORE_CTX_get_error(ctx);
depth = X509_STORE_CTX_get_error_depth(ctx);
buf1[0] = buf2[0] = '\0';
/* Fill buf1 */
X509_NAME_oneline(X509_get_subject_name(err_cert), buf1, 256);
/* Fill buf2 */
X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf2, 256);
switch (ctx->error) {
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
reason = int_reason_no_issuer;
break;
case X509_V_ERR_CERT_NOT_YET_VALID:
reason = int_reason_not_yet;
break;
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
reason = int_reason_before;
break;
case X509_V_ERR_CERT_HAS_EXPIRED:
reason = int_reason_expired;
break;
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
reason = int_reason_after;
break;
}
if((cb_ssl_verify_level == 1) && ok)
return ok;
fprintf(fp_cb_ssl_verify, "chain-depth=%d, ", depth);
if(reason)
fprintf(fp_cb_ssl_verify, "error=%s\n", reason);
else
fprintf(fp_cb_ssl_verify, "error=%d\n", err);
if(cb_ssl_verify_level < 3)
return ok;
fprintf(fp_cb_ssl_verify, "--> subject = %s\n", buf1);
fprintf(fp_cb_ssl_verify, "--> issuer = %s\n", buf2);
if(!ok)
fprintf(fp_cb_ssl_verify,"--> verify error:num=%d:%s\n",err,
X509_verify_cert_error_string(err));
fprintf(fp_cb_ssl_verify, "--> verify return:%d\n",ok);
return ok;
}
void cb_ssl_verify_set_output(FILE *fp)
{
fp_cb_ssl_verify = fp;
}
void cb_ssl_verify_set_depth(unsigned int verify_depth)
{
int_verify_depth = verify_depth;
}
void cb_ssl_verify_set_level(unsigned int level)
{
if(level < 4)
cb_ssl_verify_level = level;
}
RSA *cb_generate_tmp_rsa(SSL *s, int is_export, int keylength)
{
/* TODO: Perhaps make it so our global key can be generated on-the-fly
* after certain intervals? */
static RSA *rsa_tmp = NULL;
BIGNUM *bn = NULL;
int ok = 1;
if(!rsa_tmp) {
ok = 0;
if(!(bn = BN_new()))
goto end;
if(!BN_set_word(bn, RSA_F4))
goto end;
if(!(rsa_tmp = RSA_new()))
goto end;
if(!RSA_generate_key_ex(rsa_tmp, keylength, bn, NULL))
goto end;
ok = 1;
}
end:
if(bn)
BN_free(bn);
if(!ok) {
RSA_free(rsa_tmp);
rsa_tmp = NULL;
}
return rsa_tmp;
}
#endif /* !defined(NO_OPENSSL) */
dnl Process this file with autoconf to produce a configure script.
AC_INIT(tunala.c)
AM_CONFIG_HEADER(config.h)
AM_INIT_AUTOMAKE(tunala, 0.0.1-dev)
dnl Checks for programs. (Though skip libtool)
AC_PROG_CC
dnl AC_PROG_LIBTOOL
dnl AM_PROG_LIBTOOL
dnl Checks for libraries.
AC_CHECK_LIB(dl, dlopen)
AC_CHECK_LIB(z, inflate)
AC_CHECK_LIB(socket, socket)
AC_CHECK_LIB(nsl, gethostbyname)
dnl Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS(fcntl.h limits.h unistd.h)
dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
dnl Checks for library functions.
AC_CHECK_FUNCS(strstr strtoul)
AC_CHECK_FUNCS(select socket)
AC_CHECK_FUNCS(dlopen)
AC_OUTPUT(Makefile)
#include "tunala.h"
#ifndef NO_IP
#define IP_LISTENER_BACKLOG 511 /* So if it gets masked by 256 or some other
such value it'll still be respectable */
/* Any IP-related initialisations. For now, this means blocking SIGPIPE */
int ip_initialise(void)
{
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
if(sigaction(SIGPIPE, &sa, NULL) != 0)
return 0;
return 1;
}
int ip_create_listener_split(const char *ip, unsigned short port)
{
struct sockaddr_in in_addr;
int fd = -1;
int reuseVal = 1;
/* Create the socket */
if((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
goto err;
/* Set the SO_REUSEADDR flag - servers act weird without it */
if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)(&reuseVal),
sizeof(reuseVal)) != 0)
goto err;
/* Prepare the listen address stuff */
in_addr.sin_family = AF_INET;
memcpy(&in_addr.sin_addr.s_addr, ip, 4);
in_addr.sin_port = htons(port);
/* Bind to the required port/address/interface */
if(bind(fd, (struct sockaddr *)&in_addr, sizeof(struct sockaddr_in)) != 0)
goto err;
/* Start "listening" */
if(listen(fd, IP_LISTENER_BACKLOG) != 0)
goto err;
return fd;
err:
if(fd != -1)
close(fd);
return -1;
}
int ip_create_connection_split(const char *ip, unsigned short port)
{
struct sockaddr_in in_addr;
int flags, fd = -1;
/* Create the socket */
if((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
goto err;
/* Make it non-blocking */
if(((flags = fcntl(fd, F_GETFL, 0)) < 0) ||
(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0))
goto err;
/* Prepare the connection address stuff */
in_addr.sin_family = AF_INET;
memcpy(&in_addr.sin_addr.s_addr, ip, 4);
in_addr.sin_port = htons(port);
/* Start a connect (non-blocking, in all likelihood) */
if((connect(fd, (struct sockaddr *)&in_addr,
sizeof(struct sockaddr_in)) != 0) &&
(errno != EINPROGRESS))
goto err;
return fd;
err:
if(fd != -1)
close(fd);
return -1;
}
static char all_local_ip[] = {0x00,0x00,0x00,0x00};
int ip_parse_address(const char *address, const char **parsed_ip,
unsigned short *parsed_port, int accept_all_ip)
{
char buf[256];
struct hostent *lookup;
unsigned long port;
const char *ptr = strstr(address, ":");
const char *ip = all_local_ip;
if(!ptr) {
/* We assume we're listening on all local interfaces and have
* only specified a port. */
if(!accept_all_ip)
return 0;
ptr = address;
goto determine_port;
}
if((ptr - address) > 255)
return 0;
memset(buf, 0, 256);
memcpy(buf, address, ptr - address);
ptr++;
if((lookup = gethostbyname(buf)) == NULL) {
/* Spit a message to differentiate between lookup failures and
* bad strings. */
fprintf(stderr, "hostname lookup for '%s' failed\n", buf);
return 0;
}
ip = lookup->h_addr_list[0];
determine_port:
if(strlen(ptr) < 1)
return 0;
if(!int_strtoul(ptr, &port) || (port > 65535))
return 0;
*parsed_ip = ip;
*parsed_port = (unsigned short)port;
return 1;
}
int ip_create_listener(const char *address)
{
const char *ip;
unsigned short port;
if(!ip_parse_address(address, &ip, &port, 1))
return -1;
return ip_create_listener_split(ip, port);
}
int ip_create_connection(const char *address)
{
const char *ip;
unsigned short port;
if(!ip_parse_address(address, &ip, &port, 0))
return -1;
return ip_create_connection_split(ip, port);
}
int ip_accept_connection(int listen_fd)
{
return accept(listen_fd, NULL, NULL);
}
#endif /* !defined(NO_IP) */
#include "tunala.h"
#ifndef NO_TUNALA
void state_machine_init(state_machine_t *machine)
{
machine->ssl = NULL;
machine->bio_intossl = machine->bio_fromssl = NULL;
buffer_init(&machine->clean_in);
buffer_init(&machine->clean_out);
buffer_init(&machine->dirty_in);
buffer_init(&machine->dirty_out);
}
void state_machine_close(state_machine_t *machine)
{
if(machine->ssl)
SSL_free(machine->ssl);
/* SSL_free seems to decrement the reference counts already so doing this goes
* kaboom. */
#if 0
if(machine->bio_intossl)
BIO_free(machine->bio_intossl);
if(machine->bio_fromssl)
BIO_free(machine->bio_fromssl);
#endif
buffer_close(&machine->clean_in);
buffer_close(&machine->clean_out);
buffer_close(&machine->dirty_in);
buffer_close(&machine->dirty_out);
state_machine_init(machine);
}
buffer_t *state_machine_get_buffer(state_machine_t *machine, sm_buffer_t type)
{
switch(type) {
case SM_CLEAN_IN:
return &machine->clean_in;
case SM_CLEAN_OUT:
return &machine->clean_out;
case SM_DIRTY_IN:
return &machine->dirty_in;
case SM_DIRTY_OUT:
return &machine->dirty_out;
default:
break;
}
/* Should never get here */
abort();
return NULL;
}
SSL *state_machine_get_SSL(state_machine_t *machine)
{
return machine->ssl;
}
int state_machine_set_SSL(state_machine_t *machine, SSL *ssl, int is_server)
{
if(machine->ssl)
/* Shouldn't ever be set twice */
abort();
machine->ssl = ssl;
/* Create the BIOs to handle the dirty side of the SSL */
if((machine->bio_intossl = BIO_new(BIO_s_mem())) == NULL)
abort();
if((machine->bio_fromssl = BIO_new(BIO_s_mem())) == NULL)
abort();
/* Hook up the BIOs on the dirty side of the SSL */
SSL_set_bio(machine->ssl, machine->bio_intossl, machine->bio_fromssl);
if(is_server)
SSL_set_accept_state(machine->ssl);
else
SSL_set_connect_state(machine->ssl);
/* If we're the first one to generate traffic - do it now otherwise we
* go into the next select empty-handed and our peer will not send data
* but will similarly wait for us. */
return state_machine_churn(machine);
}
/* Performs the data-IO loop and returns zero if the machine should close */
int state_machine_churn(state_machine_t *machine)
{
unsigned int loop;
if(machine->ssl == NULL) {
if(buffer_empty(&machine->clean_out))
/* Time to close this state-machine altogether */
return 0;
else
/* Still buffered data on the clean side to go out */
return 1;
}
/* Do this loop twice to cover any dependencies about which precise
* order of reads and writes is required. */
for(loop = 0; loop < 2; loop++) {
buffer_to_SSL(&machine->clean_in, machine->ssl);
buffer_to_BIO(&machine->dirty_in, machine->bio_intossl);
buffer_from_SSL(&machine->clean_out, machine->ssl);
buffer_from_BIO(&machine->dirty_out, machine->bio_fromssl);
}
/* We close on the SSL side if the info callback noticed some problems
* or an SSL shutdown was underway and shutdown traffic had all been
* sent. */
if(SSL_get_app_data(machine->ssl) || (SSL_get_shutdown(machine->ssl) &&
buffer_empty(&machine->dirty_out))) {
/* Great, we can seal off the dirty side completely */
if(!state_machine_close_dirty(machine))
return 0;
}
/* Either the SSL is alive and well, or the closing process still has
* outgoing data waiting to be sent */
return 1;
}
/* Called when the clean side of the SSL has lost its connection */
int state_machine_close_clean(state_machine_t *machine)
{
/* Well, first thing to do is null out the clean-side buffers - they're
* no use any more. */
buffer_close(&machine->clean_in);
buffer_close(&machine->clean_out);
/* And start an SSL shutdown */
if(machine->ssl)
SSL_shutdown(machine->ssl);
/* This is an "event", so flush the SSL of any generated traffic */
state_machine_churn(machine);
if(buffer_empty(&machine->dirty_in) &&
buffer_empty(&machine->dirty_out))
return 0;
return 1;
}
/* Called when the dirty side of the SSL has lost its connection. This is pretty
* terminal as all that can be left to do is send any buffered output on the
* clean side - after that, we're done. */
int state_machine_close_dirty(state_machine_t *machine)
{
buffer_close(&machine->dirty_in);
buffer_close(&machine->dirty_out);
buffer_close(&machine->clean_in);
if(machine->ssl)
SSL_free(machine->ssl);
machine->ssl = NULL;
machine->bio_intossl = machine->bio_fromssl = NULL;
if(buffer_empty(&machine->clean_out))
return 0;
return 1;
}
#endif /* !defined(NO_TUNALA) */
#!/bin/sh
HTTP="localhost:8080"
CLIENT_PORT="9020"
SERVER_PORT="9021"
sub_test ()
{
echo "STARTING - $VER $CIPHER"
./tunala -listen localhost:$CLIENT_PORT -proxy localhost:$SERVER_PORT \
-cacert CA.pem -cert A-client.pem -server 0 \
-dh_special standard -v_peer -v_strict \
$VER -cipher $CIPHER 1> tc1.txt 2> tc2.txt &
./tunala -listen localhost:$SERVER_PORT -proxy $HTTP \
-cacert CA.pem -cert A-server.pem -server 1 \
-dh_special standard -v_peer -v_strict \
$VER -cipher $CIPHER 1> ts1.txt 2> ts2.txt &
# Wait for the servers to be listening before starting the wget test
DONE="no"
while [ "$DONE" != "yes" ]; do
L1=`netstat -a | egrep "LISTEN[\t ]*$" | grep ":$CLIENT_PORT"`
L2=`netstat -a | egrep "LISTEN[\t ]*$" | grep ":$SERVER_PORT"`
if [ "x$L1" != "x" ]; then
DONE="yes"
elif [ "x$L2" != "x" ]; then
DONE="yes"
else
sleep 1
fi
done
HTML=`wget -O - -T 1 http://localhost:$CLIENT_PORT 2> /dev/null | grep "<HTML>"`
if [ "x$HTML" != "x" ]; then
echo "OK - $CIPHER ($VER)"
else
echo "FAIL - $CIPHER ($VER)"
killall tunala
exit 1
fi
killall tunala
# Wait for the servers to stop before returning - otherwise the next
# test my fail to start ... (fscking race conditions)
DONE="yes"
while [ "$DONE" != "no" ]; do
L1=`netstat -a | egrep "LISTEN[\t ]*$" | grep ":$CLIENT_PORT"`
L2=`netstat -a | egrep "LISTEN[\t ]*$" | grep ":$SERVER_PORT"`
if [ "x$L1" != "x" ]; then
DONE="yes"
elif [ "x$L2" != "x" ]; then
DONE="yes"
else
DONE="no"
fi
done
exit 0
}
run_test ()
{
(sub_test 1> /dev/null) || exit 1
}
run_ssl_test ()
{
killall tunala 1> /dev/null 2> /dev/null
echo ""
echo "Starting all $PRETTY tests"
if [ "$PRETTY" != "SSLv2" ]; then
if [ "$PRETTY" != "SSLv3" ]; then
export VER="-no_ssl2 -no_ssl3"
export OSSL="-tls1"
else
export VER="-no_ssl2 -no_tls1"
export OSSL="-ssl3"
fi
else
export VER="-no_ssl3 -no_tls1"
export OSSL="-ssl2"
fi
LIST="`../../apps/openssl ciphers $OSSL | sed -e 's/:/ /g'`"
#echo "$LIST"
for i in $LIST; do \
DSS=`echo "$i" | grep "DSS"`
if [ "x$DSS" != "x" ]; then
echo "---- skipping $i (no DSA cert/keys) ----"
else
export CIPHER=$i
run_test
echo "SUCCESS: $i"
fi
done;
}
# Welcome the user
echo "Tests will assume an http server running at $HTTP"
# TLSv1 test
export PRETTY="TLSv1"
run_ssl_test
# SSLv3 test
export PRETTY="SSLv3"
run_ssl_test
# SSLv2 test
export PRETTY="SSLv2"
run_ssl_test
此差异已折叠。
/* Tunala ("Tunneler with a New Zealand accent")
*
* Written by Geoff Thorpe, but endorsed/supported by noone. Please use this is
* if it's useful or informative to you, but it's only here as a scratchpad for
* ideas about how you might (or might not) program with OpenSSL. If you deploy
* this is in a mission-critical environment, and have not read, understood,
* audited, and modified this code to your satisfaction, and the result is that
* all hell breaks loose and you are looking for a new employer, then it proves
* nothing except perhaps that Darwinism is alive and well. Let's just say, *I*
* don't use this in a mission-critical environment, so it would be stupid for
* anyone to assume that it is solid and/or tested enough when even its author
* doesn't place that much trust in it. You have been warned.
*
* With thanks to Cryptographic Appliances, Inc.
*/
#ifndef _TUNALA_H
#define _TUNALA_H
/* pull in autoconf fluff */
#ifndef NO_CONFIG_H
#include "config.h"
#else
/* We don't have autoconf, we have to set all of these unless a tweaked Makefile
* tells us not to ... */
/* headers */
#ifndef NO_HAVE_SELECT
#define HAVE_SELECT
#endif
#ifndef NO_HAVE_SOCKET
#define HAVE_SOCKET
#endif
#ifndef NO_HAVE_UNISTD_H
#define HAVE_UNISTD_H
#endif
#ifndef NO_HAVE_FCNTL_H
#define HAVE_FCNTL_H
#endif
#ifndef NO_HAVE_LIMITS_H
#define HAVE_LIMITS_H
#endif
/* features */
#ifndef NO_HAVE_STRSTR
#define HAVE_STRSTR
#endif
#ifndef NO_HAVE_STRTOUL
#define HAVE_STRTOUL
#endif
#endif
#if !defined(HAVE_SELECT) || !defined(HAVE_SOCKET)
#error "can't build without some network basics like select() and socket()"
#endif
#include <stdlib.h>
#ifndef NO_SYSTEM_H
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#include <netdb.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#endif /* !defined(NO_SYSTEM_H) */
#ifndef NO_OPENSSL
#include <openssl/err.h>
#include <openssl/engine.h>
#include <openssl/ssl.h>
#endif /* !defined(NO_OPENSSL) */
#ifndef OPENSSL_NO_BUFFER
/* This is the generic "buffer" type that is used when feeding the
* state-machine. It's basically a FIFO with respect to the "adddata" &
* "takedata" type functions that operate on it. */
#define MAX_DATA_SIZE 16384
typedef struct _buffer_t {
unsigned char data[MAX_DATA_SIZE];
unsigned int used;
/* Statistical values - counts the total number of bytes read in and
* read out (respectively) since "buffer_init()" */
unsigned long total_in, total_out;
} buffer_t;
/* Initialise a buffer structure before use */
void buffer_init(buffer_t *buf);
/* Cleanup a buffer structure - presently not needed, but if buffer_t is
* converted to using dynamic allocation, this would be required - so should be
* called to protect against an explosion of memory leaks later if the change is
* made. */
void buffer_close(buffer_t *buf);
/* Basic functions to manipulate buffers */
unsigned int buffer_used(buffer_t *buf); /* How much data in the buffer */
unsigned int buffer_unused(buffer_t *buf); /* How much space in the buffer */
int buffer_full(buffer_t *buf); /* Boolean, is it full? */
int buffer_notfull(buffer_t *buf); /* Boolean, is it not full? */
int buffer_empty(buffer_t *buf); /* Boolean, is it empty? */
int buffer_notempty(buffer_t *buf); /* Boolean, is it not empty? */
unsigned long buffer_total_in(buffer_t *buf); /* Total bytes written to buffer */
unsigned long buffer_total_out(buffer_t *buf); /* Total bytes read from buffer */
#if 0 /* Currently used only within buffer.c - better to expose only
* higher-level functions anyway */
/* Add data to the tail of the buffer, returns the amount that was actually
* added (so, you need to check if return value is less than size) */
unsigned int buffer_adddata(buffer_t *buf, const unsigned char *ptr,
unsigned int size);
/* Take data from the front of the buffer (and scroll the rest forward). If
* "ptr" is NULL, this just removes data off the front of the buffer. Return
* value is the amount actually removed (can be less than size if the buffer has
* too little data). */
unsigned int buffer_takedata(buffer_t *buf, unsigned char *ptr,
unsigned int size);
/* Flushes as much data as possible out of the "from" buffer into the "to"
* buffer. Return value is the amount moved. The amount moved can be restricted
* to a maximum by specifying "cap" - setting it to -1 means no limit. */
unsigned int buffer_tobuffer(buffer_t *to, buffer_t *from, int cap);
#endif
#ifndef NO_IP
/* Read or write between a file-descriptor and a buffer */
int buffer_from_fd(buffer_t *buf, int fd);
int buffer_to_fd(buffer_t *buf, int fd);
#endif /* !defined(NO_IP) */
#ifndef NO_OPENSSL
/* Read or write between an SSL or BIO and a buffer */
void buffer_from_SSL(buffer_t *buf, SSL *ssl);
void buffer_to_SSL(buffer_t *buf, SSL *ssl);
void buffer_from_BIO(buffer_t *buf, BIO *bio);
void buffer_to_BIO(buffer_t *buf, BIO *bio);
/* Callbacks */
void cb_ssl_info(const SSL *s, int where, int ret);
void cb_ssl_info_set_output(FILE *fp); /* Called if output should be sent too */
int cb_ssl_verify(int ok, X509_STORE_CTX *ctx);
void cb_ssl_verify_set_output(FILE *fp);
void cb_ssl_verify_set_depth(unsigned int verify_depth);
void cb_ssl_verify_set_level(unsigned int level);
RSA *cb_generate_tmp_rsa(SSL *s, int is_export, int keylength);
#endif /* !defined(NO_OPENSSL) */
#endif /* !defined(OPENSSL_NO_BUFFER) */
#ifndef NO_TUNALA
#ifdef OPENSSL_NO_BUFFER
#error "TUNALA section of tunala.h requires BUFFER support"
#endif
typedef struct _state_machine_t {
SSL *ssl;
BIO *bio_intossl;
BIO *bio_fromssl;
buffer_t clean_in, clean_out;
buffer_t dirty_in, dirty_out;
} state_machine_t;
typedef enum {
SM_CLEAN_IN, SM_CLEAN_OUT,
SM_DIRTY_IN, SM_DIRTY_OUT
} sm_buffer_t;
void state_machine_init(state_machine_t *machine);
void state_machine_close(state_machine_t *machine);
buffer_t *state_machine_get_buffer(state_machine_t *machine, sm_buffer_t type);
SSL *state_machine_get_SSL(state_machine_t *machine);
int state_machine_set_SSL(state_machine_t *machine, SSL *ssl, int is_server);
/* Performs the data-IO loop and returns zero if the machine should close */
int state_machine_churn(state_machine_t *machine);
/* Is used to handle closing conditions - namely when one side of the tunnel has
* closed but the other should finish flushing. */
int state_machine_close_clean(state_machine_t *machine);
int state_machine_close_dirty(state_machine_t *machine);
#endif /* !defined(NO_TUNALA) */
#ifndef NO_IP
/* Initialise anything related to the networking. This includes blocking pesky
* SIGPIPE signals. */
int ip_initialise(void);
/* ip is the 4-byte ip address (eg. 127.0.0.1 is {0x7F,0x00,0x00,0x01}), port is
* the port to listen on (host byte order), and the return value is the
* file-descriptor or -1 on error. */
int ip_create_listener_split(const char *ip, unsigned short port);
/* Same semantics as above. */
int ip_create_connection_split(const char *ip, unsigned short port);
/* Converts a string into the ip/port before calling the above */
int ip_create_listener(const char *address);
int ip_create_connection(const char *address);
/* Just does a string conversion on its own. NB: If accept_all_ip is non-zero,
* then the address string could be just a port. Ie. it's suitable for a
* listening address but not a connecting address. */
int ip_parse_address(const char *address, const char **parsed_ip,
unsigned short *port, int accept_all_ip);
/* Accepts an incoming connection through the listener. Assumes selects and
* what-not have deemed it an appropriate thing to do. */
int ip_accept_connection(int listen_fd);
#endif /* !defined(NO_IP) */
/* These functions wrap up things that can be portability hassles. */
int int_strtoul(const char *str, unsigned long *val);
#ifdef HAVE_STRSTR
#define int_strstr strstr
#else
char *int_strstr(const char *haystack, const char *needle);
#endif
#endif /* !defined(_TUNALA_H) */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册