Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Allow several certificates with the same public key
Backported fix for NB#223086 from Harmattan. Verisign has
issued two different versions of two of their roots (public
key fingerprints 00d85a4c25c12... and f3a27298eeb81...) that
use the same public keys. This fix is needed to have both
versions in the common-ca.
  • Loading branch information
Juhani Mäkelä committed Sep 2, 2011
1 parent 5a3e67d commit 5b66292
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 57 deletions.
10 changes: 6 additions & 4 deletions etc/secure/s/certman.common-ca
@@ -1,3 +1,4 @@
c4aa8c223c6b54807b69dad0096ac6716e693656 */etc/certs/common-ca/00d85a4c25c122e58b31ef6dbaf3cc5f29f10d61-1.pem
92e109791674722d1c2d12af81a512a8b9ba32e5 */etc/certs/common-ca/00d85a4c25c122e58b31ef6dbaf3cc5f29f10d61.pem
03e0b79c05a92a953e17fa223e79959424780168 */etc/certs/common-ca/00f92ac34191b6c9c2b83e55f2c0971113a00720.pem
5bf2c97581d93cb79732334d4ef5777439f0a87f */etc/certs/common-ca/03252fde6f82013a5c2cdc2ba169b567d48cd3fd.pem
Expand Down Expand Up @@ -143,11 +144,12 @@ b90532984059d385c1bed7ce35073b38e443a8b0 */etc/certs/common-ca/eedd79c0d379b04d7
b6ac90234f72582580ce77395afac680a51f86c1 */etc/certs/common-ca/f0115c20abf0d0fe3d0842ef9571e372c11c1256.pem
18f5a50c3fe7da37693a4325fba9f17f95c9d3d7 */etc/certs/common-ca/f18ab43c6a02bfd8228c7965cf88f4abbc180aa6.pem
c85dd47ad4764e2aaf33e28b676fb5038c0568a8 */etc/certs/common-ca/f2c013e082433efbee2f673296355cdbb8cb02d0.pem
85840f86cfae6c8e9a8451c914ed0c7a77d173e0 */etc/certs/common-ca/f3a27298eeb81b82801c4db69a3027990a2f72e2-1.pem
ccfc9c432014816ec5fced905795455daacde9b8 */etc/certs/common-ca/f3a27298eeb81b82801c4db69a3027990a2f72e2.pem
6a885e59bc986c4e28f76a632700b1c5ae47b9bd */etc/certs/common-ca/f924ac0fb2b5f879c0fa60881bc4d94d029e1719.pem
7b35ecfbc1933c9cf33d35343701747042b0326b */etc/certs/common-ca/fba33b6ec137e95605da491620a39e0aa16287c7.pem
SIGNATURE:
e737c0d7192b01092347ebe2860f976b33724df91c1a086c31cc36cbf07653f7
3f5bf584154e206a76c5481e203acafdc79ebf2d806f234b9127e92486779040
fed3452c4aea74074702bbc45df860da1f56e011f2d62fb0dd2acd71fd8a76fa
7dc126758cdb41c4989aec83555c0d55bb1276aa03979dd145b5c09d5b2e2e60
c6021ff6cf32f5529f768b1690568eec141f656a3f93f460d72c7023883ab733
078c1515dbe25d5f4efdbe1dac9503241a09b740c514e09673774327f1a0ef07
4344eb9710b052ec80dd351954ba1af343740ac5363186d31621ae6f3cdfac04
a3f07d37229d40dcb0f929629ea728c44cd01d72cee6a3f76f26be7ee544cd06
170 changes: 117 additions & 53 deletions lib/certman/certman_main.cpp
Expand Up @@ -346,38 +346,6 @@ remove_spec_chars(char* in_string)
}


/*
* Make a unique filename for each certificate
*/
static void
make_unique_filename(X509* of_cert, const char* in_dir, string& to_string)
{
const char* c;
char nbuf[1024], *name;
long serial;
int rc;
struct stat fs;

to_string.assign(in_dir);
to_string.append(PATH_SEP);
maemosec_key_id key_id;
if (0 == maemosec_certman_get_key_id(of_cert, key_id)) {
append_hex(to_string, key_id, MAEMOSEC_KEY_ID_LEN);
to_string.append(".pem");
} else {
MAEMOSEC_ERROR("Cannot get key id out of certificate");
goto failed;
}

ok:
MAEMOSEC_DEBUG(1, "=> %s", to_string.c_str());
return;

failed:
;
}


static void
hex_to_key_id(const char* hstring, unsigned char* to_id)
{
Expand All @@ -401,17 +369,81 @@ load_cert_from_file(const char* from_file)

fp = fopen(from_file, "r");
if (!fp) {
fprintf(stderr, "Cannot read '%s' (%d)\n", from_file, errno);
MAEMOSEC_ERROR("%s: Cannot read '%s' (%d)\n", __func__, from_file, errno);
return(0);
}
cert = PEM_read_X509(fp, NULL, 0, NULL);
if (!cert) {
fprintf(stderr, "Cannot read certificate from '%s'\n", from_file);
MAEMOSEC_ERROR("%s: Cannot read certificate from '%s'\n", from_file);
}
fclose(fp);
return(cert);
}


