From 861044a44a5d01b30c9ff34e21bb47324e484bb6 Mon Sep 17 00:00:00 2001 From: Hristo Venev Date: Fri, 6 May 2022 02:18:03 +0300 Subject: Initial commit? --- .gitignore | 1 + cacerts.pem | 333 ++++++++++++++++++++++++++++++++++++++ rebiss.py | 522 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ run.sh | 2 + ssl.key | 28 ++++ ssl.pem | 40 +++++ 6 files changed, 926 insertions(+) create mode 100644 .gitignore create mode 100644 cacerts.pem create mode 100644 rebiss.py create mode 100755 run.sh create mode 100644 ssl.key create mode 100644 ssl.pem diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bee8a64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/cacerts.pem b/cacerts.pem new file mode 100644 index 0000000..16de510 --- /dev/null +++ b/cacerts.pem @@ -0,0 +1,333 @@ +-----BEGIN CERTIFICATE----- +MIIHYTCCBUmgAwIBAgIIVWzBnzXxlcowDQYJKoZIhvcNAQELBQAwcDELMAkGA1UE +BhMCQkcxGDAWBgNVBGETD05UUkJHLTIwMTIzMDQyNjESMBAGA1UEChMJQk9SSUNB +IEFEMRAwDgYDVQQLEwdCLVRydXN0MSEwHwYDVQQDExhCLVRydXN0IFJvb3QgQWR2 +YW5jZWQgQ0EwHhcNMTgwNjAxMTMyOTM0WhcNMzMwNTMxMTMyOTM0WjB3MQswCQYD +VQQGEwJCRzEYMBYGA1UEYRMPTlRSQkctMjAxMjMwNDI2MRIwEAYDVQQKEwlCT1JJ +Q0EgQUQxEDAOBgNVBAsTB0ItVHJ1c3QxKDAmBgNVBAMTH0ItVHJ1c3QgT3BlcmF0 +aW9uYWwgQWR2YW5jZWQgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQC4X1C5+lc6L831DczO5X8lbZhJZReYpt4CsQvvomIcs+cR+gBnO8ZBxPAhe5TG +DKbEAbULe8S6UtGdhq3QG80wBuAgSF6fV4qeq/s4af7idG3HmIIClVwtphuu0EoY +sGSnXz6td+h/vEUE06tZ7KICM/oXju1n6BhIZlH2TuhfwCwgU8VILORWp74gA87S +LSIXmTqM/rsa+Cqk1cB6k4dCCdkyvKAaQA5IMV3yARDLk2tYdy6G7oOq4GTyHcL2 +2/VnHrA481OwDJ68HnwcfYXzVoVA8tSnZ2lM7cW8xdVCd4s36A7vKuiPm4UtxXeV +/sC9MQgI+r6yinQDsGSLAEpPpd+09JrgvqY9R8JsBHQmNPsSjcI50MXsnhaWobz1 +ga/ys4N/Wn+4n7HrWkFjP6x653DhtiFGWBMXcB8t3gX0EKqxLblxobEn12pEkoQD +BpcoXbpZ25wXvCEuRAhHO/+YuXDWGaj2oZ/6hTADTgd9UEs9UXlGBBRg8oZbcjDg +Ap/scpVtnGyYTgLBQn7HlXwoDtjyzrtWrr4DpSVRtJ0YVYVWm15a8R338eegZwUt +RZ2+30iBR8BDZlZ8XJE6xqgdyzMs9W4A+UJjgysI9CDxNFXfoDdYlK/PHCsB/B4R +hkIdelRQ6mlV1r0AlBPrYxRm5bIrYJP7kLj77jbvmyzcoQIDAIi3o4IB9jCCAfIw +HQYDVR0OBBYEFAfcqjB2mLeFS20DGMjjzad7NoLvMB8GA1UdIwQYMBaAFIjbQu2J +BTIMcicMRhvhxgle7MkhMCEGA1UdEgQaMBiGFmh0dHA6Ly93d3cuYi10cnVzdC5v +cmcwEgYDVR0TAQH/BAgwBgEB/wIBADCBpwYDVR0gBIGfMIGcMEAGCisGAQQB+3YB +BwEwMjAwBggrBgEFBQcCARYkaHR0cDovL3d3dy5iLXRydXN0Lm9yZy9kb2N1bWVu +dHMvY3BzMA0GCysGAQQB+3YBBwEBMA0GCysGAQQB+3YBBwECMA0GCysGAQQB+3YB +BwEDMA0GCysGAQQB+3YBBwEEMA0GCysGAQQB+3YBBwEFMA0GCysGAQQB+3YBBwEG +MA4GA1UdDwEB/wQEAwIBBjBFBgNVHR8EPjA8MDqgOKA2hjRodHRwOi8vY3JsLmIt +dHJ1c3Qub3JnL3JlcG9zaXRvcnkvQi1UcnVzdFJvb3RBQ0EuY3JsMHgGCCsGAQUF +BwEBBGwwajAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuYi10cnVzdC5vcmcwQwYI +KwYBBQUHMAKGN2h0dHA6Ly9jYS5iLXRydXN0Lm9yZy9yZXBvc2l0b3J5L0ItVHJ1 +c3RSb290QUNBT0NTUC5jZXIwDQYJKoZIhvcNAQELBQADggIBALo0i4vghSPkaLAz +6auMu1Y6ITa1ur3UDgZ1mPvItTlFynQPZTGXGDwBFhX5Fx8raa7lWti7dhaaz01Q +iTJKVpPvpSzNp7yde5u+l4/ciD+x0THzyBo2Xr2pBDFlqFrCOGpVsU6T8BGgDxaj +Vu2H0wF7GS4WJ7gNnz60n06gwYh+T0PhOhqInmrIfYmuw90Pj075aTASRuCvJSrS +AV7l9VlkeE8bhTNAsF9A9n3tOl2gEYAMHTDA78i5jG/EsuuKRupGta3UcbA56Sr8 +EMLIM6GvRcBdszpugDwgHVe2Uu1Nem+hiZlxR7KbrkVWVgGzGxWgwcDu+Zd1d0o1 +8VePC4IiG8hTZIZoXFheKvskZVe9AF/9H1RS6saNsIVDGs27oFSZ6Jf9tYXVcNyU +w0m6ewWVB5Rjbqx6u7DVbii9z2oD/mRwuE6kJxhFk528UMuYhQg6qHQWh6PIbUWO +2mqzmIqWdB+VnVxEfbTmR260nqoZG820quMTiUCC0TAyrKT0/luq+sPwsoZAev6l +pWwOvpXiI8NaFEVy9UIbJGSVambpSvhuN3CWToGcucqsFeHFdg4S2qjXcV0ryNKF +QIWfARnE/rBqTbbnKhujjxfp+WO55RAG3MDduOeIu31fbg2BJgvdLkL4VKse8HO4 +hUr5/mi/HgyvqTAzoCf/KTxV7lYm +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIHMzCCBRugAwIBAgIIaQ5Pt5rtE5QwDQYJKoZIhvcNAQELBQAwcTELMAkGA1UE +BhMCQkcxGDAWBgNVBGETD05UUkJHLTIwMTIzMDQyNjESMBAGA1UEChMJQk9SSUNB +IEFEMRAwDgYDVQQLEwdCLVRydXN0MSIwIAYDVQQDExlCLVRydXN0IFJvb3QgUXVh +bGlmaWVkIENBMB4XDTE4MDYwMTEzNDQ1MFoXDTMzMDUzMTEzNDQ1MFoweDELMAkG +A1UEBhMCQkcxGDAWBgNVBGETD05UUkJHLTIwMTIzMDQyNjESMBAGA1UEChMJQk9S +SUNBIEFEMRAwDgYDVQQLEwdCLVRydXN0MSkwJwYDVQQDEyBCLVRydXN0IE9wZXJh +dGlvbmFsIFF1YWxpZmllZCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC +ggIBALotZe4YXbj/eg9cTbUEIm96CN/g6pr0mkSMQzcGoFJ/ob7ag7EFfXMh3p0o +aYx0sq3Sd3cRdSaFlkJhYHtuz6UqA6g/2iIjTehPS4a+NLIgkU7jfVjZ0rAZM/0J +Yeh2BPwgw0wiSwpviHTvMIpu7DHFNeWruocEKvgq4YqZriJRtPNapOFjRQWSTeZc +0btyn4prkLE54SreFQ/+z33spbgrnhI9m90GG6kMr/vx0E+iUYkVklCdBrTBcNll +gM+bF2V6iMcbLgnnjU1biHvPpZTd6cedJM3rHC9LLLE8Dxq95MmMK9vLoOCU0Sog +AjEx4XeZnS3h3xwA4qF6FCLe7D8FfNA0gWJO49h2GjDhnAzTGhyep6tH1p1Snizo +Pq+Z1rFcHOYrOXfJf5EplaZ0ls32HlFSGCCqHFOcx+NFcZelubJUsA0f7tYT2Pud +MmT0QrrFB/BODl4625UZlsiEWG0YLRkujBQgTYKjdSS9hiX9ZVcf8t/zeEibe1FC +nEjmrm8G+79bqAPa8dT3zy7FgWxN+YkYbqMaIdXmtCYLemmDHeYij/UbjrcSJ0Um +mR41PunO9bX64Jh2EsZn6TKUqWqJu/vGoDo93rvkIFcRMrD5Fe36G0WKcE7ytP57 +ekYYAotaVCpp4ecCyhPwV+BRBRqUPbw1asxvikrph4PlWn9JAgMAl6mjggHGMIIB +wjAdBgNVHQ4EFgQUJ88IQwTwxYM3Z4EXTfwF5ttli7AwHwYDVR0jBBgwFoAU8oTu +LjX+8PrYUFCwnEiJ6lov2aswIQYDVR0SBBowGIYWaHR0cDovL3d3dy5iLXRydXN0 +Lm9yZzASBgNVHRMBAf8ECDAGAQH/AgEAMHgGA1UdIARxMG8wQAYKKwYBBAH7dgEG +ATAyMDAGCCsGAQUFBwIBFiRodHRwOi8vd3d3LmItdHJ1c3Qub3JnL2RvY3VtZW50 +cy9jcHMwDQYLKwYBBAH7dgEGAQEwDQYLKwYBBAH7dgEGAQIwDQYLKwYBBAH7dgEG +AQMwDgYDVR0PAQH/BAQDAgEGMEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly9jcmwu +Yi10cnVzdC5vcmcvcmVwb3NpdG9yeS9CLVRydXN0Um9vdFFDQS5jcmwweAYIKwYB +BQUHAQEEbDBqMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5iLXRydXN0Lm9yZzBD +BggrBgEFBQcwAoY3aHR0cDovL2NhLmItdHJ1c3Qub3JnL3JlcG9zaXRvcnkvQi1U +cnVzdFJvb3RRQ0FPQ1NQLmNlcjANBgkqhkiG9w0BAQsFAAOCAgEAiPODGc6gWdHj +ROgQ2cy0KtZROQDl8ax0fTNJGmCvj714uBzuTvBECtLX8xZRmIvpd6PZq6Nexl4p +XhS04SLdz7MhakN970d12/cGxkdYotTEpx0WuXqPC3J0A5VWY8LLsJ8JhVoO4xp4 +HaNE4abnCj+uXURFLJsoxbEKy1iqHMy7lopej9sCuOjp6jNQa+J4b4mEx8RtFn4V +TnaC+19z3VQaPCaWfpJYnO1DsHSunZTq95UUVnjvgDM3WxuBRFkc551Q5dh4A+gr +Gw6yPW5ijOC1eTxpG6DMgJL41G7ftGX1AsXhOuxoWRf9r2sCdQJUVe/CtZ37Vjm1 +QUS+TmTAjLXInh/sVNFC3xs7wt2umPQYevTeS4KRrxXgcv92ClW8qZGXoqnsrNvx +9ATuHSMwysTBqrdEAAxqUrPrt2nb58yp+2Aa44CHhzXCfpFN9J84nwJhIOEVhLBa +VelsP5IpiCfUTDtluNFNZ+0lWws7ugwt0Y4UwNVkEbm+TxYe3taAoOcf3eZP2+Bf +VNM/MANpcY7h5uNdOxhRhB7l6MdvMJIMEq3RzEH+IH4tEBb56+H6Dkp93k1Hif6d +Iwa9vleIueDpL3R3aG7yv2lq2xFVUlB6r+zEFAXmGA6X26R44TwWO1tLVCYR76D7 +81dYNmLCvS/sJ4idGjW2TQDAOOB6mZ0= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIG7TCCBNWgAwIBAgIBATANBgkqhkiG9w0BAQsFADBwMQswCQYDVQQGEwJCRzEY +MBYGA1UEYRMPTlRSQkctMjAxMjMwNDI2MRIwEAYDVQQKEwlCT1JJQ0EgQUQxEDAO +BgNVBAsTB0ItVHJ1c3QxITAfBgNVBAMTGEItVHJ1c3QgUm9vdCBBZHZhbmNlZCBD +QTAeFw0xNzA0MjQxNTU1NDBaFw0zNzA0MjQxNTU1NDBaMHAxCzAJBgNVBAYTAkJH +MRgwFgYDVQRhEw9OVFJCRy0yMDEyMzA0MjYxEjAQBgNVBAoTCUJPUklDQSBBRDEQ +MA4GA1UECxMHQi1UcnVzdDEhMB8GA1UEAxMYQi1UcnVzdCBSb290IEFkdmFuY2Vk +IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvHDWX60/6UWsnNB9 +e0pTVK79v8xmGJwzzziPGJQcJn8vYL47ahbhL54m05nswif36k6WglCPR2+pFryg +HiTeUyDOpv96qTKOr3gpu2IrVxnL1078fCPQSta1xbWWGVQNJMx1td2TOfOv3QVU +azix/1kyfFxgTYIKpeYxm55/04eKiSy7ls6a38SXrrEEQTKCT2YmpqF6oTb+IXFw +K/b66wVDtEAbM93lfmz/EYDongHWK3ZJ4Vu+VhlDuhXhEee45FCaEmGUmQY4CYey +OKzR0FZPvv58QrcopfNRmJEtJzc5KNXwX96N4VDI1NO1+y1dYW206806HcoFLzTG +KXrxjsLROPM2LhGGqlOIEnvEHcSzmuqm6WiEZWkVjpsxLg3aYrcIy8R+KFAe+r4w +doveCJB9J3LqxsrppLEm1Vi7BHKpctzRypfgKwtREmG635mxFcDWGvdlpNxOS6wI +Rxq/uWYr5ENFZqXeccPk5IO27CPN32LXpqdTG1NMeJNCSuWeY/aisZx3ZkDpEhVv +UuYkVEP9SPPC0/FlUa01BZQV+OHmbu86AFeqfRBU+Gz6xJ7/4kiiXHTHlQQD2AOq +IaI4x3sWOzr471lQGct6qf5T9IW2rYoK61HvgsyTRAMgwMG8SdPjiovh7pW3w2Im +bWA/Cs2axUYZTTuxm4PmjBYEPe0CAwC8eaOCAZAwggGMMB0GA1UdDgQWBBSI20Lt +iQUyDHInDEYb4cYJXuzJITAfBgNVHSMEGDAWgBSI20LtiQUyDHInDEYb4cYJXuzJ +ITAhBgNVHRIEGjAYhhZodHRwOi8vd3d3LmItdHJ1c3Qub3JnMA8GA1UdEwEB/wQF +MAMBAf8wRQYDVR0gBD4wPDA6BgRVHSAAMDIwMAYIKwYBBQUHAgEWJGh0dHA6Ly93 +d3cuYi10cnVzdC5vcmcvZG9jdW1lbnRzL2NwczAOBgNVHQ8BAf8EBAMCAQYwRQYD +VR0fBD4wPDA6oDigNoY0aHR0cDovL2NybC5iLXRydXN0Lm9yZy9yZXBvc2l0b3J5 +L0ItVHJ1c3RSb290QUNBLmNybDB4BggrBgEFBQcBAQRsMGowIwYIKwYBBQUHMAGG +F2h0dHA6Ly9vY3NwLmItdHJ1c3Qub3JnMEMGCCsGAQUFBzAChjdodHRwOi8vY2Eu +Yi10cnVzdC5vcmcvcmVwb3NpdG9yeS9CLVRydXN0Um9vdEFDQU9DU1AuY2VyMA0G +CSqGSIb3DQEBCwUAA4ICAQA80F3bd7EII8Mbe+KApILCK5rgNKyzLBkpy074MCf+ +rRo1rnALybBUZSIyIOaxTFYEzHfubCMfGSd5VzZ9sJqCdM+REq7npzsx7f9fqfhi +USnJD+nrpLfyGNG0YsLFJS2KUPpMwBzrTTylgSVVnrLL38c976vJKBYQ7IsUt0Lr +DKYXoK+mBBsMlEfjgVsgsoeTF23tnqbAj6O9j7q0bkmw3AJkrCBEnhu183H0/Fnf +u8NV9s7vY5byFE8+fJGocr91VB8F/BKoduZO07Zo9DqbAn0lQttraGKTtxNbyM7W +hUgo9xaTkBHAx6PdjtW+cFCntKVibR4Pyaqqer2HOFVd/r+tG9FgEBX6fLkBdMmC +wgrvD8317zMyW9oQBi7VL0lGEVU1c7vrSAvNMBWkM0eATh40JF3Lt+/rJGttXL14 ++rW+JiUHVXV1ki0wUPgbS9P4Q7rjWte+43Z4axfYBOn079m2OXhDK/9lUvLMSPzh +loLq5DVzPtiehveg3YN8HuyyaJx/YN1FUGDzzmD4YGnKdW+OuVa7tQtc5Lxxl6Vs +YiEt6o5w81z5+4epgsathT1eNE3rjzIPqbCHCgGrXNgTWdqNC1U2XSNcLSA2UmIR +oR4TomufK6LDMFhiXFN841Ly1lrJRaYVi6l83AAFHDHQynFHFbw1PWWlxaLl/IEw +/Q== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIG7zCCBNegAwIBAgIBATANBgkqhkiG9w0BAQsFADBxMQswCQYDVQQGEwJCRzEY +MBYGA1UEYRMPTlRSQkctMjAxMjMwNDI2MRIwEAYDVQQKEwlCT1JJQ0EgQUQxEDAO +BgNVBAsTB0ItVHJ1c3QxIjAgBgNVBAMTGUItVHJ1c3QgUm9vdCBRdWFsaWZpZWQg +Q0EwHhcNMTcwNDI1MTUyODQzWhcNMzcwNDI1MTUyODQzWjBxMQswCQYDVQQGEwJC +RzEYMBYGA1UEYRMPTlRSQkctMjAxMjMwNDI2MRIwEAYDVQQKEwlCT1JJQ0EgQUQx +EDAOBgNVBAsTB0ItVHJ1c3QxIjAgBgNVBAMTGUItVHJ1c3QgUm9vdCBRdWFsaWZp +ZWQgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvMcOLZlM8z4Sm +jI6q0pT07UaZdFy9YdcErzJO2n8QSm4T9NQb9HYthmGNa/ZsBSh18rmC80pVpd9h +PCYr6uiMK/8dSBrY65pIU2HLSqVrhe+b0Qx6OS6lkKKYlHProEas3R0pNTTrg2hO +xJsEazBBghZC9ZUpermXR2ZlKM7QDMzEocRGVDjq4X49zx1a5TYlGJBAmAfwfVLt +rWeIlYjLAXu0Y4ntSuYQFX9d3uIUaVMgW+9S+XK+MuBZosSHPwl1VHMCbnvJH+9v +99/xheYYwfNsIesMI/cLdipaUFi76IhwgZk3741OACScqWl9/I2KKI+HfwPNQXKe +988kwJ6C9k0Q3BrzpFiOySU9YGQLd21nq5/0qvINmWp/hQn0J9BYnJYkX8yKTNEq +rEBV6xReIHHBVIgFCc89gcElryHHEJPw0HQOPdN9Yu099t7begrp9NCjY3h/RSg0 +JRua1pvIHxER3wCdjRuRdCDCcwpIMamVwsEtPs24lvgzBC0fqtVOP47uqEKgCcqY +lEx/cCgQI4bnZxY4WHXYHUgmBiH9iMUD9mly3+JzvO8oaPQXjIUg1oIAGkRLRPH0 +JNqmG+6Uw/b4mAbwYS5DDnFp6bN3MrSvPvEu0T7LTIkoKF9nZjByaMSSoOV36CD/ +kc0rQ2KIUNGcrKevvM4QocOPrau5owIDAMv9o4IBkDCCAYwwHQYDVR0OBBYEFPKE +7i41/vD62FBQsJxIiepaL9mrMB8GA1UdIwQYMBaAFPKE7i41/vD62FBQsJxIiepa +L9mrMCEGA1UdEgQaMBiGFmh0dHA6Ly93d3cuYi10cnVzdC5vcmcwDwYDVR0TAQH/ +BAUwAwEB/zBFBgNVHSAEPjA8MDoGBFUdIAAwMjAwBggrBgEFBQcCARYkaHR0cDov +L3d3dy5iLXRydXN0Lm9yZy9kb2N1bWVudHMvY3BzMA4GA1UdDwEB/wQEAwIBBjBF +BgNVHR8EPjA8MDqgOKA2hjRodHRwOi8vY3JsLmItdHJ1c3Qub3JnL3JlcG9zaXRv +cnkvQi1UcnVzdFJvb3RRQ0EuY3JsMHgGCCsGAQUFBwEBBGwwajAjBggrBgEFBQcw +AYYXaHR0cDovL29jc3AuYi10cnVzdC5vcmcwQwYIKwYBBQUHMAKGN2h0dHA6Ly9j +YS5iLXRydXN0Lm9yZy9yZXBvc2l0b3J5L0ItVHJ1c3RSb290UUNBT0NTUC5jZXIw +DQYJKoZIhvcNAQELBQADggIBAJkWw21cnW4B9sVeetOiaT3MdeN3Zz2PWZO4kkFE +yLQ8Yp0U0a4fj/c/09sO+D6KXXOnmCmSB+vbGMBdT6OTsgeierCJxOEtKWdxKRQx +rhDSwhYGiYvrATojdJAaaRS6Sz7AiezmqE6Nm0s3nWDk0Ne84YR4QQAHQ0HyX2oK +6+sP/1WuCVH1hQAT6mR1T+H6E+dqtRKi6luWICcGhls0l6SwhfvUioAe17cX1DTS +mnzNJ7f5kkwAih7s6vLgYltsEhqF/Mdlwmr2bkz4/Oo/5lorZNRrcNnsSUIdi6Ke +smZnxiotIVYjYktLOMFHlI1EzqNX9N0hD3wGoaoh6q+pdD3ynl0euih/A20gI35F +7NqeCJunQIbpfVR6C7NDzLlT62SFHeyO7HYXyrZHzabbsAIjoJuzyMR+fgTPDgWt +1w9ro/jGBWxijoOUtajWoIB/QsnbTuAbhVoSLI5cKBaEiQkcDh4seHecBzsidUHI +EBp0767rftu1SGBjXTRjoq2uPJvqdssAO09PRx5UoRWq/HvYfLz+1yC8TnH0A2uU ++bxt2xIgGmV4LAeLWo9GZpNlg4JhnwMO064UnQiaYJP7eS4cJaFAmWnFQfe65tij +NantvhJGbRL0dmV9fk5MfGFDCkYNj5Eop8GqLdVGQQsdx3LtjQsdK2bgwRhEAMQ1 ++uQZ +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +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 +So+/SJP8UkgxMHsQgwU= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIIYzCCBkugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQGEwJCRzEO +MAwGA1UEBxMFU29maWExIDAeBgNVBAoTF0JPUklDQSAtIEJBTktTRVJWSUNFIEFE +MRAwDgYDVQQLEwdCLVRydXN0MRgwFgYDVQQDEw9CLVRydXN0IFJvb3QgQ0EwHhcN +MTAwODE3MTQxMjQ4WhcNMjUwODE3MTQxMjQ4WjCCAQsxCzAJBgNVBAYTAkJHMQ4w +DAYDVQQIEwVTb2ZpYTEOMAwGA1UEBxMFU29maWExLzAtBgNVBAoTJkJPUklDQSAt +IEJBTktTRVJWSUNFIEFELCBFSUsgMjAxMjMwNDI2MRAwDgYDVQQLEwdCLVRydXN0 +MSMwIQYDVQQDExpCLVRydXN0IE9wZXJhdGlvbmFsIENBIFFFUzEnMCUGA1UECRMe +YnVsLiBUc2FyaWdyYWRza28gc2hvc2UgTm8gMTE3MQ0wCwYDVQQREwQxNzg0MSEw +HwYJKoZIhvcNAQkBFhJjYTVxZXNAYi10cnVzdC5vcmcxGTAXBgNVBBQTECszNTkg +MiA5IDIxNSAxMDAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC7Rdek +BYc7uX8wQ38Q3isEtAsyag33JNeu16awt7Ikl/IJcv7W8r3Jkgv+PShbkgJBj0CH +Oyndwn+MaojYVqwY3HKJYZBBCeo7IO28GXqIyk/Vh9jajADbReGzf9Pf63E1ZYaH +c182EcGZ3txweIWo2OjnI64+YiyL/X8U+xkUDgSr5hFKmNp8cL2YpSSKr3qtFWvj +50/GG3rkZ65IytEhQblRuWLoCMFed7rdo+s96jc+PmGHykAe0zIeJfOMgwf0QxEE +A8xHIBqtgWatFBZ/MddZi9RhOJK9x5xBRSLFXOB4RekMBD6St/Np7C9XUoDufAUb +LcbdnVOnyOs7eDioMDMR2fNqxiS86gjp4f38UgEX4Zvv7jbXzbKqUvGwm6ettcIJ +cGcgygEDCh+StWnrms56ZDUzSaRro3jgdRq5taRo5PLKNjBtvGFlxQe5uoUFUGkK +RIW2ufGIsyN3CuF+XE0Gc14mM8MJ4W5xlvG45zC2zdiicNmJ5fsYKP5WBrj5eqbt +EG6rlD9nQoQ9m/Z51/wU+CLwkBV5gwDSp3qhEJgXWccBni63XelGi2y3hlqfmWcH +Ye0c0qk0phD8FlwPovvYw7cMRZ1LOl43lj4U+oDWYWeDBwRhC2FccBxL51mWouVC +rHhrQEuMctCdBEIKWJ5BdOAx5AokmShkTinX+wIDAJvNo4ICbjCCAmowHQYDVR0O +BBYEFPI3d+hH+ukeEoLVuddycKlmD72KMIGVBgNVHSMEgY0wgYqAFJumSDojHzqp +qIgoV2TtBJYcMMidoW+kbTBrMQswCQYDVQQGEwJCRzEOMAwGA1UEBxMFU29maWEx +IDAeBgNVBAoTF0JPUklDQSAtIEJBTktTRVJWSUNFIEFEMRAwDgYDVQQLEwdCLVRy +dXN0MRgwFgYDVQQDEw9CLVRydXN0IFJvb3QgQ0GCAQEwIQYDVR0SBBowGIYWaHR0 +cDovL3d3dy5iLXRydXN0Lm9yZzASBgNVHRMBAf8ECDAGAQH/AgEDMIHfBgNVHSAE +gdcwgdQwRAYKKwYBBAH7dgEFATA2MDQGCCsGAQUFBwIBFihodHRwOi8vd3d3LmIt +dHJ1c3Qub3JnL2RvY3VtZW50cy9jYTUvY3BzMEUGCysGAQQB+3YBBQEBMDYwNAYI +KwYBBQUHAgEWKGh0dHA6Ly93d3cuYi10cnVzdC5vcmcvZG9jdW1lbnRzL2NhNS9j +cHMwRQYLKwYBBAH7dgEFAQIwNjA0BggrBgEFBQcCARYoaHR0cDovL3d3dy5iLXRy +dXN0Lm9yZy9kb2N1bWVudHMvY2E1L2NwczAOBgNVHQ8BAf8EBAMCAQYwUwYDVR0f +BEwwSjBIoEagRIZCaHR0cDovL3d3dy5iLXRydXN0Lm9yZy9yZXBvc2l0b3J5L2Nh +NXJvb3QvY3JsL2ItdHJ1c3RfY2E1X3Jvb3QuY3JsMDMGCCsGAQUFBwEBBCcwJTAj +BggrBgEFBQcwAYYXaHR0cDovL29jc3AuYi10cnVzdC5vcmcwDQYJKoZIhvcNAQEF +BQADggIBAJvP/zRgVMRkPkim5qvaHv7fL56IrVPml/mlD2Yqyry9tG3lhajTdG+D +T3JWaYHjff8dB7D20XK3KQUf0cKbKufuRlHqCCrGnIE3qWXxCzyEGxtCZm4+eUsI +bEgZQ0O0Sc968f69mmz1KgkIepDCW9dsgRwypOo8IjruD199fr0TpMltvqlArEF3 +EbOeJZ6d0tszWVLCy5Y7F970T+hgKicVkf9RXUmgdj9Xl1y3QWnDY4CVn3bQf732 +M3hpv1e/vmL86fz+JAtwEpw7ijAwO1XImfnjqTKjITRWoAUsH65CxZBOPIPix3kE +FcQLngZNdrmW23CBUBbjHI8kx0VvOEImsOUxSMboN2WeuaL6MOzoIxjSWaJwrVBO +s5/wMAB7AAYC0QxlUAUcOwkWoZRYLneQDpsDYngT7XOAVkaMiMTfWChg26EIGQdW +Wijib0ScvDvoNTF4XkLHWSBrKB2G1SNTuz20ZYqSm7Vm2M2mC90gUHQJOky+w4bC +V7FqETqcUhRp1LjSDqdiRysW9ahCgKKFRT2F26IVmPK4nYXDmBBy2MK9loTIY7lG +tGVz4XLKxCkJZ8GWaZ7f5PDbQfaeNzSFWdVHYyP4EI8xYiOzDBnuUaQxmeJwrG8E +TC+JPMS0GuY8BkEuwnjuEVpAeNCiOycik3cPODHGPz8ZAvuQKNC2 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIG4TCCBMmgAwIBAgIJAK7EeUZ21Q7RMA0GCSqGSIb3DQEBCwUAMHgxCzAJBgNV +BAYTAkJHMRgwFgYDVQRhEw9OVFJCRy0yMDEyMzA0MjYxEjAQBgNVBAoTCUJPUklD +QSBBRDEQMA4GA1UECxMHQi1UcnVzdDEpMCcGA1UEAxMgQi1UcnVzdCBPcGVyYXRp +b25hbCBRdWFsaWZpZWQgQ0EwHhcNMTgwNjAxMTEzMzIzWhcNMjMwNTMxMTEzMzIz +WjB+MQswCQYDVQQGEwJCRzEYMBYGA1UEYRMPTlRSQkctMjAxMjMwNDI2MRIwEAYD +VQQKEwlCT1JJQ0EgQUQxEDAOBgNVBAsTB0ItVHJ1c3QxLzAtBgNVBAMTJkItVHJ1 +c3QgUXVhbGlmaWVkIFRpbWUgU3RhbXAgQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA7Mx265YrppQtywsh3VXKOHF9Fviji9mrzmgmx0jT +lbxGMx3+9RG+F23QOF8KpRSOhQ6164rMfmuWTW40KLOTGw6ATEI1GoIXmivkb+Q4 +rm2zmwQPWYCpDurDRbtz3dY63CdKErVy5GJlw/vEEZl0xiJ/fwyVhsdKDIbhnUFs +RnaRPVB5htOLcClAjEMJLYmRVkT1dH2Tq36+LkYSIt7Sy2mH1929AWzHAHYx/ryP +DRbVqoiXEiGUAZrP8f11/82mLp6iDjTno8zfoZlNaiMxvaR7zBGSBXXSHdZL1EKI +3R4YB2DV3E/qfe93l6Pejm5PdL58HLnKP1euji8AueGyXQIDANkVo4ICZjCCAmIw +HQYDVR0OBBYEFFeWkxGiXJLO+yOeatiFDFC3sDqkMB8GA1UdIwQYMBaAFCfPCEME +8MWDN2eBF038BebbZYuwMCEGA1UdEgQaMBiGFmh0dHA6Ly93d3cuYi10cnVzdC5v +cmcwIQYDVR0RBBowGIYWaHR0cDovL3RzYS5iLXRydXN0Lm9yZzAJBgNVHRMEAjAA +MFUGA1UdIAROMEwwQAYKKwYBBAH7dgEGAzAyMDAGCCsGAQUFBwIBFiRodHRwOi8v +d3d3LmItdHJ1c3Qub3JnL2RvY3VtZW50cy9jcHMwCAYGBACPegECMA4GA1UdDwEB +/wQEAwIGwDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDBMBgNVHR8ERTBDMEGgP6A9 +hjtodHRwOi8vY3JsLmItdHJ1c3Qub3JnL3JlcG9zaXRvcnkvQi1UcnVzdE9wZXJh +dGlvbmFsUUNBLmNybDB/BggrBgEFBQcBAQRzMHEwIwYIKwYBBQUHMAGGF2h0dHA6 +Ly9vY3NwLmItdHJ1c3Qub3JnMEoGCCsGAQUFBzAChj5odHRwOi8vY2EuYi10cnVz +dC5vcmcvcmVwb3NpdG9yeS9CLVRydXN0T3BlcmF0aW9uYWxRQ0FPQ1NQLmNlcjCB +gAYIKwYBBQUHAQMEdDByMBUGCCsGAQUFBwsCMAkGBwQAi+xJAQIwCAYGBACORgEB +MAgGBgQAjkYBBDBFBgYEAI5GAQUwOzA5FjNodHRwczovL3d3dy5iLXRydXN0Lm9y +Zy9kb2N1bWVudHMvcGRzL3RzX3Bkc19lbi5wZGYTAmVuMA0GCSqGSIb3DQEBCwUA +A4ICAQCUL8wk1fFd3SIogse9DeCF7hrUV0BN6IZdhfynbzszjtaVU6rmYhzkpZpR +Z9JtM9L8Gl8KJ2YRiEohqCjR5ipZt/f/OEeWsvANnfJEWDYG5DBVtFxOx+UBqmaN +T/BS+rmLiIENBW2+cm5QWJPu2z9S1WgD5qYatbeg4lxAzrUm1PBoQS3AWCGDYwmb +U3P94ZRkNv93ncld++N348JFp67u/3ZDVGvh6mfCqzWeiISppo7ttTn+Pr9d8UZt +WAxjwRZpy7N62wGyCHJE83WjYdOxgayQNpUgDfl0QNMOUKkhCyEogw/3FJsszdpI +sR8rcMTT2GEZd5px+mCUADeN9mJr6f7j5Yb0zYrVGgNukuRe+mX6YxgXckyK+jBW +WEqblhOmWmQZGBYUiB0xSNB+va9EeF+O+SRZsWK7dq8VfqejMLuCgU2BGHiaSpGT +4+oA8mk8Sn7x/TTX0CmUI/l53IAY9RtuHJlaBiF4idyJ1yL2aY2pW1iC1W7vV1Vc +yDyf/GCpBFADocoE0dtEMEBb3qULtPUwUSXWMwxylPTl1iHibYfSauDkQxiCYtY5 +5AgEI4EkR5v8IyH461OiELXeQjUwDFOqWVDKAd3f7DToJ6K2/YzRo/YAzjn1+vS6 +HMFFvitv9TXR00hL0d55MBqicpQqlGgUDbDw/09fNv9e/GQ6Kw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- diff --git a/rebiss.py b/rebiss.py new file mode 100644 index 0000000..28a3e44 --- /dev/null +++ b/rebiss.py @@ -0,0 +1,522 @@ +# SPDX-License-Identifier: GPL-3.0-only + +import base64 +import logging +import getpass +import hashlib +import json +import os +import re +import subprocess +import unicodedata +import time +import datetime + +import OpenSSL.crypto as cr + + +class HashAlg: + __slots__ = ('len', 'hashlib_name', 'mech') + + def __init__(self, len, hashlib_name, mech): + self.len = len + self.hashlib_name = hashlib_name + self.mech = mech + +HASH_ALG = { + 'SHA256': HashAlg(32, 'sha256', 'SHA256-RSA-PKCS'), + 'SHA384': HashAlg(48, 'sha384', 'SHA384-RSA-PKCS'), + 'SHA512': HashAlg(64, 'sha512', 'SHA512-RSA-PKCS'), +} + + +def pkcs11_list(): + lines = subprocess.check_output(['pkcs11-tool', '--list-slots'], text=True).splitlines() + readers = [] + for line in lines: + m = re.fullmatch('Slot ([0-9]+) \\(.*\\): .*', line) + if m is None: + continue + readers.append(m.group(1)) + + certs = {} + for reader in readers: + lines = subprocess.check_output(['pkcs15-tool', '--reader', reader, '-c'], text=True).splitlines() + for line in lines: + m = re.fullmatch('\tID *: *([0-9a-f]+)$', line) + if m is None: + continue + cert_id = m.group(1) + cert_data = subprocess.check_output(['pkcs15-tool', '--reader', reader, '--read-certificate', cert_id]) + cert = cr.load_certificate(cr.FILETYPE_PEM, cert_data) + certs[reader,cert_id] = cert + + return certs + +def pkcs11_sign(key, msg, hash_alg, pin): + hash_val = hashlib.new(hash_alg.hashlib_name, msg).digest() + + reader,kid = key + env = os.environ.copy() + env['PIN'] = pin + proc = subprocess.run(['pkcs11-tool', '--slot', reader, '--id', kid, '-m', hash_alg.mech, '--pin', 'env:PIN', '--sign'], input=hash_val, stdout=subprocess.PIPE, env=env, check=True) + + return proc.stdout + + +def load_ts(ts): + t = time.strptime(ts.decode('ascii'), '%Y%m%d%H%M%SZ') + return datetime.datetime( + t.tm_year, + t.tm_mon, + t.tm_mday, + t.tm_hour, + t.tm_min, + t.tm_sec, + tzinfo=datetime.timezone.utc, + ) + +def check_selector(cert, selector, valid_only): + if valid_only: + valid_from = load_ts(cert.get_notBefore()) + valid_until = load_ts(cert.get_notAfter()) + if not (valid_from <= datetime.datetime.now(datetime.timezone.utc) <= valid_until): + return False + + vals = selector.get('issuers') + if vals is not None: + issuer_cn = [val.decode('utf-8', 'surrogateescape') for name,val in cert.get_issuer().get_components() if name == b'CN'] + if issuer_cn: + issuer_cn = issuer_cn[0] + else: + issuer_cn = '' + if f'CN={issuer_cn}' not in vals: + return False + + return True + +def describe_name(val): + return ', '.join(f'{k.decode("ascii")}={escape_bad(v.decode("utf-8", "surrogateescape"), ",=")}' for k,v in val.get_components()) + +def describe_cert(cert): + valid_from = load_ts(cert.get_notBefore()) + valid_until = load_ts(cert.get_notAfter()) + return ( + f'Issuer: {describe_name(cert.get_issuer())}\n' + f'Subject: {describe_name(cert.get_subject())}\n' + f'Valid from: {valid_from:%Y-%m-%d %H:%M:%S} UTC\n' + f'Valid until: {valid_until:%Y-%m-%d %H:%M:%S} UTC\n' + ) + +def escape_bad(l, esc=''): + r = [] + for c in l: + o = ord(c) + if 0xdc80 <= o <= 0xdd00: + r.append(f'\\x{ord(c)-0xdc00:02x}') + continue + if c == '\\': + r.append('\\\\') + continue + if o < 32 or o == 127 or (c in esc and o < 128): + r.append(f'\\x{ord(c):02x}') + continue + cat = unicodedata.category(c) + if cat in {'Cc', 'Cf', 'Cs'} or (cat.startswith('Z') and c != ' ') or c in esc: + if o < 0x10000: + r.append(f'\\u{o:04x}') + else: + r.append(f'\\U{o:08x}') + continue + r.append(c) + return ''.join(r) + +def print_blob(name, data, /): + if type(data) is str: + kind = 'text' + elif type(data) is bytes: + kind = 'blob' + data = '\n'.join(escape_bad(l.decode('utf-8', 'surrogateescape')) for l in data.splitlines()) + else: + kind = 'repr' + data = repr(data) + print(f'{name} ({kind}):') + + for line in data.splitlines(): + print(f' > {line!s}') + +def prompt(txt, /, default=False): + while True: + if default: + d = 'Y/n' + else: + d = 'y/N' + txt = input(f'{txt} [{d}]? ') + if txt in {'y', 'Y'}: + return True + if txt in {'n', 'N'}: + return False + if not txt: + return default + +STATUS_TEXT = { + 200: 'OK', + 201: 'Created', + 202: 'Accepted', + 203: 'Non-Authoritative Information', + 204: 'No Content', + 205: 'Reset Content', + 206: 'Partial Content', + 207: 'Multi-Status', + 208: 'Already Reported', + 226: 'IM Used', + 300: 'Multiple Choices', + 301: 'Moved Permanently', + 302: 'Found', + 303: 'See Other', + 304: 'Not Modified', + 305: 'Use Proxy', + 306: 'Switch Proxy', + 307: 'Temporary Redirect', + 308: 'Permanent Redirect', + 400: 'Bad Request', + 401: 'Unauthorized', + 402: 'Payment Required', + 403: 'Forbidden', + 404: 'Not Found', + 405: 'Method Not Allowed', + 406: 'Not Acceptable', + 407: 'Proxy Authentication Required', + 408: 'Request Timeout', + 409: 'Conflict', + 410: 'Gone', + 411: 'Length Required', + 412: 'Precondition Failed', + 413: 'Payload Too Large', + 414: 'URI Too Long', + 415: 'Unsupported Media Type', + 416: 'Range Not Satisfiable', + 417: 'Expectation Failed', + 418: 'I\'m a teapot', + 421: 'Misdirected Request', + 422: 'Unprocessable Entity', + 423: 'Locked', + 424: 'Failed Dependency', + 425: 'Too Early', + 426: 'Upgrade Required', + 428: 'Precondition Required', + 429: 'Too Many Requests', + 431: 'Request Header Fields Too Large', + 451: 'Unavailable For Legal Reasons', + 500: 'Internal Server Error', + 501: 'Not Implemented', + 502: 'Bad Gateway', + 503: 'Service Unavailable', + 504: 'Gateway Timeout', + 505: 'HTTP Version Not Supported', + 506: 'Variant Also Negotiates', + 507: 'Insufficient Storage', + 508: 'Loop Detected', + 510: 'Not Extended', + 511: 'Network Authentication Required', +} + +STATUS_FULL = {status: f'{status} {text}' for status,text in STATUS_TEXT.items()} + +class Req: + __slots__ = ('path', 'query_string', 'method', 'headers', 'input') + + def __init__(self, env): + self.path = env['PATH_INFO'] + self.query_string = env.get('QUERY_STRING') + self.method = env['REQUEST_METHOD'] + self.input = env['wsgi.input'] + headers = self.headers = {} + for k,v in env.items(): + if not k.startswith('HTTP_'): + continue + k = ''.join(map(str.title, k[5:].split('_'))) + headers[k] = v + + def read_data(self, /): + d = self.input + del self.input + return d.read() + + def resp(self, /, status, headers, data, *, content_type): + assert type(status) is int + assert type(data) is bytes + assert type(content_type) is str + headers = [*headers] + assert all(type(k) is str and type(v) is str for k,v in headers) + hdr = headers.append + + hdr(('Access-Control-Allow-Methods', 'GET, POST')) + hdr(('Access-Control-Allow-Headers', 'Accept, Content-Type')) + + try: + hdr(('Access-Control-Allow-Origin', self.headers['Origin'])) + except KeyError: + pass + + if self.method != 'OPTIONS': + hdr(('Content-Type', content_type)) + hdr(('Content-Length', f'{len(data)}')) + + hdr(('Cache-Control', 'no-cache')) + + return (status, headers, data) + + def resp_json(self, /, data, *, status=200, content_type='application/json;charset=UTF-8', headers=()): + return self.resp( + status, + headers, + json.dumps(data).encode('utf-8'), + content_type=content_type, + ) + + def resp_error(self, status, /): + try: + text = STATUS_TEXT[status] + except KeyError: + text = f'HTTP {status}' + if message is not None: + text = f'{text}: {message}' + return self.resp( + status, + (), + text.encode('utf-8'), + content_type='text/plain', + ) + + def resp_404(self, /): + return self.resp_error(404, **kw) + + def resp_405(self, /): + return self.resp_error(405, **kw) + + def resp_biss_error(self, /, status, message): + return self.resp_json({ + 'status': 'failed', + 'reasonCode': status, + 'reasonText': message, + }, status=status) + + def resp_biss_ok(self, /, **kw): + return self.resp_json({ + 'status': 'ok', + 'reasonCode': 200, + 'reasonText': 'response.success', + **kw, + }) + + +cr.X509StoreFlags.NO_CHECK_TIME = 0x200000 +store = cr.X509Store() +store.set_flags(cr.X509StoreFlags.CRL_CHECK_ALL | cr.X509StoreFlags.X509_STRICT | cr.X509StoreFlags.NO_CHECK_TIME) +store.load_locations('cacerts.pem') + +certs = pkcs11_list() + +def req_options(req): + return req.resp(200, (), b'', content_type='') + +def req_get_version(req): + return req.resp_json({ + 'version': '2.30', + 'httpMethods': 'GET, POST', + 'contentTypes': 'data', + 'signatureTypes': 'signature', + 'selectorAvailable': True, + 'hashAlgorithms': 'SHA256, SHA384, SHA512', + }) + +def req_get_status(req): + return req.resp_json('') + +def req_post_getsigner(req): + data = json.loads(req.read_data().decode('utf-8')) + + valid_only = data.get('showValidCerts', False) + # WAT + if valid_only == 'true': + valid_only = True + if valid_only == 'false': + valid_only = False + if type(valid_only) is not bool: + return req.resp_biss_error(400, 'error.request.bad-type') + + selector = data.get('selector', {}) + + for cert in certs.values(): + if check_selector(cert, selector, valid_only): + break + else: + return req.resp_biss_error(403, 'error.user-canceled') + + return req.resp_biss_ok( + chain = [ + base64.b64encode(cr.dump_certificate(cr.FILETYPE_ASN1, cert)).decode('ascii'), + ], + ) + +def req_post_sign(req): + data = json.loads(req.read_data().decode('utf-8')) + + try: + own_cert_data = data['signerCertificateB64'] + own_cert_data = base64.b64decode(own_cert_data) + except (KeyError, IndexError): + return req.resp_biss_error(400, 'error.wsp-cert-not-found') + + for own_key,own_cert in certs.items(): + if cr.dump_certificate(cr.FILETYPE_ASN1, own_cert) == own_cert_data: + break + else: + return req.resp_biss_error(400, 'error.request.bad-type') + + # BISS ignores it + # if data['contentType'] != 'data': + # return req.resp_biss_error(400, 'error.request.bad-type') + + try: + hash_alg = HASH_ALG[data.get('hashAlgorithm', 'SHA256')] + except KeyError: + return req.resp_biss_error(400, 'error.request.bad-type') + + msgs = [] + for i,(msg,sig,server_cert) in enumerate(zip(data['contents'], data['signedContents'], data['signedContentsCert'])): + msg = base64.b64decode(msg) + sig = base64.b64decode(sig) + server_cert = cr.load_certificate(cr.FILETYPE_ASN1, base64.b64decode(server_cert)) + + try: + # WAT? + cr.verify(server_cert, sig, hashlib.new(hash_alg.hashlib_name, msg).digest(), hash_alg.hashlib_name) + except cr.Error: + return req.resp_biss_error(400, 'error.request.signature-not-val') + + verify_ctx = cr.X509StoreContext(store, server_cert, None) + try: + verify_ctx.verify_certificate() + except cr.X509StoreContextError as exc: + if not prompt(f'Server certificate invalid ({exc!s}); continue'): + return req.resp_biss_error(403, 'error.request.certificate-not-valid') + + msgs.append((msg, server_cert)) + + t = data.get('confirmText') + if t is not None: + print_blob('Confirmation text', t) + + t = data.get('additionalConfirmText') + if t is not None: + print_blob('Additional confirmation text', t) + + for (msg,server_cert) in msgs: + print_blob(f'Message #{1+i}', msg) + print_blob('Server name', describe_cert(server_cert)) + + if not prompt('Sign'): + return req.resp_biss_error(403, 'error.user-canceled') + + pin = getpass.getpass('PIN: ') + + sigs = [] + for (msg, server_cert) in msgs: + sigs.append(pkcs11_sign(own_key, msg, hash_alg, pin)) + + return req.resp_biss_ok( + signatures = [base64.b64encode(sig).decode('ascii') for sig in sigs], + ) + +def req_post_chain_found(req): + # stub + data = json.loads(req.read_data().decode('utf-8')) + return req.resp_biss_ok(chainFound=True) + + +def fix_methods(hnd): + assert type(hnd) is dict and all(type(k) is str for k in hnd) + hnd = hnd.copy() + + if 'GET' in hnd and 'HEAD' not in hnd: + on_get = hnd['GET'] + def on_head(req): + (status, headers, data) = on_get(req) + return (status, headers, None) + hnd['HEAD'] = on_head + + hnd['OPTIONS'] = req_options + + return hnd + +def resp_exc(env, resp, exc): + rdata = ( + 'Internal Server Error' + '

