summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Melnikov <alexey.melnikov@isode.com>2012-02-28 14:55:06 (GMT)
committerKevin Smith <git@kismith.co.uk>2012-02-28 16:53:39 (GMT)
commitbca7e9a19e35ca4d64b66a7b6785197d91c5bffa (patch)
tree8a52fa9a69fc415fe5e5fe0fa82d4d8d2334683b
parent920fa6a454e921dd0480ae2675f195382fccf32a (diff)
downloadswift-contrib-bca7e9a19e35ca4d64b66a7b6785197d91c5bffa.zip
swift-contrib-bca7e9a19e35ca4d64b66a7b6785197d91c5bffa.tar.bz2
Changed certstore: URIs to use SHA1 hashes of certificates
Value of the certificate's subject DN leftmost RDN is not necessarily unique. This change switches to using SHA1 hash of DER certificates, which should guaranty uniqueness. License: This patch is BSD-licensed, see Documentation/Licenses/BSD-simplified.txt for details.
-rw-r--r--Swift/QtUI/CAPICertificateSelector.cpp69
-rw-r--r--Swiften/TLS/CAPICertificate.cpp57
2 files changed, 59 insertions, 67 deletions
diff --git a/Swift/QtUI/CAPICertificateSelector.cpp b/Swift/QtUI/CAPICertificateSelector.cpp
index aa41d70..e7948ef 100644
--- a/Swift/QtUI/CAPICertificateSelector.cpp
+++ b/Swift/QtUI/CAPICertificateSelector.cpp
@@ -13,6 +13,7 @@
#include <WinCrypt.h>
#include <cryptuiapi.h>
+#include <Swiften/StringCodecs/Hexify.h>
#include <boost/algorithm/string.hpp>
namespace Swift {
@@ -23,67 +24,23 @@ namespace Swift {
#define exclude_columns CRYPTUI_SELECT_LOCATION_COLUMN \
|CRYPTUI_SELECT_INTENDEDUSE_COLUMN
-
+// Size of the SHA1 hash
+#define SHA1_HASH_LEN 20
static std::string getCertUri(PCCERT_CONTEXT cert, const char * cert_store_name) {
- DWORD required_size;
- char * comma;
- char * p_in;
- char * p_out;
- char * subject_name;
- std::string ret = std::string("certstore:") + cert_store_name + ":";
-
- required_size = CertNameToStrA(cert->dwCertEncodingType,
- &cert->pCertInfo->Subject,
- /* Discard attribute names: */
- CERT_SIMPLE_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
- NULL,
- 0);
-
- subject_name = static_cast<char *>(malloc(required_size+1));
-
- if (!CertNameToStrA(cert->dwCertEncodingType,
- &cert->pCertInfo->Subject,
- /* Discard attribute names: */
- CERT_SIMPLE_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
- subject_name,
- required_size)) {
+ DWORD cbHash = SHA1_HASH_LEN;
+ BYTE aHash[SHA1_HASH_LEN];
+ std::string ret = std::string("certstore:") + cert_store_name + ":" + "sha1:";
+
+ if (CertGetCertificateContextProperty(cert,
+ CERT_HASH_PROP_ID,
+ aHash,
+ &cbHash) == FALSE ) {
return "";
}
- /* Now search for the "," (ignoring escapes)
- and truncate the rest of the string */
- if (subject_name[0] == '"') {
- for (comma = subject_name + 1; comma[0]; comma++) {
- if (comma[0] == '"') {
- comma++;
- if (comma[0] != '"') {
- break;
- }
- }
- }
- } else {
- comma = strchr(subject_name, ',');
- }
-
- if (comma != NULL) {
- *comma = '\0';
- }
-
- /* We now need to unescape the returned RDN */
- if (subject_name[0] == '"') {
- for (p_in = subject_name + 1, p_out = subject_name; p_in[0]; p_in++, p_out++) {
- if (p_in[0] == '"') {
- p_in++;
- }
-
- p_out[0] = p_in[0];
- }
- p_out[0] = '\0';
- }
-
- ret += subject_name;
- free(subject_name);
+ ByteArray byteArray = createByteArray((char *)(&aHash[0]));
+ ret += Hexify::hexify(byteArray);
return ret;
}
diff --git a/Swiften/TLS/CAPICertificate.cpp b/Swiften/TLS/CAPICertificate.cpp
index 9a3bbc8..a6725c9 100644
--- a/Swiften/TLS/CAPICertificate.cpp
+++ b/Swiften/TLS/CAPICertificate.cpp
@@ -6,9 +6,13 @@
#pragma once
#include <Swiften/TLS/CAPICertificate.h>
+#include <Swiften/StringCodecs/Hexify.h>
#include <boost/algorithm/string/predicate.hpp>
+// Size of the SHA1 hash
+#define SHA1_HASH_LEN 20
+
namespace Swift {
CAPICertificate::CAPICertificate(const std::string& capiUri)
@@ -34,11 +38,51 @@ const std::string& CAPICertificate::getCertName() const {
return certName_;
}
+static PCCERT_CONTEXT findCertificateInStore (HCERTSTORE certStoreHandle, const std::string &certName) {
+ PCCERT_CONTEXT pCertContext = NULL;
+
+ if (!boost::iequals(certName.substr(0, 5), "sha1:")) {
+
+ // Find client certificate. Note that this sample just searches for a
+ // certificate that contains the user name somewhere in the subject name.
+ pCertContext = CertFindCertificateInStore(certStoreHandle,
+ X509_ASN_ENCODING,
+ 0, // dwFindFlags
+ CERT_FIND_SUBJECT_STR_A,
+ certName.c_str(), // *pvFindPara
+ NULL ); // pPrevCertContext
+ return pCertContext;
+ }
+
+
+ std::string hexstring = certName.substr(5);
+ ByteArray byteArray = Hexify::unhexify(hexstring);
+ CRYPT_HASH_BLOB HashBlob;
+
+ if (byteArray.size() != SHA1_HASH_LEN) {
+ return NULL;
+ }
+ HashBlob.cbData = SHA1_HASH_LEN;
+ HashBlob.pbData = static_cast<BYTE *>(vecptr(byteArray));
+
+ // Find client certificate. Note that this sample just searches for a
+ // certificate that contains the user name somewhere in the subject name.
+ pCertContext = CertFindCertificateInStore(certStoreHandle,
+ X509_ASN_ENCODING,
+ 0, // dwFindFlags
+ CERT_FIND_HASH,
+ &HashBlob,
+ NULL ); // pPrevCertContext
+
+ return pCertContext;
+}
+
+
void CAPICertificate::setUri (const std::string& capiUri) {
valid_ = false;
- /* Syntax: "certstore:" [<cert_store> ":"] <cert_id> */
+ /* Syntax: "certstore:" <cert_store> ":" <hash> ":" <hash_of_cert> */
if (!boost::iequals(capiUri.substr(0, 10), "certstore:")) {
return;
@@ -77,16 +121,7 @@ void CAPICertificate::setUri (const std::string& capiUri) {
certStore_ = new_certStore_name;
- /* NB: This might have to change, depending on how we locate certificates */
-
- // Find client certificate. Note that this sample just searches for a
- // certificate that contains the user name somewhere in the subject name.
- pCertContext = CertFindCertificateInStore(certStoreHandle_,
- X509_ASN_ENCODING,
- 0, // dwFindFlags
- CERT_FIND_SUBJECT_STR_A,
- certName_.c_str(), // *pvFindPara
- NULL ); // pPrevCertContext
+ pCertContext = findCertificateInStore (certStoreHandle_, certName_);
if (!pCertContext) {
return;