// Copyright (c) 2016 Sandstorm Development Group, Inc. and contributors // Licensed under the MIT License: // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. #if KJ_HAS_OPENSSL #include "tls.h" #include <kj/test.h> #include <kj/async-io.h> #include <stdlib.h> namespace kj { namespace { // ======================================================================================= // test data // // made with make-test-certs.sh static constexpr char CA_CERT[] = "-----BEGIN CERTIFICATE-----\n" "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\n" "-----END CERTIFICATE-----\n"; static constexpr char INTERMEDIATE_CERT[] = "-----BEGIN CERTIFICATE-----\n" "MIIGDjCCA/agAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgacxCzAJBgNVBAYTAlVT\n" "MRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlQYWxvIEFsdG8xFTATBgNV\n" "BAoMDFNhbmRzdG9ybS5pbzEbMBkGA1UECwwSVGVzdGluZyBEZXBhcnRtZW50MRcw\n" "FQYDVQQDDA5jYS5leGFtcGxlLmNvbTEiMCAGCSqGSIb3DQEJARYTZ2FycGx5QHNh\n" "bmRzdG9ybS5pbzAgFw0xNjA1MzEwNDI4NDZaGA8yMTE2MDUwNzA0Mjg0NlowgZcx\n" "CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRUwEwYDVQQKDAxTYW5k\n" "c3Rvcm0uaW8xGzAZBgNVBAsMElRlc3RpbmcgRGVwYXJ0bWVudDEbMBkGA1UEAwwS\n" "aW50LWNhLmV4YW1wbGUuY29tMSIwIAYJKoZIhvcNAQkBFhNnYXJwbHlAc2FuZHN0\n" "b3JtLmlvMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtqWYNn5PO7cG\n" "gyFzFX3q4QUQuKX+mzHjf560nOiF0Hon4SnZHnJqfGTSPBiEtqsaYLLf4dmO2SkR\n" "w65MRKy8A6/441NhmCv8OamepOJWB71jlGVuLIoUwYgvT0R529r+Kzdq2xcnSgOo\n" "O54SB4d8sSALAfOMKky+EOqcQq7VC+JZtel8LEJUpfvicHZtwS64D4IetsaGuAPz\n" "KCZ3QTWMZr+FPzvmTJnxmrVwHU/whT8ma8rFljZ3oQiawIzeb/hQ4OjGdjt/H3TZ\n" "A5rWL5s3t6RbR/MhLkajH4Fpw1qQUt5aHm54czLnHBQ9yz4dP/oWxZ8GBWT9PV63\n" "CW34Irb6Zb5bmfYpaDtd0XsGACYCmLwDxBH2G5UZ6Z5nazjOHAQcYb6f4kjYVuoG\n" "PvD5pjsZ7pcZr//gb4+SsVgMQDC1jRNoJPS9G3Wz42msR9IAqFaSUuay6viTPQqf\n" "mQGOMPzJFbxnje0U483YotL+DhqtV5zFxx1l1nNJL7/5AdSPBRCvriLzIxblemBq\n" "5JdlkKcqWq/QJtvrzHnlixVCKA1mHaWUB7zv7Np0KzeHWZ6sIcBlR7No0boW4Xmm\n" "S4F9sTIfh+4f6qhXnjq3G4yIXhggHIWOutFAgupMQv5oNZYDjqzBhDIfWXK/8V9P\n" "/3ubm34tOsNcWwpxxiEc5dkQAvLmFycCAwEAAaNQME4wHQYDVR0OBBYEFMvpWUv7\n" "zweivFl4A6ZykYOe9hogMB8GA1UdIwQYMBaAFNIcrdRyL5MclnpDhYZuBnZ2X7Lx\n" "MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAFyOD1Zti+4awHLMYDwn\n" "s6YMSKDNnG1GjpNVjkOPZ2BOAbg18fcsNmy69R4S4rfRQMIEZPNSXh092v4BKUmc\n" "Afa4ahEZmDET4plRWWpWUC8j8/ESIv2372QG2Q00TNWmhPiUKd8VMwV4HFcHml/+\n" "99BrTNn68s8zMB5BNiJgWTxFIRPLy12FWjr0OriVp1EaPOstkYNxfl4RdBgTXCJ8\n" "A9XRBNc25JHPNGPVqiRmCpewsSzEmP2sdz1MGspX7xiaE0UWnCyMPOmX90+dZlSI\n" "GHoBI6iNL894pzKiGvl4dZ2cwKhMncXqvbx9v+IDGSXrC6bsZNl42wee8D7axsKE\n" "xGNQKcGpU8EQqt6YC2wFV+wAHIlYuH90yk1LAZrehKy0E7N/ToKBz7MgGtoQLbn6\n" "UuHZto/LthCY6A8ppgqrq1JEbuLoqskRuOCIF6qXjPTsNhsBXCU/xnkae74QO+2r\n" "adrOubDvIjNtaHBuDgAeVl6PIP4mcJUMF3KhdVg/EDXWVq34YSEF+G/hR/Cj8GKl\n" "DIGGtcQ2re+uPAoPnQ+II9iJcDeY+1wpo9HK4VL54ERzXd53Vl357mNuA/69Fjh3\n" "HRzI5ELdyzWOEFCteCWyPtlOCZJ3Uuj9umS9K/B7KM1XmRzTOYvvj7aTaT4DhoO6\n" "VfvEtl+RmGSm/YmfTJ8551Zq\n" "-----END CERTIFICATE-----\n"; static constexpr char HOST_KEY[] = "-----BEGIN RSA PRIVATE KEY-----\n" "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\n" "-----END RSA PRIVATE KEY-----\n"; static constexpr char VALID_CERT[] = "-----BEGIN CERTIFICATE-----\n" "MIIF9zCCA9+gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgZcxCzAJBgNVBAYTAlVT\n" "MRMwEQYDVQQIDApDYWxpZm9ybmlhMRUwEwYDVQQKDAxTYW5kc3Rvcm0uaW8xGzAZ\n" "BgNVBAsMElRlc3RpbmcgRGVwYXJ0bWVudDEbMBkGA1UEAwwSaW50LWNhLmV4YW1w\n" "bGUuY29tMSIwIAYJKoZIhvcNAQkBFhNnYXJwbHlAc2FuZHN0b3JtLmlvMCAXDTE2\n" "MDUzMTA0Mjg0N1oYDzIxMTYwNTMxMDQyODQ3WjCBkDELMAkGA1UEBhMCVVMxEzAR\n" "BgNVBAgMCkNhbGlmb3JuaWExFTATBgNVBAoMDFNhbmRzdG9ybS5pbzEbMBkGA1UE\n" "CwwSVGVzdGluZyBEZXBhcnRtZW50MRQwEgYDVQQDDAtleGFtcGxlLmNvbTEiMCAG\n" "CSqGSIb3DQEJARYTZ2FycGx5QHNhbmRzdG9ybS5pbzCCAiIwDQYJKoZIhvcNAQEB\n" "BQADggIPADCCAgoCggIBANsHStqtDiv+hz3eunDuTrcY/207sgCEbdObcpANvLVz\n" "jSc67B9aemMqa/yT8BmHkgTock1DSkEOOmEnsvszkzt1R9tf66XXhAJglYMv3I7S\n" "WqMmAFbkn+vuTXB6Yf6D1/cEalQG9wY6Y0Aci6+BLynYStkvq9ACXDdW3j1iUiKU\n" "LptBIJsc9c9jlkEV9Pt8lfLWULZNYiSr5jyNSTRSKkLIEDMUIAUEsrEYHxasMioA\n" "4BB6FGKhL1Ns2XjkNaJ80TS8X95rHmc/SRrGk2qmI7OL7DkimEE+VHGvre6tO2dm\n" "xX/e5CkyXVVeDbV8sm4Vl8b5tafjEqEkqU4OO6DeAFRh++T7rJo52oI1pTu60wGY\n" "de0IgDkVxoBpWEalQmCjzHWoXoRI+3LqTZ+eZsR+GGqJha8Iz2sl2v9U7F8z9e2+\n" "Wk0jDcntKujcDjCFBjgMp/MExFEkgwxKwuJ4oUR8Rm95BU6KtXagiPUnPS9R2Oe0\n" "qfLaSuQkA9Rt6ac4cGdv15/OIqUK4qILFeQC28bpAu1hmY04AWobDGQah1rViLjl\n" "IwCq/1/46aDYAaZE+lS6qcfS+049c47xcC7BNGAEKt+5cdkmpv/gkswNwRw7Mehj\n" "UqbUSimLz0iGAxcSVL3/yh4PJiP4J6mtBIByb0zwTku4KNRuDoT/SFII1qKFzITz\n" "AgMBAAGjUDBOMB0GA1UdDgQWBBT2qSSBGCUEYfohpsiHlq9yECjAqDAfBgNVHSME\n" "GDAWgBTL6VlL+88HorxZeAOmcpGDnvYaIDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3\n" "DQEBCwUAA4ICAQCb34A5Hz6iI80U+mSnkvOnVtaqyxnsVcBbfMcsRyGG/GSVBNJD\n" "zcCxnxrPc0NXcsK3wIR7KU1oQmusNCtI2XNd1lceBytQD6TDzcuuNCpjF7Uh+pdi\n" "AL2HzDoy9q4Mxxk1wTGDuyy+4opZQG12fe9pr4wo93/BXbE4kDrSzp/2iTQp9/zh\n" "JRrRISwyFH6HKX/MoVbpJfAqiMHXHeHylH6h4lUVVfYFSSB8PWL3lxAwCM0ECGmd\n" "ZMGyh089ViW0mBoF5lacwHkAnw17S0JrUM9+66oPRLIo2rsgnNj4sMo/9dzSJ9/T\n" "OneewTK4O8t/mZNp1auYFC1+m8wWRh0G5Y5CwZ1CJqy8mHMd/33FbMO+MyyEeFkG\n" "DHNzCYEupp1ymqvFZK8TyIX1m/QOy0W6NT6INFY1dy3CoJWnMAJRKvxeFQGJ28Up\n" "wYPZPj7xxGb6TdgVC0c7kMCorIu3tsLLRtwtAbN/D8ogS78QwgyLqJ41friFMD+9\n" "AS1sjfqiiC4hpr11z+xdCJLb4vkBsigHuofjx3uyiueyKXQTFQCXjF2w1FbJTKSZ\n" "kQ4CP2eG8UN5BN46kih89NjBUCduXq/x4SJCEjtG57QFBogmcG/OTX1pCOwjnK4L\n" "z6Kz4+2VTNYHvIXSIoicO+jZeISYpllg6ISNBeqoOp2zp6Rf6rwR6/YZog==\n" "-----END CERTIFICATE-----\n"; static constexpr char EXPIRED_CERT[] = "-----BEGIN CERTIFICATE-----\n" "MIIF9TCCA92gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwgZcxCzAJBgNVBAYTAlVT\n" "MRMwEQYDVQQIDApDYWxpZm9ybmlhMRUwEwYDVQQKDAxTYW5kc3Rvcm0uaW8xGzAZ\n" "BgNVBAsMElRlc3RpbmcgRGVwYXJ0bWVudDEbMBkGA1UEAwwSaW50LWNhLmV4YW1w\n" "bGUuY29tMSIwIAYJKoZIhvcNAQkBFhNnYXJwbHlAc2FuZHN0b3JtLmlvMB4XDTE2\n" "MDEwMTAwMDAwMFoXDTE2MDEwMTAwMDAwMFowgZAxCzAJBgNVBAYTAlVTMRMwEQYD\n" "VQQIDApDYWxpZm9ybmlhMRUwEwYDVQQKDAxTYW5kc3Rvcm0uaW8xGzAZBgNVBAsM\n" "ElRlc3RpbmcgRGVwYXJ0bWVudDEUMBIGA1UEAwwLZXhhbXBsZS5jb20xIjAgBgkq\n" "hkiG9w0BCQEWE2dhcnBseUBzYW5kc3Rvcm0uaW8wggIiMA0GCSqGSIb3DQEBAQUA\n" "A4ICDwAwggIKAoICAQDbB0rarQ4r/oc93rpw7k63GP9tO7IAhG3Tm3KQDby1c40n\n" "OuwfWnpjKmv8k/AZh5IE6HJNQ0pBDjphJ7L7M5M7dUfbX+ul14QCYJWDL9yO0lqj\n" "JgBW5J/r7k1wemH+g9f3BGpUBvcGOmNAHIuvgS8p2ErZL6vQAlw3Vt49YlIilC6b\n" "QSCbHPXPY5ZBFfT7fJXy1lC2TWIkq+Y8jUk0UipCyBAzFCAFBLKxGB8WrDIqAOAQ\n" "ehRioS9TbNl45DWifNE0vF/eax5nP0kaxpNqpiOzi+w5IphBPlRxr63urTtnZsV/\n" "3uQpMl1VXg21fLJuFZfG+bWn4xKhJKlODjug3gBUYfvk+6yaOdqCNaU7utMBmHXt\n" "CIA5FcaAaVhGpUJgo8x1qF6ESPty6k2fnmbEfhhqiYWvCM9rJdr/VOxfM/XtvlpN\n" "Iw3J7Sro3A4whQY4DKfzBMRRJIMMSsLieKFEfEZveQVOirV2oIj1Jz0vUdjntKny\n" "2krkJAPUbemnOHBnb9efziKlCuKiCxXkAtvG6QLtYZmNOAFqGwxkGoda1Yi45SMA\n" "qv9f+Omg2AGmRPpUuqnH0vtOPXOO8XAuwTRgBCrfuXHZJqb/4JLMDcEcOzHoY1Km\n" "1Eopi89IhgMXElS9/8oeDyYj+CeprQSAcm9M8E5LuCjUbg6E/0hSCNaihcyE8wID\n" "AQABo1AwTjAdBgNVHQ4EFgQU9qkkgRglBGH6IabIh5avchAowKgwHwYDVR0jBBgw\n" "FoAUy+lZS/vPB6K8WXgDpnKRg572GiAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B\n" "AQsFAAOCAgEAtIjwUBNVrc62XK36bHHFLawYJaJUNj4zwdBUmVc5BL0tPHfDIwhP\n" "GBbxZCrAbPlHUkWig6l52S2lG0Aq2rtBwZPrjSJMio4ln/3y9qZjdqCjKtiQy7lc\n" "jQu9wXzlcTomARt2NcgTMedOrC4+eXMExUZ+n7xHKsj9u6sYeH0LXtMfg0Xzloc7\n" "ojF+ISM3bZbZQzGNkG+Fz1OCGgJ6W/wHxAadIHMmOMl1YN9ZRbO7T93AlMSGpehi\n" "LYh/n8B769yyxlfMWIM/aGECZdLyE5NUeN2r0jfjSkgp9l9dXr5fJL7bA54YcQC4\n" "dWjuMf8tpPpI1580fU5xD0ta6NGeLkQ5lEUexIaH0vSmUDs0N9HpTooGFcONl75R\n" "sEaB7/xH/ZGjtRXTc/QAPyfzFvbQNgRSoiif7DHRt7Wv13fKt/xL9uZlTGZUfojt\n" "eIFe82dNIffpoXkkHGFlpxxgnpwMb62N7BFqi2uJrSasrNEYZuEKTQMb1p76qojp\n" "6zAUPaut+FHgM5zVaKkvdXvJEReHG7un2a/DfZelIa8VIWO4BGQJBhSaKbRiGXiu\n" "2BbV3/qp9R0msirfyesBa/NV1syw2PYoouYukSdMfROK4r2FGPN7cw0AYrY3NbGG\n" "5jFKu2Vr1krHysnmFyXhkoyVSy4dYjrrqa1ItZW9SF0f83IN54C/P7E=\n" "-----END CERTIFICATE-----\n"; static constexpr char SELF_SIGNED_CERT[] = "-----BEGIN CERTIFICATE-----\n" "MIIGHzCCBAegAwIBAgIJAN7Q46+wlXJHMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYD\n" "VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJUGFsbyBBbHRv\n" "MRUwEwYDVQQKDAxTYW5kc3Rvcm0uaW8xGzAZBgNVBAsMElRlc3RpbmcgRGVwYXJ0\n" "bWVudDEUMBIGA1UEAwwLZXhhbXBsZS5jb20xIjAgBgkqhkiG9w0BCQEWE2dhcnBs\n" "eUBzYW5kc3Rvcm0uaW8wIBcNMTYwNTMxMDQyODQ3WhgPMjExNjA1MzEwNDI4NDda\n" "MIGkMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJ\n" "UGFsbyBBbHRvMRUwEwYDVQQKDAxTYW5kc3Rvcm0uaW8xGzAZBgNVBAsMElRlc3Rp\n" "bmcgRGVwYXJ0bWVudDEUMBIGA1UEAwwLZXhhbXBsZS5jb20xIjAgBgkqhkiG9w0B\n" "CQEWE2dhcnBseUBzYW5kc3Rvcm0uaW8wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw\n" "ggIKAoICAQDbB0rarQ4r/oc93rpw7k63GP9tO7IAhG3Tm3KQDby1c40nOuwfWnpj\n" "Kmv8k/AZh5IE6HJNQ0pBDjphJ7L7M5M7dUfbX+ul14QCYJWDL9yO0lqjJgBW5J/r\n" "7k1wemH+g9f3BGpUBvcGOmNAHIuvgS8p2ErZL6vQAlw3Vt49YlIilC6bQSCbHPXP\n" "Y5ZBFfT7fJXy1lC2TWIkq+Y8jUk0UipCyBAzFCAFBLKxGB8WrDIqAOAQehRioS9T\n" "bNl45DWifNE0vF/eax5nP0kaxpNqpiOzi+w5IphBPlRxr63urTtnZsV/3uQpMl1V\n" "Xg21fLJuFZfG+bWn4xKhJKlODjug3gBUYfvk+6yaOdqCNaU7utMBmHXtCIA5FcaA\n" "aVhGpUJgo8x1qF6ESPty6k2fnmbEfhhqiYWvCM9rJdr/VOxfM/XtvlpNIw3J7Sro\n" "3A4whQY4DKfzBMRRJIMMSsLieKFEfEZveQVOirV2oIj1Jz0vUdjntKny2krkJAPU\n" "bemnOHBnb9efziKlCuKiCxXkAtvG6QLtYZmNOAFqGwxkGoda1Yi45SMAqv9f+Omg\n" "2AGmRPpUuqnH0vtOPXOO8XAuwTRgBCrfuXHZJqb/4JLMDcEcOzHoY1Km1Eopi89I\n" "hgMXElS9/8oeDyYj+CeprQSAcm9M8E5LuCjUbg6E/0hSCNaihcyE8wIDAQABo1Aw\n" "TjAdBgNVHQ4EFgQU9qkkgRglBGH6IabIh5avchAowKgwHwYDVR0jBBgwFoAU9qkk\n" "gRglBGH6IabIh5avchAowKgwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC\n" "AgEA0dYsDTtt75fqQ35+ZHZGFCzJ4eUM4m/IdXfMlVw5Eb+2XA7pAVQgHhUD2qU0\n" "6Xk5EqINr7X8TvvR3OGVzlAw7BD4ZVKXkNy82BwRoydSUN9GM+Q1yqHES8+dBH5D\n" "jdrBq5XdtG3cQEjxxHPb5iWc5MLvVM0UtuuBtk3rp9IoY3+ReczGbm8CXep7jyIv\n" "W0wTi8gjMPWqn/f4ikkprMh0hXCwRTojfWi+Gl1sKyzviG+FF3hJj/fNf7IKYG8d\n" "lO/Ay9wqY+j7oMIz6RUUOht31tLnTaSSDDknuHF+r0GJoNWjsncf/NseGDLBiTkZ\n" "bBGMJhB3Pd6FNcLuREtE1WT5EwJr9WZeSh1mQPssQvwgYjdCI558sw1WEBdON73M\n" "0/aZzc/gDx9G1zxUxzn85/pxpBeQgb+J8iaAz1Iy9Gn64A6rVbQWAb5/xZ4y1LSe\n" "xTFVcK9spSf3k2FX24DPOov3oLu7vGmgye76bD4I0WtcVFFK5vXsfXGHq+P8EXv5\n" "F2KmlitfAh6N+uSeWzROrwU7roYsg81epvXVTYR/MyXNEB46iRMNdOqWThpdteEk\n" "qts6SreMmr0+aX7oqJ52Ohtw437JvxMqd5PNHuU3qQQS2o7cJzlZ+dDQMoZdxNaV\n" "bWPnPRk8plkBJLuQZA7KcTGA3b6qHl0hMTDJUE8bscNmMs4=\n" "-----END CERTIFICATE-----\n"; // ======================================================================================= class ErrorNexus { // Helper class that wraps various promises such that if one throws an exception, they all do. public: ErrorNexus(): ErrorNexus(kj::newPromiseAndFulfiller<void>()) {} template <typename T> kj::Promise<T> wrap(kj::Promise<T>&& promise) { return promise.catch_([this](kj::Exception&& e) -> kj::Promise<T> { fulfiller->reject(kj::cp(e)); return kj::mv(e); }).exclusiveJoin(failurePromise.addBranch().then([]() -> T { KJ_UNREACHABLE; })); } private: kj::ForkedPromise<void> failurePromise; kj::Own<kj::PromiseFulfiller<void>> fulfiller; ErrorNexus(kj::PromiseFulfillerPair<void> paf) : failurePromise(kj::mv(paf.promise).fork()), fulfiller(kj::mv(paf.fulfiller)) {} }; struct TlsTest { kj::AsyncIoContext io = setupAsyncIo(); TlsContext tlsClient; TlsContext tlsServer; TlsTest(TlsContext::Options clientOpts = defaultClient(), TlsContext::Options serverOpts = defaultServer()) : tlsClient(kj::mv(clientOpts)), tlsServer(kj::mv(serverOpts)) {} static TlsContext::Options defaultServer() { static TlsKeypair keypair = { TlsPrivateKey(HOST_KEY), TlsCertificate(kj::str(VALID_CERT, INTERMEDIATE_CERT)) }; TlsContext::Options options; options.defaultKeypair = keypair; return options; } static TlsContext::Options defaultClient() { static TlsCertificate caCert(CA_CERT); TlsContext::Options options; options.useSystemTrustStore = false; options.trustedCertificates = kj::arrayPtr(&caCert, 1); return options; } }; KJ_TEST("TLS basics") { TlsTest test; ErrorNexus e; auto pipe = test.io.provider->newTwoWayPipe(); auto clientPromise = e.wrap(test.tlsClient.wrapClient(kj::mv(pipe.ends[0]), "example.com")); auto serverPromise = e.wrap(test.tlsServer.wrapServer(kj::mv(pipe.ends[1]))); auto client = clientPromise.wait(test.io.waitScope); auto server = serverPromise.wait(test.io.waitScope); auto writePromise = client->write("foo", 3); char buf[4]; server->read(&buf, 3).wait(test.io.waitScope); buf[3] = '\0'; KJ_ASSERT(kj::StringPtr(buf) == "foo"); } class TestSniCallback: public TlsSniCallback { public: kj::Maybe<TlsKeypair> getKey(kj::StringPtr hostname) override { ++callCount; KJ_ASSERT(hostname == "example.com"); return TlsKeypair { TlsPrivateKey(HOST_KEY), TlsCertificate(kj::str(VALID_CERT, INTERMEDIATE_CERT)) }; } uint callCount = 0; }; KJ_TEST("TLS SNI") { TlsContext::Options serverOptions; TestSniCallback callback; serverOptions.sniCallback = callback; TlsTest test(TlsTest::defaultClient(), serverOptions); ErrorNexus e; auto pipe = test.io.provider->newTwoWayPipe(); auto clientPromise = e.wrap(test.tlsClient.wrapClient(kj::mv(pipe.ends[0]), "example.com")); auto serverPromise = e.wrap(test.tlsServer.wrapServer(kj::mv(pipe.ends[1]))); auto client = clientPromise.wait(test.io.waitScope); auto server = serverPromise.wait(test.io.waitScope); auto writePromise = client->write("foo", 3); char buf[4]; server->read(&buf, 3).wait(test.io.waitScope); buf[3] = '\0'; KJ_ASSERT(kj::StringPtr(buf) == "foo"); KJ_ASSERT(callback.callCount == 1); } void expectInvalidCert(kj::StringPtr hostname, TlsCertificate cert, kj::StringPtr message) { TlsKeypair keypair = { TlsPrivateKey(HOST_KEY), kj::mv(cert) }; TlsContext::Options serverOpts; serverOpts.defaultKeypair = keypair; TlsTest test(TlsTest::defaultClient(), kj::mv(serverOpts)); ErrorNexus e; auto pipe = test.io.provider->newTwoWayPipe(); auto clientPromise = e.wrap(test.tlsClient.wrapClient(kj::mv(pipe.ends[0]), hostname)); auto serverPromise = e.wrap(test.tlsServer.wrapServer(kj::mv(pipe.ends[1]))); KJ_EXPECT_THROW_MESSAGE(message, clientPromise.wait(test.io.waitScope)); } KJ_TEST("TLS certificate validation") { expectInvalidCert("wrong.com", TlsCertificate(kj::str(VALID_CERT, INTERMEDIATE_CERT)), "Hostname mismatch"); expectInvalidCert("example.com", TlsCertificate(VALID_CERT), "unable to get local issuer certificate"); expectInvalidCert("example.com", TlsCertificate(kj::str(EXPIRED_CERT, INTERMEDIATE_CERT)), "certificate has expired"); expectInvalidCert("example.com", TlsCertificate(SELF_SIGNED_CERT), "self signed certificate"); } KJ_TEST("TLS client certificate verification") { TlsContext::Options serverOptions = TlsTest::defaultServer(); TlsContext::Options clientOptions = TlsTest::defaultClient(); serverOptions.verifyClients = true; serverOptions.trustedCertificates = clientOptions.trustedCertificates; // No certificate loaded in the client: fail { TlsTest test(clientOptions, serverOptions); auto pipe = test.io.provider->newTwoWayPipe(); auto clientPromise = test.tlsClient.wrapClient(kj::mv(pipe.ends[0]), "example.com"); auto serverPromise = test.tlsServer.wrapServer(kj::mv(pipe.ends[1])); KJ_EXPECT_THROW_MESSAGE("peer did not return a certificate", serverPromise.wait(test.io.waitScope)); KJ_EXPECT_THROW_MESSAGE("alert handshake failure", clientPromise.wait(test.io.waitScope)); } // Self-signed certificate loaded in the client: fail { TlsKeypair selfSignedKeypair = { TlsPrivateKey(HOST_KEY), TlsCertificate(SELF_SIGNED_CERT) }; clientOptions.defaultKeypair = selfSignedKeypair; TlsTest test(clientOptions, serverOptions); auto pipe = test.io.provider->newTwoWayPipe(); auto clientPromise = test.tlsClient.wrapClient(kj::mv(pipe.ends[0]), "example.com"); auto serverPromise = test.tlsServer.wrapServer(kj::mv(pipe.ends[1])); KJ_EXPECT_THROW_MESSAGE("certificate verify failed", serverPromise.wait(test.io.waitScope)); KJ_EXPECT_THROW_MESSAGE("alert unknown ca", clientPromise.wait(test.io.waitScope)); } // Trusted certificate loaded in the client: success. { clientOptions.defaultKeypair = serverOptions.defaultKeypair; TlsTest test(clientOptions, serverOptions); ErrorNexus e; auto pipe = test.io.provider->newTwoWayPipe(); auto clientPromise = e.wrap(test.tlsClient.wrapClient(kj::mv(pipe.ends[0]), "example.com")); auto serverPromise = e.wrap(test.tlsServer.wrapServer(kj::mv(pipe.ends[1]))); auto client = clientPromise.wait(test.io.waitScope); auto server = serverPromise.wait(test.io.waitScope); auto writePromise = client->write("foo", 3); char buf[4]; server->read(&buf, 3).wait(test.io.waitScope); buf[3] = '\0'; KJ_ASSERT(kj::StringPtr(buf) == "foo"); } } #ifdef KJ_EXTERNAL_TESTS KJ_TEST("TLS to capnproto.org") { kj::AsyncIoContext io = setupAsyncIo(); TlsContext tls; auto network = tls.wrapNetwork(io.provider->getNetwork()); auto addr = network->parseAddress("capnproto.org", 443).wait(io.waitScope); auto stream = addr->connect().wait(io.waitScope); kj::StringPtr request = "HEAD / HTTP/1.1\r\n" "Host: capnproto.org\r\n" "Connection: close\r\n" "User-Agent: capnp-test/0.6\r\n" "\r\n"; stream->write(request.begin(), request.size()).wait(io.waitScope); char buffer[4096]; size_t n = stream->tryRead(buffer, sizeof(buffer) - 1, sizeof(buffer) - 1).wait(io.waitScope); buffer[n] = '\0'; kj::StringPtr response(buffer, n); KJ_ASSERT(response.startsWith("HTTP/1.1 200 OK\r\n")); } #endif } // namespace } // namespace kj #endif // KJ_HAS_OPENSSL