/*
* Make a unique filename for each certificate
*/
static bool
make_unique_filename(X509* of_cert, struct local_domain* in_domain, string& to_string)
{
bool result = true;
maemosec_key_id key_id;
char nickname[255];

to_string.assign(in_domain->dirname.c_str());
to_string.append(PATH_SEP);
if (NULL == of_cert ||
0 != maemosec_certman_get_nickname(of_cert, nickname, sizeof(nickname)))
{
MAEMOSEC_ERROR("%s: invalid parameter", __func__);
return false;
}
MAEMOSEC_DEBUG(1, "%s: for '%s'", __func__, nickname);

if (0 != maemosec_certman_get_key_id(of_cert, key_id)) {
MAEMOSEC_ERROR("Cannot get key id out of certificate");
return false;
}

for (int i = 0; result && i < 1000 ; i++) {
string test_name;
test_name.assign(to_string);
append_hex(test_name, key_id, MAEMOSEC_KEY_ID_LEN);
if (0 < i) {
char onbr[10];
sprintf(onbr, "-%d", i);
test_name.append(onbr);
}
test_name.append(".pem");
MAEMOSEC_DEBUG(1, "%s: testing '%s'", __func__, test_name.c_str());
if (in_domain->index->contains_file(test_name.c_str())) {
X509* ocert = load_cert_from_file(test_name.c_str());
if (NULL != ocert) {
if (0 == X509_cmp(of_cert, ocert)) {
MAEMOSEC_DEBUG(1, "%s: domain '%s' already contains equal certificate",
__func__, in_domain->index->name());
to_string.assign(test_name);
result = false;
} else {
MAEMOSEC_DEBUG(1, "%s: domain '%s' contains same key but different cert",
__func__, in_domain->index->name());
}
X509_free(ocert);
} else {
to_string.assign(test_name);
break;
}
} else {
to_string.assign(test_name);
break;
}
}
MAEMOSEC_DEBUG(1, "%s: %s (%s)", __func__, to_string.c_str(), result?"ok":"duplicate");
return result;
}


#define MAX_TRIES 100

typedef enum hash_status {hash_not_exists, hash_already_exists, hash_error};
Expand Down Expand Up @@ -990,7 +1022,8 @@ extern "C" {
}
#endif

make_unique_filename(cert, mydomain->dirname.c_str(), filename);
if (!make_unique_filename(cert, mydomain, filename))
return(EEXIST);

to_file = fopen(filename.c_str(), "w+");
if (to_file) {
Expand Down Expand Up @@ -1051,10 +1084,12 @@ extern "C" {
if (X509_LU_X509 == obj->type) {
rc = maemosec_certman_add_cert
(to_domain, obj->data.x509);
if (0 == rc)
if (0 == rc) {
added++;
else
} else {
MAEMOSEC_ERROR("Failed to add a certificate");
errno = rc;
}
}
}
} else {
Expand All @@ -1072,9 +1107,9 @@ extern "C" {
maemosec_certman_rm_cert(domain_handle from_domain,
maemosec_key_id key_id)
{
int pos, rc;
string filename;
struct local_domain* mydomain = (struct local_domain*)from_domain;
int removed = 0;

AUTOINIT;

Expand All @@ -1087,21 +1122,50 @@ extern "C" {
filename = mydomain->dirname;
filename.append(PATH_SEP);
append_hex(filename, key_id, MAEMOSEC_KEY_ID_LEN);
filename.append(".pem");
if (mydomain->index->contains_file(filename.c_str())) {
MAEMOSEC_DEBUG(1, "Remove cert file '%s'", filename.c_str());
mydomain->index->remove_file(filename.c_str());
rm_openssl_hash_file(mydomain->dirname.c_str(), filename.c_str());
unlink(filename.c_str());
/*
* TODO: Never remove keys in case it is used for another
* purpose. Must be fixed by checking other domains.
*/
// remove_key_file(key_id);
mydomain->index->commit();
return(0);
} else
return(ENOENT);
for (int i = 0; i < 1000; i++) {
string test_name(filename);
if (0 < i) {
char onbr[10];
sprintf(onbr, "-%d", i);
test_name.append(onbr);
}
test_name.append(".pem");
if (mydomain->index->contains_file(test_name.c_str())) {
MAEMOSEC_DEBUG(1, "Remove cert file '%s'", test_name.c_str());
mydomain->index->remove_file(test_name.c_str());
if (0 == mydomain->index->contains_file(test_name.c_str())) {
removed++;
if (0 != unlink(test_name.c_str())) {
if (0 == errno)
errno = EACCES;
break;
}
errno = 0;
} else {
MAEMOSEC_DEBUG(1, "%s: couldn't remove '%s' (%s)",
__func__, test_name.c_str(), strerror(errno));
return errno;
}
} else {
/* No such file
*/
break;
}
}

if (0 == removed) {
if (0 == errno)
return ENOENT;
else
return errno;
}

/* TODO: Never remove keys in case it is used for another
* purpose. Must be fixed by checking other domains.
*/
// remove_key_file(key_id);
mydomain->index->commit();
return(0);
}


Expand Down

0 comments on commit 5b66292

Please sign in to comment.