diff options
author | Geoff Thorpe <geoff@openssl.org> | 2000-11-01 23:11:19 +0000 |
---|---|---|
committer | Geoff Thorpe <geoff@openssl.org> | 2000-11-01 23:11:19 +0000 |
commit | d1855cc7af56acb62407618711ee5e90a805e231 (patch) | |
tree | 788db0508b6b72d79fecf2e868cd684a8e51a3b5 /demos/tunala | |
parent | 14c6d27d63795ead1b70d97e3303731b433c0db8 (diff) |
This is a demo that performs SSL tunneling (client and/or server) and is
built using an abstracted state machine with a non-blocking IP wrapper
around it. README will follow in the next commit.
Diffstat (limited to 'demos/tunala')
-rw-r--r-- | demos/tunala/A-client.pem | 85 | ||||
-rw-r--r-- | demos/tunala/A-server.pem | 85 | ||||
-rw-r--r-- | demos/tunala/CA.pem | 24 | ||||
-rw-r--r-- | demos/tunala/Makefile | 40 | ||||
-rw-r--r-- | demos/tunala/buffer.c | 146 | ||||
-rw-r--r-- | demos/tunala/ip.c | 147 | ||||
-rw-r--r-- | demos/tunala/sm.c | 149 | ||||
-rw-r--r-- | demos/tunala/tunala.c | 733 | ||||
-rw-r--r-- | demos/tunala/tunala.h | 146 |
9 files changed, 1555 insertions, 0 deletions
diff --git a/demos/tunala/A-client.pem b/demos/tunala/A-client.pem new file mode 100644 index 0000000000..6b6c341182 --- /dev/null +++ b/demos/tunala/A-client.pem @@ -0,0 +1,85 @@ +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: Nov 1 21:09:30 2000 GMT + Not After : Nov 1 21:09:30 2001 GMT + Subject: C=NZ, L=Auckland, O=Silly City-Boys Corp., OU=Internal counselling, CN=tunala-client/Email=client@fake.domain + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (1024 bit) + Modulus (1024 bit): + 00:a5:b2:8e:de:05:d1:fe:29:f7:46:a6:6b:a0:e5: + 41:2c:f7:55:a8:53:5a:e8:37:1a:68:29:5d:fd:7e: + a4:40:b5:ce:e0:44:54:9e:c6:f8:9a:40:bb:45:41: + 57:cc:dc:97:d9:66:3e:68:9d:29:93:15:f9:2b:75: + aa:49:7f:e6:cf:7f:95:44:8e:41:ed:05:97:1e:cb: + 3f:03:33:b0:21:2b:89:67:08:cc:7b:b2:ef:fa:26: + c7:ea:21:f2:77:5f:bd:e2:67:36:0a:e2:3d:ee:76: + 4f:d2:d3:e9:bb:22:c0:bb:0c:e4:a2:8c:aa:71:3b: + 75:6c:46:a7:d2:1b:57:ee:f3 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + 74:A8:8B:1F:5B:59:55:09:CB:98:5C:2F:41:87:CA:AC:D4:B5:04:FF + X509v3 Authority Key Identifier: + keyid:57:5A:5D:E0:71:0B:0C:E0:0F:51:87:DE:08:C8:25:E7:F7:87:46:C0 + 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 + 5f:36:74:77:1d:c7:56:71:d3:32:30:12:8f:4d:8e:25:90:1c: + b3:2e:e0:c1:77:75:ea:2c:aa:ef:82:c8:e0:86:8c:df:dc:e1: + 86:68:81:91:1e:4e:56:b1:5d:93:6f:80:10:80:c3:d8:c4:3b: + 0f:20:dd:43:b5:f8:09:a4:bb:a9:04:11:e0:d4:f9:d9:83:19: + 2a:da:7c:bb:4c:c2:4f:57:43:0d:1a:1e:31:61:fb:24:62:92: + 74:12:9c:51:ef:12:3e:23:e4:45:66:2b:ac:00:60:bf:a0:ff: + 43:da:95:c3:cf:64:40:d2:97:8d:c1:dd:26:ce:5f:b9:a1:ea: + 92:32 +-----BEGIN CERTIFICATE----- +MIIECDCCA3GgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBtDELMAkGA1UEBhMCTlox +EzARBgNVBAcTCldlbGxpbmd0b24xPDA6BgNVBAoTM1JlYWxseSBJcnJlc3BvbnNp +YmxlIEF1dGhvcmlzYXRpb24gQXV0aG9yaXR5IChSSUFBKTEWMBQGA1UECxMNQ2Vy +dC1zdGFtcGluZzEZMBcGA1UEAxMQSmFja292IGFsLVRyYWRlczEfMB0GCSqGSIb3 +DQEJARYQbm9uZUBmYWtlLmRvbWFpbjAeFw0wMDExMDEyMTA5MzBaFw0wMTExMDEy +MTA5MzBaMIGaMQswCQYDVQQGEwJOWjERMA8GA1UEBxMIQXVja2xhbmQxHjAcBgNV +BAoTFVNpbGx5IENpdHktQm95cyBDb3JwLjEdMBsGA1UECxMUSW50ZXJuYWwgY291 +bnNlbGxpbmcxFjAUBgNVBAMTDXR1bmFsYS1jbGllbnQxITAfBgkqhkiG9w0BCQEW +EmNsaWVudEBmYWtlLmRvbWFpbjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA +pbKO3gXR/in3RqZroOVBLPdVqFNa6DcaaCld/X6kQLXO4ERUnsb4mkC7RUFXzNyX +2WY+aJ0pkxX5K3WqSX/mz3+VRI5B7QWXHss/AzOwISuJZwjMe7Lv+ibH6iHyd1+9 +4mc2CuI97nZP0tPpuyLAuwzkooyqcTt1bEan0htX7vMCAwEAAaOCAUAwggE8MAkG +A1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRp +ZmljYXRlMB0GA1UdDgQWBBR0qIsfW1lVCcuYXC9Bh8qs1LUE/zCB4QYDVR0jBIHZ +MIHWgBRXWl3gcQsM4A9Rh94IyCXn94dGwKGBuqSBtzCBtDELMAkGA1UEBhMCTlox +EzARBgNVBAcTCldlbGxpbmd0b24xPDA6BgNVBAoTM1JlYWxseSBJcnJlc3BvbnNp +YmxlIEF1dGhvcmlzYXRpb24gQXV0aG9yaXR5IChSSUFBKTEWMBQGA1UECxMNQ2Vy +dC1zdGFtcGluZzEZMBcGA1UEAxMQSmFja292IGFsLVRyYWRlczEfMB0GCSqGSIb3 +DQEJARYQbm9uZUBmYWtlLmRvbWFpboIBADANBgkqhkiG9w0BAQQFAAOBgQBfNnR3 +HcdWcdMyMBKPTY4lkByzLuDBd3XqLKrvgsjghozf3OGGaIGRHk5WsV2Tb4AQgMPY +xDsPIN1DtfgJpLupBBHg1PnZgxkq2ny7TMJPV0MNGh4xYfskYpJ0EpxR7xI+I+RF +ZiusAGC/oP9D2pXDz2RA0peNwd0mzl+5oeqSMg== +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +MIICWwIBAAKBgQClso7eBdH+KfdGpmug5UEs91WoU1roNxpoKV39fqRAtc7gRFSe +xviaQLtFQVfM3JfZZj5onSmTFfkrdapJf+bPf5VEjkHtBZceyz8DM7AhK4lnCMx7 +su/6JsfqIfJ3X73iZzYK4j3udk/S0+m7IsC7DOSijKpxO3VsRqfSG1fu8wIDAQAB +AoGAUWBCHfQJz6NYl8//p8MvoR/PZ52YVddKFsHKMUbS8BzZ/vZQALKDQW5tCnQu +5KOpx9EY8VPOKThvaNKe0P4Joi+ozOm9UHABAQAL/dzk6NP4NG/GYoBdYDhRowbo +3mdxgbJ95INznK3WhGZNGnhd4umz0P67U2xyc5PklKqCGuECQQDcZQE0ZTi1hQ7Z +hStH5h0soyz9VQrx9wF5nfC64lKbh0f6k/pRJqanJ9EDE9od1tuxyWi0IGhOWGC0 +LPeB3S+LAkEAwHdptzi+c4hsGqoAEIuYvXah02LOYS2nCpcOssy3jwj8u6IWqiDf +KGt8J3S5u1afRIca9wgJiFME754FYdQrOQJACerNnBL1800Sdv1EDk8vfuO00Y1z +GaI4wcU2oOIwP2ld9suT1vT7SMhE4nORPAiACEb83CYdK3FUoKbpWEGgswJAe8aP ++yAIAz7x3vgDUKCmGvqHOe2qMf7tFTduYXicd+Vcu8KS9thrC5CMaMd9hsg/Zw/I +PKQzlTNm0j760R5kqQJAeO239gMrscKDFvsqSYr3UKf7uJxCetikhVZE1LH//WiM +Rl5jhu6fL9FgNWuyM0z8VTIgZAX6RwZdn1fb3mFYjw== +-----END RSA PRIVATE KEY----- diff --git a/demos/tunala/A-server.pem b/demos/tunala/A-server.pem new file mode 100644 index 0000000000..a35661b963 --- /dev/null +++ b/demos/tunala/A-server.pem @@ -0,0 +1,85 @@ +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: Nov 1 21:14:03 2000 GMT + Not After : Nov 1 21:14:03 2001 GMT + Subject: C=NZ, L=Wellington, O=The Stuff of Culture and Taste, 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:a7:07:a0:70:5e:76:4e:98:46:70:0e:53:e3:09: + f4:18:7b:c2:7e:8a:d9:3c:12:52:24:9f:bf:76:e1: + 0e:ca:99:c0:ed:fb:0f:7c:d1:1a:6d:9c:1f:e0:19: + 3a:65:a4:00:26:19:5b:5f:0e:6d:a2:b0:49:0c:28: + 40:c5:43:94:55:57:50:d4:28:8a:35:3c:73:f3:bb: + 5a:14:1f:ac:85:ba:b1:20:26:98:9a:92:94:96:fb: + 90:1d:c4:18:04:f5:7e:f1:21:d7:34:5c:6e:14:b6: + 9b:48:ac:85:c0:50:d9:cf:79:67:a8:9e:3f:80:6c: + ff:68:95:4c:52:95:c9:23:41 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + 9F:91:73:D0:8D:11:13:25:8B:68:2A:40:57:8D:96:B7:62:0B:6E:0E + X509v3 Authority Key Identifier: + keyid:57:5A:5D:E0:71:0B:0C:E0:0F:51:87:DE:08:C8:25:E7:F7:87:46:C0 + 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 + 27:c3:c3:d8:2e:b2:12:0c:b0:4c:bd:a4:d0:34:77:fe:13:6f: + 5e:8d:2c:50:c9:b5:a7:80:16:79:73:68:45:a1:5a:ed:74:d8: + 7c:92:f4:04:c0:6b:da:a5:ca:6d:03:2c:cc:f9:32:f9:fb:b9: + be:83:5a:4b:c5:54:1d:07:02:a4:78:c4:90:49:f6:bb:0f:32: + 57:86:ff:17:99:7a:a0:85:5f:ee:45:db:28:5f:91:66:d2:35: + 54:d7:c2:55:26:ff:ea:b7:3a:d0:3f:fd:6a:dd:26:35:3f:18: + 4e:c5:fa:36:d6:71:41:05:a0:4a:49:5d:b7:87:ee:6f:38:17: + 9a:4a +-----BEGIN CERTIFICATE----- +MIIEDTCCA3agAwIBAgIBAjANBgkqhkiG9w0BAQQFADCBtDELMAkGA1UEBhMCTlox +EzARBgNVBAcTCldlbGxpbmd0b24xPDA6BgNVBAoTM1JlYWxseSBJcnJlc3BvbnNp +YmxlIEF1dGhvcmlzYXRpb24gQXV0aG9yaXR5IChSSUFBKTEWMBQGA1UECxMNQ2Vy +dC1zdGFtcGluZzEZMBcGA1UEAxMQSmFja292IGFsLVRyYWRlczEfMB0GCSqGSIb3 +DQEJARYQbm9uZUBmYWtlLmRvbWFpbjAeFw0wMDExMDEyMTE0MDNaFw0wMTExMDEy +MTE0MDNaMIGfMQswCQYDVQQGEwJOWjETMBEGA1UEBxMKV2VsbGluZ3RvbjEnMCUG +A1UEChMeVGhlIFN0dWZmIG9mIEN1bHR1cmUgYW5kIFRhc3RlMRcwFQYDVQQLEw5T +U0wgZGV2IHRoaW5nczEWMBQGA1UEAxMNdHVuYWxhLXNlcnZlcjEhMB8GCSqGSIb3 +DQEJARYSc2VydmVyQGZha2UuZG9tYWluMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB +iQKBgQCnB6BwXnZOmEZwDlPjCfQYe8J+itk8ElIkn7924Q7KmcDt+w980RptnB/g +GTplpAAmGVtfDm2isEkMKEDFQ5RVV1DUKIo1PHPzu1oUH6yFurEgJpiakpSW+5Ad +xBgE9X7xIdc0XG4UtptIrIXAUNnPeWeonj+AbP9olUxSlckjQQIDAQABo4IBQDCC +ATwwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQg +Q2VydGlmaWNhdGUwHQYDVR0OBBYEFJ+Rc9CNERMli2gqQFeNlrdiC24OMIHhBgNV +HSMEgdkwgdaAFFdaXeBxCwzgD1GH3gjIJef3h0bAoYG6pIG3MIG0MQswCQYDVQQG +EwJOWjETMBEGA1UEBxMKV2VsbGluZ3RvbjE8MDoGA1UEChMzUmVhbGx5IElycmVz +cG9uc2libGUgQXV0aG9yaXNhdGlvbiBBdXRob3JpdHkgKFJJQUEpMRYwFAYDVQQL +Ew1DZXJ0LXN0YW1waW5nMRkwFwYDVQQDExBKYWNrb3YgYWwtVHJhZGVzMR8wHQYJ +KoZIhvcNAQkBFhBub25lQGZha2UuZG9tYWluggEAMA0GCSqGSIb3DQEBBAUAA4GB +ACfDw9gushIMsEy9pNA0d/4Tb16NLFDJtaeAFnlzaEWhWu102HyS9ATAa9qlym0D +LMz5Mvn7ub6DWkvFVB0HAqR4xJBJ9rsPMleG/xeZeqCFX+5F2yhfkWbSNVTXwlUm +/+q3OtA//WrdJjU/GE7F+jbWcUEFoEpJXbeH7m84F5pK +-----END CERTIFICATE----- + +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQCnB6BwXnZOmEZwDlPjCfQYe8J+itk8ElIkn7924Q7KmcDt+w98 +0RptnB/gGTplpAAmGVtfDm2isEkMKEDFQ5RVV1DUKIo1PHPzu1oUH6yFurEgJpia +kpSW+5AdxBgE9X7xIdc0XG4UtptIrIXAUNnPeWeonj+AbP9olUxSlckjQQIDAQAB +AoGAJPm/PqDqt8Nl9HB3iY8uhiz/hVvfczjrDkh+7iYsTBV1bDlj2FHB8/nX5Jgx +IUcI8WYzn/tlsdoskZBnpkOrlk0naOsgQk7Osh7Dn5sprRU0ieCgFhD/2DJNjJUE +ZfHrjXwr8LeG2CMa/FzkfkjDPC40gT8plbTOXmLECrjiEnECQQDaukSpJHX4JVtL +08j/mmKoBtBBVyzcSdxxHRXKBp+ivdszHC82oKH4yKwFdsfP6lX7iRsjKWIkdIiA +M9ZDF4TLAkEAw34aSYXWJttRr91HZ+aDXbxTnaaqdrwP1hUJM7dH/a1DQDoxV1vR +SWDX8YHSXgqPsxNtlW8bRtjh5cNWeZICowJAeS1A5MRCZxurHLNUY+dQSO6dadW2 +EMUKz8/hRm+s+ShdzE8NCSKtGXtzcgOAZ3vX7ubilfRTXwcAqKYPSlQ5SQJAFg2G +p56abt201FLw+C6PySYyhIlFl4lVe//5fsUBMQO3n2oxILqx3EY5dfwAIC2u0jOx +2/ahrBdRPFsRyTsIYwJBALAxKM5g7Qw0JgQ3gJnczY3/rpwlUhayYRYrNy1pJKp3 +hlVv+s5Oy1vXXppVfm830Eii7hsVp5PCFN+jRQhkFqw= +-----END RSA PRIVATE KEY----- diff --git a/demos/tunala/CA.pem b/demos/tunala/CA.pem new file mode 100644 index 0000000000..00d1e36290 --- /dev/null +++ b/demos/tunala/CA.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID9zCCA2CgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBtDELMAkGA1UEBhMCTlox +EzARBgNVBAcTCldlbGxpbmd0b24xPDA6BgNVBAoTM1JlYWxseSBJcnJlc3BvbnNp +YmxlIEF1dGhvcmlzYXRpb24gQXV0aG9yaXR5IChSSUFBKTEWMBQGA1UECxMNQ2Vy +dC1zdGFtcGluZzEZMBcGA1UEAxMQSmFja292IGFsLVRyYWRlczEfMB0GCSqGSIb3 +DQEJARYQbm9uZUBmYWtlLmRvbWFpbjAeFw0wMDExMDEyMTA3MDdaFw0wMTExMDEy +MTA3MDdaMIG0MQswCQYDVQQGEwJOWjETMBEGA1UEBxMKV2VsbGluZ3RvbjE8MDoG +A1UEChMzUmVhbGx5IElycmVzcG9uc2libGUgQXV0aG9yaXNhdGlvbiBBdXRob3Jp +dHkgKFJJQUEpMRYwFAYDVQQLEw1DZXJ0LXN0YW1waW5nMRkwFwYDVQQDExBKYWNr +b3YgYWwtVHJhZGVzMR8wHQYJKoZIhvcNAQkBFhBub25lQGZha2UuZG9tYWluMIGf +MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCj2aqRye4r8KZ0XKNC68elRVa5AHQY +Igd2K5OYkxACU+UkGzkPoYUz6Uq/kFjXa0lftCxMBvr3FoPb/MMVD+0LeFcJQza5 +dMfp3abLe7mttgU2fAQzC6OMetXvqVaBp/rlT0AE2DhzA4g+p51ivkG/pw2zDpra +nHaFsoRKg5puhQIDAQABo4IBFTCCAREwHQYDVR0OBBYEFFdaXeBxCwzgD1GH3gjI +Jef3h0bAMIHhBgNVHSMEgdkwgdaAFFdaXeBxCwzgD1GH3gjIJef3h0bAoYG6pIG3 +MIG0MQswCQYDVQQGEwJOWjETMBEGA1UEBxMKV2VsbGluZ3RvbjE8MDoGA1UEChMz +UmVhbGx5IElycmVzcG9uc2libGUgQXV0aG9yaXNhdGlvbiBBdXRob3JpdHkgKFJJ +QUEpMRYwFAYDVQQLEw1DZXJ0LXN0YW1waW5nMRkwFwYDVQQDExBKYWNrb3YgYWwt +VHJhZGVzMR8wHQYJKoZIhvcNAQkBFhBub25lQGZha2UuZG9tYWluggEAMAwGA1Ud +EwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEARuRhKpXa7K2HZEvoIWlLxF/ZrpfB +Zy2ixH25Uk8OnWm/NiS7eQAuR3aRWtEUsMENj1bC9I3hDk6zJVubp8TN0MPlvDvw +gOsMkGGSoumZRPh2aQadcmdBAHSMUMxNHGG0VdhXhodYZCF0H7z0gvKMPVTuIH5U +K2Iq6/aBOw9XbKM= +-----END CERTIFICATE----- diff --git a/demos/tunala/Makefile b/demos/tunala/Makefile new file mode 100644 index 0000000000..fd5b651bc7 --- /dev/null +++ b/demos/tunala/Makefile @@ -0,0 +1,40 @@ +# 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) +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 ip.c sm.c tunala.c +OBJS=buffer.o ip.o sm.o tunala.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 +ip.o: ip.c tunala.h +sm.o: sm.c tunala.h +tunala.o: tunala.c tunala.h diff --git a/demos/tunala/buffer.c b/demos/tunala/buffer.c new file mode 100644 index 0000000000..e9a4e5b030 --- /dev/null +++ b/demos/tunala/buffer.c @@ -0,0 +1,146 @@ +#include "tunala.h" + +#ifndef NO_BUFFER + +void buffer_init(buffer_t *buf) +{ + buf->used = 0; +} + +void buffer_close(buffer_t *buf) +{ + /* Our data is static - nothing needs "release", just reset */ + buffer_init(buf); +} + +/* 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 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; + return added; +} + +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; +} + +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; +} + +#ifndef NO_IP + +int buffer_from_fd(buffer_t *buf, int fd) +{ + unsigned 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; + return toread; +} + +int buffer_to_fd(buffer_t *buf, int fd) +{ + unsigned 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); + return towrite; +} + +#endif /* !defined(NO_IP) */ + +#ifndef NO_OPENSSL + +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; +} + +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); +} + +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; +} + +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); +} + +#endif /* !defined(NO_OPENSSL) */ + +#endif /* !defined(NO_BUFFER) */ diff --git a/demos/tunala/ip.c b/demos/tunala/ip.c new file mode 100644 index 0000000000..4874d620d5 --- /dev/null +++ b/demos/tunala/ip.c @@ -0,0 +1,147 @@ +#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 unsigned 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, &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 unsigned 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, &in_addr, sizeof(struct sockaddr_in)) != 0) && + (errno != EINPROGRESS)) + goto err; + return fd; +err: + if(fd != -1) + close(fd); + return -1; +} + +static unsigned char all_local_ip[] = {0x00,0x00,0x00,0x00}; + +int ip_parse_address(const char *address, unsigned char **parsed_ip, + unsigned short *parsed_port, int accept_all_ip) +{ + char buf[256]; + struct hostent *lookup; + unsigned long port; + char *temp; + const char *ptr = strstr(address, ":"); + unsigned 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; + port = strtoul(ptr, &temp, 10); + if((temp == ptr) || (*temp != '\0') || (port > 65535)) + return 0; + *parsed_ip = ip; + *parsed_port = (unsigned short)port; + return 1; +} + +int ip_create_listener(const char *address) +{ + unsigned 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) +{ + unsigned 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) */ + diff --git a/demos/tunala/sm.c b/demos/tunala/sm.c new file mode 100644 index 0000000000..05bd7b9459 --- /dev/null +++ b/demos/tunala/sm.c @@ -0,0 +1,149 @@ +#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; +} + +void 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. */ + 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; + /* 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); + } + 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; + } + if(SSL_get_shutdown(machine->ssl)) { + /* An SSL shutdown was underway */ + if(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 */ + 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) */ + diff --git a/demos/tunala/tunala.c b/demos/tunala/tunala.c new file mode 100644 index 0000000000..445940fabd --- /dev/null +++ b/demos/tunala/tunala.c @@ -0,0 +1,733 @@ +#if defined(NO_BUFFER) || defined(NO_IP) || defined(NO_OPENSSL) +#error "Badness, NO_BUFFER, NO_IP or NO_OPENSSL is defined, turn them *off*" +#endif + +/* Include our bits'n'pieces */ +#include "tunala.h" + + +/********************************************/ +/* Our local types that specify our "world" */ +/********************************************/ + +/* These represent running "tunnels". Eg. if you wanted to do SSL in a + * "message-passing" scanario, the "int" file-descriptors might be replaced by + * thread or process IDs, and the "select" code might be replaced by message + * handling code. Whatever. */ +typedef struct _tunala_item_t { + /* The underlying SSL state machine. This is a data-only processing unit + * and we communicate with it by talking to its four "buffers". */ + state_machine_t sm; + /* The file-descriptors for the "dirty" (encrypted) side of the SSL + * setup. In actuality, this is typically a socket and both values are + * identical. */ + int dirty_read, dirty_send; + /* The file-descriptors for the "clean" (unencrypted) side of the SSL + * setup. These could be stdin/stdout, a socket (both values the same), + * or whatever you like. */ + int clean_read, clean_send; +} tunala_item_t; + +/* This structure is used as the data for running the main loop. Namely, in a + * network format such as this, it is stuff for select() - but as pointed out, + * when moving the real-world to somewhere else, this might be replaced by + * something entirely different. It's basically the stuff that controls when + * it's time to do some "work". */ +typedef struct _select_sets_t { + int max; /* As required as the first argument to select() */ + fd_set reads, sends, excepts; /* As passed to select() */ +} select_sets_t; +typedef struct _tunala_selector_t { + select_sets_t last_selected; /* Results of the last select() */ + select_sets_t next_select; /* What we'll next select on */ +} tunala_selector_t; + +/* This structure is *everything*. We do it to avoid the use of globals so that, + * for example, it would be easier to shift things around between async-IO, + * thread-based, or multi-fork()ed (or combinations thereof). */ +typedef struct _tunala_world_t { + /* The file-descriptor we "listen" on for new connections */ + int listen_fd; + /* The array of tunnels */ + tunala_item_t *tunnels; + /* the number of tunnels in use and allocated, respectively */ + unsigned int tunnels_used, tunnels_size; + /* Our outside "loop" context stuff */ + tunala_selector_t selector; + /* Our SSL_CTX, which is configured as the SSL client or server and has + * the various cert-settings and callbacks configured. */ + SSL_CTX *ssl_ctx; + /* Simple flag with complex logic :-) Indicates whether we're an SSL + * server or an SSL client. */ + int server_mode; +} tunala_world_t; + +/*****************************/ +/* Internal static functions */ +/*****************************/ + +static SSL_CTX *initialise_ssl_ctx(int server_mode, const char *engine_id, + const char *CAfile, const char *cert, const char *key); +static void selector_init(tunala_selector_t *selector); +static void selector_add_listener(tunala_selector_t *selector, int fd); +static void selector_add_tunala(tunala_selector_t *selector, tunala_item_t *t); +static int selector_select(tunala_selector_t *selector); +/* This returns -1 for error, 0 for no new connections, or 1 for success, in + * which case *newfd is populated. */ +static int selector_get_listener(tunala_selector_t *selector, int fd, int *newfd); +static int tunala_world_new_item(tunala_world_t *world, int fd, + const unsigned char *ip, unsigned short port); +static void tunala_world_del_item(tunala_world_t *world, unsigned int idx); +static int tunala_item_io(tunala_selector_t *selector, tunala_item_t *item); + +/*********************************************/ +/* MAIN FUNCTION (and its utility functions) */ +/*********************************************/ + +/* For now, hard-coded as follows; + * (a) We're like "tunala -listen 127.0.0.1:9001 -proxy 127.0.0.1:9002" + * (b) We max out at 50 simultaneous tunnels, listening will stop while we have + * that many tunnels operating and will recommence as/when tunnels close. + * (c) We are an SSL client proxy + * (d) We use the "openssl" ENGINE + * (e) We use the CA cert file "cacert.pem" + * */ + +static const char *def_proxyhost = "127.0.0.1:443"; +static const char *def_listenhost = "127.0.0.1:8080"; +static int def_max_tunnels = 50; +static const char *def_cacert = NULL; +static const char *def_cert = NULL; +static const char *def_key = NULL; +static const char *def_engine_id = NULL; +static int def_server_mode = 0; + +static const char *helpstring = + "\n'Tunala' (A tunneler with a New Zealand accent)\n" + "Usage: tunala [options], where options are from;\n" + " -listen [host:]<port> (default = 127.0.0.1:8080)\n" + " -proxy <host>:<port> (default = 127.0.0.1:443)\n" + " -maxtunnels <num> (default = 50)\n" + " -cacert <path|NULL> (default = NULL)\n" + " -cert <path|NULL> (default = NULL)\n" + " -key <path|NULL> (default = whatever '-cert' is)\n" + " -engine <id|NULL> (default = NULL)\n" + " -server <0|1> (default = 0, ie. an SSL client)\n" + " -<h|help|?> (displays this help screen)\n" + "NB: It is recommended to specify a cert+key when operating as an\n" + "SSL server. If you only specify '-cert', the same file must\n" + "contain a matching private key.\n"; + +static int usage(const char *errstr, int isunknownarg) +{ + if(isunknownarg) + fprintf(stderr, "Error: unknown argument '%s'\n", errstr); + else + fprintf(stderr, "Error: %s\n", errstr); + fprintf(stderr, "%s\n", helpstring); + return 1; +} + +static int err_str0(const char *str0) +{ + fprintf(stderr, str0); + fprintf(stderr, "\n"); + return 1; +} + +static int err_str1(const char *str0, const char *str1) +{ + fprintf(stderr, str0, str1); + fprintf(stderr, "\n"); + return 1; +} + +static int parse_max_tunnels(const char *s, unsigned int *maxtunnels) +{ + unsigned long l; + char *temp; + l = strtoul(s, &temp, 10); + if((temp == s) || (*temp != '\0') || (l < 1) || (l > 1024)) { + fprintf(stderr, "Error, '%s' is an invalid value for " + "maxtunnels\n", s); + return 0; + } + *maxtunnels = (unsigned int)l; + return 1; +} + +static int parse_server_mode(const char *s, int *servermode) +{ + unsigned long l; + char *temp; + l = strtoul(s, &temp, 10); + if((temp == s) || (*temp != '\0') || (l > 1)) { + fprintf(stderr, "Error, '%s' is an invalid value for the " + "server mode\n", s); + return 0; + } + *servermode = (int)l; + return 1; +} + +int main(int argc, char *argv[]) +{ + unsigned int loop; + int newfd; + tunala_world_t world; + tunala_item_t *t_item; + unsigned char *proxy_ip; + unsigned short proxy_port; + /* Overridables */ + const char *proxyhost = def_proxyhost; + const char *listenhost = def_listenhost; + unsigned int max_tunnels = def_max_tunnels; + const char *cacert = def_cacert; + const char *cert = def_cert; + const char *key = def_key; + const char *engine_id = def_engine_id; + int server_mode = def_server_mode; + +/* Parse command-line arguments */ +next_arg: + argc--; argv++; + if(argc > 0) { + if(strcmp(*argv, "-listen") == 0) { + if(argc < 2) + return usage("-listen requires an argument", 0); + argc--; argv++; + listenhost = *argv; + goto next_arg; + } else if(strcmp(*argv, "-proxy") == 0) { + if(argc < 2) + return usage("-proxy requires an |