Internal Server Error

' + '' + ).encode() + resp('500 Internal Server Error', [ + ('Content-Type', 'text/html;charset=utf-8'), + ('Content-Length', f'{len(rdata)}'), + ]) + return rdata + + +handlers = { + '/version': { + 'GET': req_get_version, + }, + '/status': { + 'GET': req_get_status, + }, + '/getsigner': { + 'POST': req_post_getsigner, + }, + '/sign': { + 'POST': req_post_sign, + }, + '/chainFound': { + 'POST': req_post_chain_found, + }, +} + +handlers = {path: fix_methods(sub) for path,sub in handlers.items()} + +def application(env, resp): + try: + req = Req(env) + except Exception as exc: + logging.exception('Failed to parse request') + return resp_exc(env, resp, exc) + + try: + h = handlers[req.path] + except KeyError: + h = Req.resp_404 + else: + try: + h = h[req.method] + except KeyError: + h = Req.resp_405 + + try: + rcode, rhdr, rdata = h(req) + except Exception as exc: + logging.exception('Request handler failed') + return resp_exc(env, resp, exc) + + assert type(rcode) is int + + try: + rcode = STATUS_FULL[rcode] + except KeyError: + rcode = f'{rcode}' + + resp(rcode, rhdr) + return rdata + +tty = os.open('/dev/tty', os.O_RDWR) +os.dup2(tty, 0) +os.dup2(tty, 1) diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..dc75fda --- /dev/null +++ b/run.sh @@ -0,0 +1,2 @@ +#!/bin/sh +exec uwsgi --master --plugin python3 --https-socket 127.0.0.1:53952,ssl.pem,ssl.key --module rebiss diff --git a/ssl.key b/ssl.key new file mode 100644 index 0000000..52fcf99 --- /dev/null +++ b/ssl.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDAdbiRz+ePjWQ5 +fb+LSNBsmryjHfzzg6qZH39mlbV5QLbR7Mj/jCOwkQ+BUc7GdrMuIBPwoKslEI7V +xwIs3s0Wdh9oNnZEbRYMF/ad2wkgjjn/FCGGONm0EsRGipyTaOaai9B2wZ5lS1vE +r+uxlrImtig83YRAn2Prj6ON+VMrnDUgiHvNcU9Ln8eZU+o8TaQouEsXgFz8Y33H +KTR6cBsLbMCSifwdm4rUIMuAx99eO+uDetF3bd2bf6beqWTjV0xOMa8xzOfb54wM +DVDWy7p1swT7/JmNbUeD+Ji8VjgZpjQ6inRQghm+UCb4AaazK/buVuZGS2ZKMRpu +CkiegNj/AgMBAAECggEAHgtilEoEnUmBJLkc3qAFKtHJx/G7AW2DriLCJIq+HonR +NcVFUstsQ43prJJPpCDMnlM9+aRYrfu/Pd/dgZFd1SH8i4FmW2Pne1zUUCvs6VWl +TSI14jpcFfs7WRhzZ/m0zNnYYb7zvLQTxTPXU00HTk7FH6H5xDgoWjzSrKuy5aLY +RM2lGZzylVzLag0MUJnp2mvB3lTeTQazritIp/8vhRZL129C7PGKYBAAjF/1MFu3 +OWE+r1yo4HtjcOi/NYn4hTcI3/wbPijkAVhlCIqolCkuZ0QT9h15DtszWC0O0XOr +ifgIeM7sMCn4D9EKulWuj5+nBWZbeVxTZekgmqfyrQKBgQDd3Ob1SjXx8CIMIiaH +G14HwU+FJv6ypnI4lEZPiW/TwXGR8fpLzZgnfqB9uhAH0stXcR0D8oeKvzPpcDyJ +7sXt18kpwY2nj8W1KX41+lNnQEuQBYYh24B/rdYyujctKcTsXMbQcQVDLfot9MAm +5wDkGlRs66opUFct5OBWchg0hQKBgQDeEqS33OPfhCJ+YrOaNjQXDi03gW4pSQsY +upZ9FUVV8O1IsuzWjd2DR+Vv+gJ9k7ufaJ6RR3pO+n/lnCDK5oaZe0cm0NaSldHf +PJAazN0e3tUnSlWKbYPskLYq2rA7LhLPAj69Qx8DN+HDVjG1fpjOxrnMCgtIN9Uk +c2XcnA2gswKBgHTzxJ/bDdLKhfglbG/eIlQuN+/13V9pVF608tdsmJFksKyBhTK+ +Xw26t3lvQpINMXmXu/bfu0mNfxz4OEFxp8636GflivmgVVUpWUm0+pA8GVkDQHDK +l9M2XOqCtSFOmmsKgRdR7Lc8HlxpX31iWlrj8ks0c4+xtTMRKp0HKfFNAoGAYDXB +iSq4yrhrXUgTuabsEGUC7/4yJM7RcOg9lHlnraEQnCNwek/B/UNjwoyVEaS0b46a +zCQkeB0M1gQ7LMyM2efP3qAxphYkc8vAPuwsjFhMDpak0rE5q37SfWR7X1hJq8e0 +OLjgsbs/IyqvpIrxVvw/uIdNdf9CZ2VbZyVwvgMCgYBPlnHKN5+rzGGO47PBB5GG +M0WeFpHW72Q1AdZOiR3Tnqtg7u9Ew4vjgmDA2TPL4iTdGzqO/Mddji6Z6sCGKtcD +NiJ7rY4EnvroPvxKfd5P99Uhz4M68FvCBrBuNVv7Cqct6nDvyPckYxjsEq0qnUju +eFu5Djr9JvONTB/D2Aju1g== +-----END PRIVATE KEY----- diff --git a/ssl.pem b/ssl.pem new file mode 100644 index 0000000..26c7ad9 --- /dev/null +++ b/ssl.pem @@ -0,0 +1,40 @@ +-----BEGIN CERTIFICATE----- +MIIHFDCCBPygAwIBAgIIbHufn8GDHocwDQYJKoZIhvcNAQELBQAwdzELMAkGA1UE +BhMCQkcxGDAWBgNVBGETD05UUkJHLTIwMTIzMDQyNjESMBAGA1UEChMJQk9SSUNB +IEFEMRAwDgYDVQQLEwdCLVRydXN0MSgwJgYDVQQDEx9CLVRydXN0IE9wZXJhdGlv +bmFsIEFkdmFuY2VkIENBMB4XDTIwMDcwMzEwMzkzN1oXDTMwMDcwMTEwMzkzN1ow +gYAxEjAQBgNVBAMTCWxvY2FsaG9zdDEPMA0GA1UECxMGT1YgU1NMMRIwEAYDVQQK +EwlCT1JJQ0EgQUQxGDAWBgNVBGETD05UUkJHLTIwMTIzMDQyNjEOMAwGA1UECBMF +U29maWExDjAMBgNVBAcTBVNvZmlhMQswCQYDVQQGEwJCRzCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAMB1uJHP54+NZDl9v4tI0GyavKMd/PODqpkff2aV +tXlAttHsyP+MI7CRD4FRzsZ2sy4gE/CgqyUQjtXHAizezRZ2H2g2dkRtFgwX9p3b +CSCOOf8UIYY42bQSxEaKnJNo5pqL0HbBnmVLW8Sv67GWsia2KDzdhECfY+uPo435 +UyucNSCIe81xT0ufx5lT6jxNpCi4SxeAXPxjfccpNHpwGwtswJKJ/B2bitQgy4DH +314764N60Xdt3Zt/pt6pZONXTE4xrzHM59vnjAwNUNbLunWzBPv8mY1tR4P4mLxW +OBmmNDqKdFCCGb5QJvgBprMr9u5W5kZLZkoxGm4KSJ6A2P8CAwEAAaOCApgwggKU +MB0GA1UdDgQWBBRvv8jv0YzeAofvbLsnXHqZbALpSTAfBgNVHSMEGDAWgBQH3Kow +dpi3hUttAxjI482nezaC7zAhBgNVHRIEGjAYhhZodHRwOi8vd3d3LmItdHJ1c3Qu +b3JnMAkGA1UdEwQCMAAwYAYDVR0gBFkwVzBBBgsrBgEEAft2AQcBBjAyMDAGCCsG +AQUFBwIBFiRodHRwOi8vd3d3LmItdHJ1c3Qub3JnL2RvY3VtZW50cy9jcHMwCAYG +Z4EMAQICMAgGBgQAj3oBBzAOBgNVHQ8BAf8EBAMCBaAwTwYDVR0lBEgwRgYIKwYB +BQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDBAYIKwYBBQUHAwUGCCsGAQUFBwMGBggr +BgEFBQcDBwYIKwYBBQUIAgIwTAYDVR0fBEUwQzBBoD+gPYY7aHR0cDovL2NybC5i +LXRydXN0Lm9yZy9yZXBvc2l0b3J5L0ItVHJ1c3RPcGVyYXRpb25hbEFDQS5jcmww +ewYIKwYBBQUHAQEEbzBtMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5iLXRydXN0 +Lm9yZzBGBggrBgEFBQcwAoY6aHR0cDovL2NhLmItdHJ1c3Qub3JnL3JlcG9zaXRv +cnkvQi1UcnVzdE9wZXJhdGlvbmFsQUNBLmNlcjBpBggrBgEFBQcBAwRdMFswFQYI +KwYBBQUHCwIwCQYHBACL7EkBAjBCBgYEAI5GAQUwODA2FjBodHRwczovL3d3dy5i +LXRydXN0Lm9yZy9kb2N1bWVudHMvcGRzL3Bkc19lbi5wZGYTAmVuMCsGA1UdEQQk +MCKCCWxvY2FsaG9zdIcEfwAAAYEPYWRtaW5AYm9yaWNhLmJnMA0GCSqGSIb3DQEB +CwUAA4ICAQCpXjBStAqiKxVLmMAdEuIS+8Yv9BsMX48G2+tTZmXf+F+UHDYXrPw3 +xqWn3Ot53ATxC0FNaKt26z7YHFVWUzPooZrF2Cacy1D3Xt63z1o5XXPVa2lW5wW5 ++FQDx4DX1hbRfQJVSKblUeobtZiBWsYoGWejMSMUw106e4Lx4vbHugFTX5Y/1joN +hdZtVijsjujyrMwCDgrNkxvISBxoXl+ia7QEWYGdfJbGoOZ55w/amlpR14TkX4Xt +Ksl1aqhVF7Q8Lv3vOYgZPUfATASohW9p97mTG/onws3dcTfAc74xMX6BhPQJofm4 +sDg6EkYPvY7DWowJV8K7qoeZf+sXYKlXe2QRwQjALCVtUrUtGR57PdFtYj84EuTf +3jHhfbLpGk9lG70dkoac/yelExgLOUe3/gDZXqkatKiaTXMyrgsCneTF9x0HnkCp +KF2wjPH1Ytegc6Yegu3UjqhHgKDg5V9IdcCpdG/rIfUWS7IYXXu+GA6woAXZf431 +i5Hwj/H2I0SMK6KpOBOwYZODLt8HCgxTC7DR6dmor4i+Fl2TkNnEzjs8dgOkwNT+ +Cv2BfDw17o/BHsO2ucCwRBIJM46RtLf7tAX6ud2i2lKdDA525HzDFHZNyhBs7zC3 +PYBiNOVzue6ETbW5ptVi5yt/+aomZzseNsm868KIZTqPHdLzVZJVrw== +-----END CERTIFICATE----- -- cgit