From 9bb65586f6f8e4a2ba2da23feb4ee8b224e45491 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Sat, 30 May 2015 17:52:44 +0200 Subject: startcom-sha2.py: utility to fix broken SHA256 intermediates Replaces intermediate certificates (PEM format) by other certificates. Beware of line endings! Supports both Python 2.7 and 3. --- startcom-sha2.py | 382 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 382 insertions(+) create mode 100755 startcom-sha2.py diff --git a/startcom-sha2.py b/startcom-sha2.py new file mode 100755 index 0000000..ea09710 --- /dev/null +++ b/startcom-sha2.py @@ -0,0 +1,382 @@ +#!/usr/bin/env python +''' +This program scans for StartCom's intermediate SHA256 certificate files which +have known compatibility issues with some Windows clients due to a cached SHA-1 +certificate. It can also fix these certificate files. + +Note that the new certificates **expire on 24 October 2017** while the +recommended (but problematic certs) expire on **14 October 2022**. Supported +intermediate CAs with their old and new serial number. + + StartCom Class 1 Primary Intermediate Server CA + 0x17153d9eab3fbf -> 0x19 + StartCom Class 2 Primary Intermediate Server CA + 0x1cab36472d9c51 -> 0x1b + StartCom Class 3 Primary Intermediate Server CA + 0x15a85b7110adcf -> 0x1d + +More details are available at +https://forum.startcom.org/viewtopic.php?p=21826#p21826 +''' + +class1 = ( +# https://www.startssl.com/certs/class1/sha2/pem/sub.class1.server.sha2.ca.pem +b''' +-----BEGIN CERTIFICATE-----''' + b''' +MIIF2TCCA8GgAwIBAgIHFxU9nqs/vzANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQG +EwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERp +Z2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDcxMDE0MjA1NDE3WhcNMjIxMDE0MjA1 +NDE3WjCBjDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzAp +BgNVBAsTIlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcxODA2BgNV +BAMTL1N0YXJ0Q29tIENsYXNzIDEgUHJpbWFyeSBJbnRlcm1lZGlhdGUgU2VydmVy +IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtonGrO8JUngHrJJj +0PREGBiEgFYfka7hh/oyULTTRwbw5gdfcA4Q9x3AzhA2NIVaD5Ksg8asWFI/ujjo +/OenJOJApgh2wJJuniptTT9uYSAK21ne0n1jsz5G/vohURjXzTCm7QduO3CHtPn6 +6+6CPAVvkvek3AowHpNz/gfK11+AnSJYUq4G2ouHI2mw5CrY6oPSvfNx23BaKA+v +WjhwRRI/ME3NO68X5Q/LoKldSKqxYVDLNM08XMML6BDAjJvwAwNi/rJsPnIO7hxD +KslIDlc5xDEhyBDBLIf+VJVSH1I8MRKbf+fAoKVZ1eKPPvDVqOHXcDGpxLPPr21T +Lwb0pwIDAQABo4IBTDCCAUgwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8E +BAMCAQYwHQYDVR0OBBYEFOtCNNCYsKuf9BtrCPfMZC7vDixFMB8GA1UdIwQYMBaA +FE4L7xqkQFulF2mHMMo0aEPQQa7yMGkGCCsGAQUFBwEBBF0wWzAnBggrBgEFBQcw +AYYbaHR0cDovL29jc3Auc3RhcnRzc2wuY29tL2NhMDAGCCsGAQUFBzAChiRodHRw +Oi8vYWlhLnN0YXJ0c3NsLmNvbS9jZXJ0cy9jYS5jcnQwMgYDVR0fBCswKTAnoCWg +I4YhaHR0cDovL2NybC5zdGFydHNzbC5jb20vc2ZzY2EuY3JsMEMGA1UdIAQ8MDow +OAYEVR0gADAwMC4GCCsGAQUFBwIBFiJodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9w +b2xpY3kucGRmMA0GCSqGSIb3DQEBCwUAA4ICAQCBnsOw7dxamNbdJb/ydkh4Qb6E +qgEU+G9hCCIGXwhWRZMYczNJMrpVvyLq5mNOmrFPC7bJrqYV+vEOYHNXrzthLyOG +FFOVQe2cxbmQecFOvbkWVlYAIaTG42sHKVi+RFsG2jRNZcFhHnsFnLPMyE6148lZ +wVdZGsxZvpeHReNUpW0jh7uq90sShFzHs4f7wJ5XmiHOL7fZbnFV6uE/OoFnBWif +CRnd9+RE3uCospESPCRPdbG+Q4GQ+MBS1moXDTRB6DcNoHvqC6eU3r8/Fn/DeA9w +9JHPXUfrAhZYKyOQUIqcfE5bvssaY+oODVxji6BMk8VSVHsJ4FSC1/7Pkt/UPoQp +FVh38wIJnvEUeNVmVl3HHFYTd50irdKYPBC63qi2V/YYI6bJKmbrjfP9Vhyt9uNr +y3Kh4W22ktDuCCvWC7n/gqerdq+VlTRfNt7D/mB0irnaKjEVNCXBXm9V/978J+Ez +8aplGZccQ9jnc9kiPtUp5dj45E3V8vKqzp9srSSI5Xapdg+ZcPY+6HNuVB+MadRp +ZW2One/Qnzg9B4GnVX7MOETImdoP4kXpostFuxoY/5LxCU1LJAIENV4txvT50lX2 +GBXCkxllRLWOgdyll11ift/4IO1aCOGDijGIfh498YisM1LGxytmGcxvbJERVri+ +gGpWAZ5J6dvtf0s+bA== +-----END CERTIFICATE----- +''', +# https://class3.test.itk98.net/class1.ca.pem +b''' +-----BEGIN CERTIFICATE-----''' + b''' +MIIGNDCCBBygAwIBAgIBGTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJ +TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERp +Z2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20g +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDcxMDI0MjA1NDE3WhcNMTcx +MDI0MjA1NDE3WjCBjDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29t +IEx0ZC4xKzApBgNVBAsTIlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNp +Z25pbmcxODA2BgNVBAMTL1N0YXJ0Q29tIENsYXNzIDEgUHJpbWFyeSBJbnRl +cm1lZGlhdGUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAtonGrO8JUngHrJJj0PREGBiEgFYfka7hh/oyULTTRwbw5gdfcA4Q +9x3AzhA2NIVaD5Ksg8asWFI/ujjo/OenJOJApgh2wJJuniptTT9uYSAK21ne +0n1jsz5G/vohURjXzTCm7QduO3CHtPn66+6CPAVvkvek3AowHpNz/gfK11+A +nSJYUq4G2ouHI2mw5CrY6oPSvfNx23BaKA+vWjhwRRI/ME3NO68X5Q/LoKld +SKqxYVDLNM08XMML6BDAjJvwAwNi/rJsPnIO7hxDKslIDlc5xDEhyBDBLIf+ +VJVSH1I8MRKbf+fAoKVZ1eKPPvDVqOHXcDGpxLPPr21TLwb0pwIDAQABo4IB +rTCCAakwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O +BBYEFOtCNNCYsKuf9BtrCPfMZC7vDixFMB8GA1UdIwQYMBaAFE4L7xqkQFul +F2mHMMo0aEPQQa7yMGYGCCsGAQUFBwEBBFowWDAnBggrBgEFBQcwAYYbaHR0 +cDovL29jc3Auc3RhcnRzc2wuY29tL2NhMC0GCCsGAQUFBzAChiFodHRwOi8v +d3d3LnN0YXJ0c3NsLmNvbS9zZnNjYS5jcnQwWwYDVR0fBFQwUjAnoCWgI4Yh +aHR0cDovL3d3dy5zdGFydHNzbC5jb20vc2ZzY2EuY3JsMCegJaAjhiFodHRw +Oi8vY3JsLnN0YXJ0c3NsLmNvbS9zZnNjYS5jcmwwgYAGA1UdIAR5MHcwdQYL +KwYBBAGBtTcBAgEwZjAuBggrBgEFBQcCARYiaHR0cDovL3d3dy5zdGFydHNz +bC5jb20vcG9saWN5LnBkZjA0BggrBgEFBQcCARYoaHR0cDovL3d3dy5zdGFy +dHNzbC5jb20vaW50ZXJtZWRpYXRlLnBkZjANBgkqhkiG9w0BAQsFAAOCAgEA +UiVivr7DGl0kxETnJMnlpLWn6AXQE+XSL2TdMkbS3wY40tqEo2O/MJ54cf1W +QgZilw659qpXYmxMNX2VGo8rz2HxPcBMaU2mjRnVAyFXn2uLvTKUcBIu0Gs1 +qA75FBUOYxKudcreUaeWD2LlPgtdMX48mEU1VmjtDAHs1X7/z5j6c75c2VZ6 +9xx05z1MKm4+32xsntq3EdcmskUBc2VZNqs6iz1+cCBTQBdeP56f+1hFQ5Hi +isQ8bDVdeENoFO99kHAAtjv4pkmj4BYqBUVWJy3VXxJcOk3QWyn5zwUps6EA +JCAkY6u7rUiEhF4a3y7IV3llMx7V+lpkACGAKOlO2CVRohy+SDOiVGkzF+dz +n+dx8Dzk+XX8ttFMh7G/IkbOBXLUOEuIDshnupkJZZdIFznMWAWN0iOj6qyb +3+FwZAA5AZua5nrZrLeqK8ssn8L5sFQOfO9mwcgszBLr63VfH+y4WqSDyVj9 +mVv3yh6zTKYoXOMjH722m0oPwmgFsNLVrRSMtGt3Vvh0oSoDCjOi594tqTwa +emktFyGcXud7db/MkwC2MU0DC1QZX3YQpjuP/keRY/U46/oOwaqI8JnhNd6x +yn4H4ufzUAgl+Pu/aphb4RlClRuEL38a/Kq70wujW77vBXiEmjVOKnIkI2OE +lZ/AyIQS/jZfAJX+NnYi6tU= +-----END CERTIFICATE----- +''' +) + +class2 = ( +# https://www.startssl.com/certs/class2/sha2/pem/sub.class2.server.sha2.ca.pem +b''' +-----BEGIN CERTIFICATE-----''' + b''' +MIIF2TCCA8GgAwIBAgIHHKs2Ry2cUTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQG +EwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERp +Z2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDcxMDE0MjA1NzA5WhcNMjIxMDE0MjA1 +NzA5WjCBjDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzAp +BgNVBAsTIlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcxODA2BgNV +BAMTL1N0YXJ0Q29tIENsYXNzIDIgUHJpbWFyeSBJbnRlcm1lZGlhdGUgU2VydmVy +IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4k85L6GMmoWtCA4I +PlfyiAEhG5SpbOK426oZGEY6UqH1D/RujOqWjJaHeRNAUS8i8gyLhw9l33F0NENV +sTUJm9m8H/rrQtCXQHK3Q5Y9upadXVACHJuRjZzArNe7LxfXyz6CnXPrB0KSss1k +s3RVG7RLhiEs93iHMuAW5Nq9TJXqpAp+tgoNLorPVavD5d1Bik7mb2VsskDPF125 +w2oLJxGEd2H2wnztwI14FBiZgZl1Y7foU9O6YekO+qIw80aiuckfbIBaQKwn7UhH +M7BUxkYa8zVhwQIpkFR+ZE3EMFICgtffziFuGJHXuKuMJxe18KMBL47SLoc6PbQp +Z4rEAwIDAQABo4IBTDCCAUgwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8E +BAMCAQYwHQYDVR0OBBYEFBHbI0X9VMxqcW+EigPXvvcBLyaGMB8GA1UdIwQYMBaA +FE4L7xqkQFulF2mHMMo0aEPQQa7yMGkGCCsGAQUFBwEBBF0wWzAnBggrBgEFBQcw +AYYbaHR0cDovL29jc3Auc3RhcnRzc2wuY29tL2NhMDAGCCsGAQUFBzAChiRodHRw +Oi8vYWlhLnN0YXJ0c3NsLmNvbS9jZXJ0cy9jYS5jcnQwMgYDVR0fBCswKTAnoCWg +I4YhaHR0cDovL2NybC5zdGFydHNzbC5jb20vc2ZzY2EuY3JsMEMGA1UdIAQ8MDow +OAYEVR0gADAwMC4GCCsGAQUFBwIBFiJodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9w +b2xpY3kucGRmMA0GCSqGSIb3DQEBCwUAA4ICAQBSyb3zvcv566LEMsqGcvzPv6cw +tf2R99WB4SEErQBM/+mLJ9r/8iTN/B8Pf9LR5YGSI3gW7msDLp0ASE+ugmUuh2/u +agdfS1Zu95ZGQebd/kW5Yiqainbprb3Wc7O8MSvQLNVsa7xqOiWHqailDdeF8Wxs +BQ70wWjLuyqBWKU+mcSf9x+EjqB60U3buAGcDYE0yoL+I2JNP22kUsBMXvJpSLHy +36xEZGmwRinHrfDywJ1oI4qoZ3EiF77OiXp2vlRsk1yL8Bpuru2OrsIFrhNX5rnn +cMgzuJ79SjDjmNQTa+5Ouebs387qoJ52apeq6t80RUL12k3Wh3Zt/85phnqBX9uy +T86w4GdgOUSwRRCFZZcSed/Ul9h4IQyEmM67T2sPGdqFaZFBbBccxrn2FK7yoYB6 +4umV7yKKzP842/whVuyA/W2ihZEpA+qrA70sYESCADXnFGx2O0CDVdVc38coo1nV +iXg+D+AG/dVXiiQcp2I4HYWTS/mTf/NE+mOYnu0miZ32/vhDbCX/B/kSPJ4RsNOA +7uyrOwykcgOSFDbpvuaKOpGLrQwGqLODgm+p9TY5giMMjur9XH7TS1wz02dIz07u +y2NwYWdV67vcnAt6QxRISap5RbaPviyQZxz4nFaSlTAwHoPaW1yuVS11tmsROMlR +RNvbaAxIU4U67YaZSw== +-----END CERTIFICATE----- +''', +# https://class3.test.itk98.net/class2.ca.pem +b''' +-----BEGIN CERTIFICATE-----''' + b''' +MIIGNDCCBBygAwIBAgIBGzANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJ +TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERp +Z2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20g +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDcxMDI0MjA1NzA5WhcNMTcx +MDI0MjA1NzA5WjCBjDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29t +IEx0ZC4xKzApBgNVBAsTIlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNp +Z25pbmcxODA2BgNVBAMTL1N0YXJ0Q29tIENsYXNzIDIgUHJpbWFyeSBJbnRl +cm1lZGlhdGUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEA4k85L6GMmoWtCA4IPlfyiAEhG5SpbOK426oZGEY6UqH1D/RujOqW +jJaHeRNAUS8i8gyLhw9l33F0NENVsTUJm9m8H/rrQtCXQHK3Q5Y9upadXVAC +HJuRjZzArNe7LxfXyz6CnXPrB0KSss1ks3RVG7RLhiEs93iHMuAW5Nq9TJXq +pAp+tgoNLorPVavD5d1Bik7mb2VsskDPF125w2oLJxGEd2H2wnztwI14FBiZ +gZl1Y7foU9O6YekO+qIw80aiuckfbIBaQKwn7UhHM7BUxkYa8zVhwQIpkFR+ +ZE3EMFICgtffziFuGJHXuKuMJxe18KMBL47SLoc6PbQpZ4rEAwIDAQABo4IB +rTCCAakwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O +BBYEFBHbI0X9VMxqcW+EigPXvvcBLyaGMB8GA1UdIwQYMBaAFE4L7xqkQFul +F2mHMMo0aEPQQa7yMGYGCCsGAQUFBwEBBFowWDAnBggrBgEFBQcwAYYbaHR0 +cDovL29jc3Auc3RhcnRzc2wuY29tL2NhMC0GCCsGAQUFBzAChiFodHRwOi8v +d3d3LnN0YXJ0c3NsLmNvbS9zZnNjYS5jcnQwWwYDVR0fBFQwUjAnoCWgI4Yh +aHR0cDovL3d3dy5zdGFydHNzbC5jb20vc2ZzY2EuY3JsMCegJaAjhiFodHRw +Oi8vY3JsLnN0YXJ0c3NsLmNvbS9zZnNjYS5jcmwwgYAGA1UdIAR5MHcwdQYL +KwYBBAGBtTcBAgEwZjAuBggrBgEFBQcCARYiaHR0cDovL3d3dy5zdGFydHNz +bC5jb20vcG9saWN5LnBkZjA0BggrBgEFBQcCARYoaHR0cDovL3d3dy5zdGFy +dHNzbC5jb20vaW50ZXJtZWRpYXRlLnBkZjANBgkqhkiG9w0BAQsFAAOCAgEA +bQjxXHkqUPtUY+u8NEFcuKMDITfjvGklLgrTuBW63grW+2AuDAZRo/066eNH +s6QV4i5e4ujwPSR2dgggY7mOIIBmiDm2QRjF5CROq6zDlIdqlsFZICkuONDN +FpFjaPtZRTmuK1n6gywQgCNSIrbzjPcwR/jL/wowbfwC9yGme1EeZRqvWy/H +zFWacs7UMmWlRk6DTmpfPOPMJo5AxyTZCiCYQQeksV7xUAeY0kWa+y/FV+ee +rOPUl6yy4jRHTk7tCySxrciZwYbd6YNLmeIQoUAdRC3CH3nTB2/JYxltcgyG +HMiPU3TtafZgLs8fvncv+wIF1YAF/OGqg8qmzoJ3ghM4upGdTMIu8vADdmuL +C/+dnbzknxX6QEGlWA8zojLUxVhGNfIFoizu/V/DyvSvYuxzzIkPECK5gDoM +oBTTMI/wnxXwulNPtfgF7/5AtDhA4GNAfB2SddxiNQAF7XkUHtMZ9ff3W6Xk +FldOG+NlLFqsDBG/KLckyFK36gq+FqNFCbmtmtXBGB5L1fDIeYzcMKG6hFQx +hHS0oqpdHhp2nWBfLlOnTNqIZNJzOH37OJE6Olk45LNFJtSrqIAZyCCfM6bQ +goQvZuIaxs9SIp+63ZMk9TxEaQj/KteaOyfaPXI9778U7JElMTz3Bls62msl +V2I1C/A73ZyqJZWQZ8NU4ds= +-----END CERTIFICATE----- +''' +) + +class3 = ( +# https://www.startssl.com/certs/class1/sha2/pem/sub.class3.server.sha2.ca.pem +b''' +-----BEGIN CERTIFICATE-----''' + b''' +MIIF2TCCA8GgAwIBAgIHFahbcRCtzzANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQG +EwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERp +Z2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDcxMDE0MjA1ODI0WhcNMjIxMDE0MjA1 +ODI0WjCBjDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzAp +BgNVBAsTIlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcxODA2BgNV +BAMTL1N0YXJ0Q29tIENsYXNzIDMgUHJpbWFyeSBJbnRlcm1lZGlhdGUgU2VydmVy +IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxtTlmqySw6jNfvAT +GV+1Z3tzCryzboJMuKv++wEh3XwM+fi1gAH9j8X6ORJYdCJcqWOA/D+E4Sh37S7x +JR9JDCfpPo+6yS9G0D/pOuQjUZVCdBfGym0DOFrHfgaAtN+wy/rvVULObi1AYw7c +F/a59olLMt5B41FNcbMCmJEBzmhc6iqttRqI0lGX72VDfcdEvOLw7rdEetvTl6hx +/s/2B58j/NxVY5M3J/oeqY0sPOSc3RMrH1mWZ1xgS96FgeblRRxdNfRbDn1/qdrE +Vxxc2jWHRyUUbpdevcgeTynGfBLcLsW9QUREZP2wGbeJL1TkbkMfxb/MKdQQzheL +/9Gc2QIDAQABo4IBTDCCAUgwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8E +BAMCAQYwHQYDVR0OBBYEFIn4QqYcYurH8TIJK0E+e6JcrsVLMB8GA1UdIwQYMBaA +FE4L7xqkQFulF2mHMMo0aEPQQa7yMGkGCCsGAQUFBwEBBF0wWzAnBggrBgEFBQcw +AYYbaHR0cDovL29jc3Auc3RhcnRzc2wuY29tL2NhMDAGCCsGAQUFBzAChiRodHRw +Oi8vYWlhLnN0YXJ0c3NsLmNvbS9jZXJ0cy9jYS5jcnQwMgYDVR0fBCswKTAnoCWg +I4YhaHR0cDovL2NybC5zdGFydHNzbC5jb20vc2ZzY2EuY3JsMEMGA1UdIAQ8MDow +OAYEVR0gADAwMC4GCCsGAQUFBwIBFiJodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9w +b2xpY3kucGRmMA0GCSqGSIb3DQEBCwUAA4ICAQAthLawLWmq9RJIhpczAyq3ep7T +ccmBd50ifXNehjyJ5d90C/uflhRHe/tzGQKHGhgb/3jhW8k0HDfdqsGTZI6jkC+a +Rld1X0cQMj/1NAXnOuMqhDXc5kANit9TdvtGlWZHVFvEk75JPYDD0D7ZXTQ3ccRn +1CzQM9pX5uxp3eiVHh8zHVwbrVyxBi3zXTSD1sUP/Ze/aXPP/OYZl8y3Iy8cQpiq +ie7OiiB1gOqp42Vb9lWnoH6jBLVpmtmkpcbH2wgClEmjgGTxmlILhD8BlrKF31vX +j6KdlRwn+jA0Uz6DCD+1IWMaADMOzeG9P41upK5uESwvVUXImboBR/OXBMc8Jyg8 +WmPTG5rEwqkhGfsedq05kxg7MXmI7M2aaxXYwedkIGzhqrv6h3tLH/o8X9Ff7d0B +SLK8wwGstLZ7vNv6K7q2bMv4g5mKaesPNg/hoTri4yJEbYVBL9xgvTLhvNGp46IY +UEzn3vnFE6gnhne4jFQWqV4zjA9JveC8LtMqoAE8Z4HJbSNurfokLEm1MS3qIVHN +po3bgKCaTKJhsOcWY3a38jb8GalRiqKJE5lKqvKvZ/gPWZVOl78qROiDfdWvBT00 +7p6y48YVkRW8Q1+M45w8cRaXfoRXbMJVCD9KvDrL2kDobaTvtIZxK0PUbKCXubPw +0N8NcSQMxAONGPkXWw== +-----END CERTIFICATE----- +''', +# https://class3.test.itk98.net/class3.ca.pem +b''' +-----BEGIN CERTIFICATE-----''' + b''' +MIIGNDCCBBygAwIBAgIBHTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJ +TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERp +Z2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20g +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDcxMDI0MjA1ODI0WhcNMTcx +MDI0MjA1ODI0WjCBjDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29t +IEx0ZC4xKzApBgNVBAsTIlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNp +Z25pbmcxODA2BgNVBAMTL1N0YXJ0Q29tIENsYXNzIDMgUHJpbWFyeSBJbnRl +cm1lZGlhdGUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAxtTlmqySw6jNfvATGV+1Z3tzCryzboJMuKv++wEh3XwM+fi1gAH9 +j8X6ORJYdCJcqWOA/D+E4Sh37S7xJR9JDCfpPo+6yS9G0D/pOuQjUZVCdBfG +ym0DOFrHfgaAtN+wy/rvVULObi1AYw7cF/a59olLMt5B41FNcbMCmJEBzmhc +6iqttRqI0lGX72VDfcdEvOLw7rdEetvTl6hx/s/2B58j/NxVY5M3J/oeqY0s +POSc3RMrH1mWZ1xgS96FgeblRRxdNfRbDn1/qdrEVxxc2jWHRyUUbpdevcge +TynGfBLcLsW9QUREZP2wGbeJL1TkbkMfxb/MKdQQzheL/9Gc2QIDAQABo4IB +rTCCAakwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O +BBYEFIn4QqYcYurH8TIJK0E+e6JcrsVLMB8GA1UdIwQYMBaAFE4L7xqkQFul +F2mHMMo0aEPQQa7yMGYGCCsGAQUFBwEBBFowWDAnBggrBgEFBQcwAYYbaHR0 +cDovL29jc3Auc3RhcnRzc2wuY29tL2NhMC0GCCsGAQUFBzAChiFodHRwOi8v +d3d3LnN0YXJ0c3NsLmNvbS9zZnNjYS5jcnQwWwYDVR0fBFQwUjAnoCWgI4Yh +aHR0cDovL3d3dy5zdGFydHNzbC5jb20vc2ZzY2EuY3JsMCegJaAjhiFodHRw +Oi8vY3JsLnN0YXJ0c3NsLmNvbS9zZnNjYS5jcmwwgYAGA1UdIAR5MHcwdQYL +KwYBBAGBtTcBAgEwZjAuBggrBgEFBQcCARYiaHR0cDovL3d3dy5zdGFydHNz +bC5jb20vcG9saWN5LnBkZjA0BggrBgEFBQcCARYoaHR0cDovL3d3dy5zdGFy +dHNzbC5jb20vaW50ZXJtZWRpYXRlLnBkZjANBgkqhkiG9w0BAQsFAAOCAgEA +SGTXnpQAUrMhzFcGLy/B/gNWS1zJ2j72py8ncV/rMxwBZdPwt6EUim63VwUA +29wXrH6ANWF0UOBoaYJWyqkObaHY8cJuqbNhEl+WXGTZSqgjtgdqdICdIYvq +Yya0rEj1Rr4tA9MoyG+1Xp4fPClHyMPAHcED5hWZ9wV0B2Rn8NOlbvmOj1dA +QMfubRvxbKrWfAJ/J9KP+CntK/jh+v3EKSe1Jeyzn1pf0bz3pInkzfcxM53R +6BWO24M3iVmAm3tY8uwwXFxv/3HVVgnorPXUFOxGujXPWv4m2LBtth7JH9CO +vQwFCqYZut9vWb+0efgp3PkY2PgZtf3HEu7l51VedulrcVEiljno8cpDjagd +b50YxNPvp6aAwxkV7wd3cgcGzS8YmbmQ8GLBCDTCcSmSIYKFIy9dTAu6C5s6 +0E6WeFHEtgNUoqzAXQ1zJLyQNRadhcM6f9lbjVCmv0/BvACOpGgAEEvjm4CY +hKxZ+ob+KsEwXXQTT2HMa+bjBKopgj6VWTnf5j295YWP+3b0921AvZSzXDTi +WIld8wrW3d89JxX69FuP3+CE85ryMxFwbuyITBYjnxDF9aFAlJOi5w7saXeB +w1TvmYsilX3+fwnn5Nu4PZqw4MjxRcip15q6pz+SPjdhpYqFDQ3mgrvf4dMH +ImruS2dA4t8bY/h8BARHrec= +-----END CERTIFICATE----- +''' +) + +startcom_ca_certificates = ( + ('class1', class1), + ('class2', class2), + ('class3', class3) +) + +import argparse, os, logging, subprocess, sys +_logger = logging.getLogger(__name__) + +def find_updated_cert(filename, ca_certificates): + ''' + Returns None if the file contents do not contain the problematic + certificate, and the new file contents otherwise. + ''' + contents = open(filename, 'rb').read() + if b'-----BEGIN CERTIFICATE-----' not in contents: + _logger.info('%s: not a certificate, skipping', filename) + return None + orig_contents = contents + for name, (old_cert, new_cert) in ca_certificates: + if not old_cert in contents: + continue + _logger.warning('%s: certificate needs update: %s', filename, name) + contents = contents.replace(old_cert, new_cert) + + if orig_contents != contents: + return contents + + _logger.info('%s: no changes needed', filename) + +def get_filenames(filenames, recursive): + ''' + Discovers all files from the given set of filenames, optionally recursing + into directory items. + ''' + while filenames: + item = filenames[0] + filenames = filenames[1:] + if os.path.isdir(item) and recursive: + try: + diritems = [os.path.join(item, filename) + for filename in os.listdir(item)] + except EnvironmentError as e: + _logger.warning('%s: %s', item, e) + continue + filenames = diritems + filenames + else: + yield item + +def main(args): + logLevel = logging.INFO if args.verbose else logging.WARNING + logging.basicConfig(format='%(message)s', level=logLevel) + + if args.reverse: + ca_certificates = ( + (name, (new_cert, old_cert)) + for name, (old_cert, new_cert) in startcom_ca_certificates + ) + else: + ca_certificates = startcom_ca_certificates + + for filename in get_filenames(args.files, args.recursive): + try: + new_contents = find_updated_cert(filename, ca_certificates) + except EnvironmentError as e: + _logger.warning('%s: read error: %s', filename, e) + continue + + # Do not write unmodified files, or when in read-only mode. + if not new_contents or not args.write: + continue + + try: + open(filename, 'wb').write(new_contents) + _logger.warning('%s: wrote new certificate', filename) + except EnvironmentError as e: + _logger.warning('%s: write error: %s', filename, e) + +def print_certificate(pem): + sys.stdout.flush() # Flush buffered messages + p = subprocess.Popen(['openssl', 'x509', '-text'], stdin=subprocess.PIPE) + p.communicate(pem) + +def print_certificates(): + for name, (old_cert, new_cert) in startcom_ca_certificates: + print('# Certificate %s:' % name) + print('') + + print('## Problematic certificate:') + print_certificate(old_cert) + print('') + + print('## Fixed certificate:') + print_certificate(new_cert) + print('') + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description=__doc__.split('\n\n')[0]) + parser.add_argument('-w', '--write', action='store_true', + help='Write new certificates besides printing changes.') + parser.add_argument('-r', '--recursive', action='store_true', + help='Recurse into directories.') + parser.add_argument('--reverse', action='store_true', + help='Replaces with the problematic certificate') + parser.add_argument('-v', '--verbose', action='store_true', + help='Be verbose, print skipped files') + parser.add_argument('files', metavar='file', nargs='*', + help='PEM-encoded certificate files') + parser.add_argument('--certificates', action='store_true', + help='Print certificates and exit') + args = parser.parse_args() + + if args.certificates: + print_certificates() + else: + if not args.files: + parser.error('At least one PEM file is required') + main(args) -- cgit v1.2.1