(detection and prevention of weak keys for CAcert-issued certificates)
pull/1/head
Wytze van der Raay 13 years ago
parent 8571e6f0a9
commit a9d9139d3a

@ -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 (<CERTTEXT>) {
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();

@ -0,0 +1,161 @@
#!/usr/bin/php -q
<? # Companion script to DumpWeakCerts.pl, takes output and sends a mail to each owner of a weak cert
function SendServerCertMail($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:
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 Server Certificate - Urgent Action Required", $mail_text, "From: CAcert Support <support@cacert.org>\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 <support@cacert.org>\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 <support@cacert.org>\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 <support@cacert.org>\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";
?>

@ -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 = '<put_password_here>';
Loading…
Cancel
Save