diff --git a/scripts/DumpWeakCerts.pl b/scripts/DumpWeakCerts.pl new file mode 100644 index 0000000..85648fe --- /dev/null +++ b/scripts/DumpWeakCerts.pl @@ -0,0 +1,179 @@ +#!/usr/bin/perl +# Script to dump weak RSA certs (Exponent 3 or Modulus size < 1024) according to https://bugs.cacert.org/view.php?id=918 +# and https://wiki.cacert.org/Arbitrations/a20110312.1 + +use strict; +use warnings; + +use DBI; + +my $cacert_db_config; +my $cacert_db_user; +my $cacert_db_password; + +# Read database access data from the config file +eval `cat perl_mysql`; + +my $dbh = DBI->connect($cacert_db_config, $cacert_db_user, $cacert_db_password, { RaiseError => 1, AutoCommit => 0 } ) || die "Cannot connect database: $DBI::errstr"; + +my $sth_certs; +my $sth_userdata; + +my $cert_domid; +my $cert_userid; +my $cert_orgid; +my $cert_CN; +my $cert_expire; +my $cert_filename; +my $cert_serial; + +my $user_email; +my $user_firstname; + +my $reason; + +my @row; + +sub IsWeak($) { + my ($CertFileName) = @_; + + my $ModulusSize = 0; + my $Exponent = 0; + my $result = 0; + + # Do key size and exponent checking for RSA keys + open(CERTTEXT, '-|', "openssl x509 -in $CertFileName -noout -text") || die "Cannot start openssl"; + while () { + if (/^ +([^ ]+) Public Key:/) { + last if ($1 ne "RSA"); + } + if (/^ +Modulus \((\d+) bit\)/) { + $ModulusSize = $1; + } + if (/^ +Exponent: (\d+)/) { + $Exponent = $1; + last; + } + } + close(CERTTEXT); + if ($ModulusSize > 0 && $Exponent > 0) { + if ($ModulusSize < 1024 || $Exponent==3) { + $result = "SmallKey"; + } + } + + if (!$result) { + # Check with openssl-vulnkey + # This is currently not tested, if you don't know what you are doing leave it commented! + if (system("openssl-vulnkey -q $CertFileName") != 0) { + $result = "openssl-vulnkey"; + } + } + + return $result; +} + +# Select only certificates expiring in more than two weeks, since two weeks will probably be needed as turnaround time +# Get all domain certificates +$sth_certs = $dbh->prepare( + "SELECT `dc`.`domid`, `dc`.`CN`, `dc`.`expire`, `dc`.`crt_name`, `dc`.`serial` ". + " FROM `domaincerts` AS `dc` ". + " WHERE `dc`.`revoked`=0 AND `dc`.`expire` > DATE_ADD(NOW(), INTERVAL 14 DAY)"); +$sth_certs->execute(); + +$sth_userdata = $dbh->prepare( + "SELECT `u`.`email`, `u`.`fname` ". + " FROM `domains` AS `d`, `users` AS `u` ". + " WHERE `d`.`memid`=`u`.`id` AND `d`.`id`=?"); + +while(($cert_domid, $cert_CN, $cert_expire, $cert_filename, $cert_serial) = $sth_certs->fetchrow_array) { + if (-f $cert_filename) { + $reason = IsWeak($cert_filename); + if ($reason) { + $sth_userdata->execute($cert_domid); + ($user_email, $user_firstname) = $sth_userdata->fetchrow_array(); + print join("\t", ('DomainCert', $user_email, $user_firstname, $cert_expire, $cert_CN, $reason, $cert_serial)). "\n"; + $sth_userdata->finish(); + } + } +} +$sth_certs->finish(); + +# Get all email certificates +$sth_certs = $dbh->prepare( + "SELECT `ec`.`memid`, `ec`.`CN`, `ec`.`expire`, `ec`.`crt_name`, `ec`.`serial` ". + " FROM `emailcerts` AS `ec` ". + " WHERE `ec`.`revoked`=0 AND `ec`.`expire` > DATE_ADD(NOW(), INTERVAL 14 DAY)"); +$sth_certs->execute(); + +$sth_userdata = $dbh->prepare( + "SELECT `u`.`email`, `u`.`fname` ". + " FROM `users` AS `u` ". + " WHERE `u`.`id`=?"); + +while(($cert_userid, $cert_CN, $cert_expire, $cert_filename, $cert_serial) = $sth_certs->fetchrow_array) { + if (-f $cert_filename) { + $reason = IsWeak($cert_filename); + if ($reason) { + $sth_userdata->execute($cert_userid); + ($user_email, $user_firstname) = $sth_userdata->fetchrow_array(); + print join("\t", ('EmailCert', $user_email, $user_firstname, $cert_expire, $cert_CN, $reason, $cert_serial)). "\n"; + $sth_userdata->finish(); + } + } +} +$sth_certs->finish(); + +# Get all Org Server certificates, notify all admins of the Org! +$sth_certs = $dbh->prepare( + "SELECT `dc`.`orgid`, `dc`.`CN`, `dc`.`expire`, `dc`.`crt_name`, `dc`.`serial` ". + " FROM `orgdomaincerts` AS `dc` ". + " WHERE `dc`.`revoked`=0 AND `dc`.`expire` > DATE_ADD(NOW(), INTERVAL 14 DAY)"); +$sth_certs->execute(); + +$sth_userdata = $dbh->prepare( + "SELECT `u`.`email`, `u`.`fname` ". + " FROM `users` AS `u`, `org` ". + " WHERE `u`.`id`=`org`.`memid` and `org`.`orgid`=?"); + +while(($cert_orgid, $cert_CN, $cert_expire, $cert_filename, $cert_serial) = $sth_certs->fetchrow_array) { + if (-f $cert_filename) { + $reason = IsWeak($cert_filename); + if ($reason) { + $sth_userdata->execute($cert_orgid); + while(($user_email, $user_firstname) = $sth_userdata->fetchrow_array()) { + print join("\t", ('OrgServerCert', $user_email, $user_firstname, $cert_expire, $cert_CN, $reason, $cert_serial)). "\n"; + } + $sth_userdata->finish(); + } + } +} +$sth_certs->finish(); + +# Get all Org Email certificates, notify all admins of the Org! +$sth_certs = $dbh->prepare( + "SELECT `ec`.`orgid`, `ec`.`CN`, `ec`.`expire`, `ec`.`crt_name`, `ec`.`serial` ". + " FROM `orgemailcerts` AS `ec` ". + " WHERE `ec`.`revoked`=0 AND `ec`.`expire` > DATE_ADD(NOW(), INTERVAL 14 DAY)"); +$sth_certs->execute(); + +$sth_userdata = $dbh->prepare( + "SELECT `u`.`email`, `u`.`fname` ". + " FROM `users` AS `u`, `org` ". + " WHERE `u`.`id`=`org`.`memid` and `org`.`orgid`=?"); + +while(($cert_orgid, $cert_CN, $cert_expire, $cert_filename, $cert_serial) = $sth_certs->fetchrow_array) { + if (-f $cert_filename) { + $reason = IsWeak($cert_filename); + if ($reason) { + $sth_userdata->execute($cert_orgid); + while(($user_email, $user_firstname) = $sth_userdata->fetchrow_array()) { + print join("\t", ('OrgEmailCert', $user_email, $user_firstname, $cert_expire, $cert_CN, $reason, $cert_serial)). "\n"; + } + $sth_userdata->finish(); + } + } +} +$sth_certs->finish(); + +$dbh->disconnect(); diff --git a/scripts/mail-weak-keys.php b/scripts/mail-weak-keys.php new file mode 100644 index 0000000..018bd64 --- /dev/null +++ b/scripts/mail-weak-keys.php @@ -0,0 +1,161 @@ +#!/usr/bin/php -q +\nReply-To: returns@cacert.org"); + } + + function SendClientMail($cert_type, $cert_email, $owner_name, $cert_expire, $cert_CN, $reason, $cert_serial, $action_date) { + $mail_text = +"Dear $owner_name, + +CAcert recently became aware that some of the certificates signed by CAcert pose a security +risk because they are backed by private keys that are vulnerable to attack. + +The security issues identified are: +Private keys with a small key size. These keys are vulnerable to brute force attack. +Private keys with an unsafe exponent. These keys are vulnerable to some specialised attacks. +Private keys generated by a compromised version of OpenSSL distributed by Debian. + +You received this email because a certificate issued to you is vulnerable: + +Client Certificate, Serial $cert_serial, expiring $cert_expire, CN $cert_CN + +To rectify the problem CAcert will revoke all vulnerable certificates (including yours) on $action_date. +CAcert will no longer accept vulnerable certificate requests for signing. In future all +client certficates must be backed by private keys with a key length at least 1024 bits +and no other known vulnerabilities. + +This means that you should replace your current certificate with a new one of acceptable strength. +If you use Firefox or Chrome, select 'Keysize: High Grade' before 'Create Certificate Request'. +If you use Internet Explorer, select 'Microsoft Strong Cryptographic Provider'. If you select an +option that generates a weak key (eg 'Microsoft Base Cryptographic Provider v1.0') your certficate +request will be rejected. + +Kind regards +CAcert Suport Team +"; + mail($cert_email, "[CAcert.org]CAcert Client Certificate - Urgent Action Required", $mail_text, "From: CAcert Support \nReply-To: returns@cacert.org"); + } + + function SendOrgServerCertMail($cert_type, $cert_email, $owner_name, $cert_expire, $cert_CN, $reason, $cert_serial, $action_date) { + $mail_text = +"Dear $owner_name, + +CAcert recently became aware that some of the certificates signed by CAcert pose a security +risk because they are backed by private keys that are vulnerable to attack. + +The security issues identified are: +Private keys with a small key size. These keys are vulnerable to brute force attack. +Private keys with an unsafe exponent. These keys are vulnerable to some specialised attacks. +Private keys generated by a compromised version of OpenSSL distributed by Debian. + +You received this email because a certificate issued to you is vulnerable: + +Organisation Server Certificate, Serial $cert_serial, expiring $cert_expire, CN $cert_CN + +To rectify the problem CAcert will revoke all vulnerable certificates (including yours) on $action_date. +CAcert will no longer accept vulnerable certificate requests for signing. In future all Certficate +Signing Requests must be backed by private keys with a key length at least 2048 bits and no other known vulnerabilities. + +You should submit a new Certificate Signing Request of acceptable strength as soon as possible +and replace your existing certificate. + +If you are interested in background information on this change please refer to this document: +http://csrc.nist.gov/publications/nistpubs/800-78-3/sp800-78-3.pdf + +Kind regards +CAcert Suport Team +"; + mail($cert_email, "[CAcert.org]CAcert Organisation Server Certificate - Urgent Action Required", $mail_text, "From: CAcert Support \nReply-To: returns@cacert.org"); + } + + function SendOrgClientMail($cert_type, $cert_email, $owner_name, $cert_expire, $cert_CN, $reason, $cert_serial, $action_date) { + $mail_text = +"Dear $owner_name, + +CAcert recently became aware that some of the certificates signed by CAcert pose a security +risk because they are backed by private keys that are vulnerable to attack. + +The security issues identified are: +Private keys with a small key size. These keys are vulnerable to brute force attack. +Private keys with an unsafe exponent. These keys are vulnerable to some specialised attacks. +Private keys generated by a compromised version of OpenSSL distributed by Debian. + +You received this email because a certificate issued to you is vulnerable: + +Organisation Client Certificate, Serial $cert_serial, expiring $cert_expire, CN $cert_CN + +To rectify the problem CAcert will revoke all vulnerable certificates (including yours) on $action_date. +CAcert will no longer accept vulnerable certificate requests for signing. In future all +client certficates must be backed by private keys with a key length at least 1024 bits +and no other known vulnerabilities. + +This means that you should replace your current certificate with a new one of acceptable strength. +If you use Firefox or Chrome, select 'Keysize: High Grade' before 'Create Certificate Request'. +If you use Internet Explorer, select 'Microsoft Strong Cryptographic Provider'. If you select an +option that generates a weak key (eg 'Microsoft Base Cryptographic Provider v1.0') your certficate +request will be rejected. + +Kind regards +CAcert Suport Team +"; + mail($cert_email, "[CAcert.org]CAcert Organisation Client Certificate - Urgent Action Required", $mail_text, "From: CAcert Support \nReply-To: returns@cacert.org"); + } + + # Main + + $num_domain = 0; + $num_client = 0; + $num_orgdomain = 0; + $num_orgclient = 0; + $action_date = '2011-04-??'; + $in = fopen("php://stdin", "r"); + while($in_string = rtrim(fgets($in, 255))) { + list($cert_type, $cert_email, $owner_name, $cert_expire, $cert_CN, $reason, $cert_serial) = explode("\t", $in_string); + + if ($cert_type == "DomainCert") { + SendServerCertMail($cert_type, $cert_email, $owner_name, $cert_expire, $cert_CN, $reason, $cert_serial, $action_date); + $num_domain++; + } else if ($cert_type == "EmailCert") { + SendClientMail($cert_type, $cert_email, $owner_name, $cert_expire, $cert_CN, $reason, $cert_serial, $action_date); + $num_client++; + } else if ($cert_type == "OrgServerCert") { + SendOrgServerCertMail($cert_type, $cert_email, $owner_name, $cert_expire, $cert_CN, $reason, $cert_serial, $action_date); + $num_orgdomain++; + } else if ($cert_type == "OrgEmailCert") { + SendOrgClientMail($cert_type, $cert_email, $owner_name, $cert_expire, $cert_CN, $reason, $cert_serial, $action_date); + $num_orgclient++; + } + } + fclose($in); + echo "Mails sent: $num_domain server certs, $num_client client certs, $num_orgdomain Org server certs, $num_orgclient Org client certs.\n"; +?> diff --git a/scripts/perl_mysql.sample b/scripts/perl_mysql.sample new file mode 100644 index 0000000..4800289 --- /dev/null +++ b/scripts/perl_mysql.sample @@ -0,0 +1,6 @@ +# This file contains the data needed to connect to the database to be +# used in perl scripts + +$cacert_db_config = 'DBI:mysql:database=cacert;host=127.0.0.1'; +$cacert_db_user = 'cacert'; +$cacert_db_password = ''; \ No newline at end of file