/* * Copyright (c) 2012 Isode Limited, London, England. * Licensed under the simplified BSD license. * See Documentation/Licenses/BSD-simplified.txt for more information. */ #include #include #define SECURITY_WIN32 #include #include #include #include #include #include #include #include namespace Swift { /////Hmm, maybe we should not exlude the "location" column #define exclude_columns CRYPTUI_SELECT_LOCATION_COLUMN | CRYPTUI_SELECT_INTENDEDUSE_COLUMN #define SHA1_HASH_LENGTH 20 static std::string getCertUri(PCCERT_CONTEXT cert, const char * cert_store_name) { DWORD cbHash = SHA1_HASH_LENGTH; BYTE aHash[SHA1_HASH_LENGTH]; std::string result("certstore:"); result += cert_store_name; result += ":sha1:"; if (CertGetCertificateContextProperty(cert, CERT_HASH_PROP_ID, aHash, &cbHash) == FALSE ) { return ""; } ByteArray byteArray = createByteArray((char *)(&aHash[0]), cbHash); result += Hexify::hexify(byteArray); return result; } std::string selectCAPICertificate() { const char* certStoreName = "MY"; DWORD storeFlags = CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER; HCERTSTORE hstore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, 0, storeFlags, certStoreName); if (!hstore) { return ""; } HWND hwnd = GetForegroundWindow(); if (!hwnd) { hwnd = GetActiveWindow(); } std::string certificateDialogTitle = QT_TRANSLATE_NOOP("", "TLS Client Certificate Selection"); std::string certificateDialogPrompt = QT_TRANSLATE_NOOP("", "Select a certificate to use for authentication"); int titleLength = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, certificateDialogTitle.c_str(), -1, NULL, 0); int promptLength = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, certificateDialogPrompt.c_str(), -1, NULL, 0); wchar_t* titleChars = new wchar_t[titleLength]; wchar_t* promptChars = new wchar_t[promptLength]; //titleChars[titleLength] = '\0'; //promptChars[promptLength] = '\0'; titleLength = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, certificateDialogTitle.c_str(), -1, titleChars, titleLength); promptLength = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, certificateDialogPrompt.c_str(), -1, promptChars, promptLength); if (titleLength == 0 || promptLength == 0) { int error = GetLastError(); switch (error) { case ERROR_INSUFFICIENT_BUFFER: SWIFT_LOG(error) << "Insufficient buffer for rendering cert dialog" << std::endl;break; case ERROR_INVALID_FLAGS: SWIFT_LOG(error) << "Invalid flags for rendering cert dialog" << std::endl;break; case ERROR_INVALID_PARAMETER: SWIFT_LOG(error) << "Invalid parameter for rendering cert dialog" << std::endl;break; case ERROR_NO_UNICODE_TRANSLATION: SWIFT_LOG(error) << "Invalid unicode for rendering cert dialog" << std::endl;break; default: SWIFT_LOG(error) << "Unexpected multibyte conversion errorcode" << std::endl; } } /* Call Windows dialog to select a suitable certificate */ PCCERT_CONTEXT cert = CryptUIDlgSelectCertificateFromStore(hstore, hwnd, titleChars, promptChars, exclude_columns, 0, NULL); delete[] titleChars; delete[] promptChars; if (hstore) { CertCloseStore(hstore, 0); } std::string result; if (cert) { result = getCertUri(cert, certStoreName); CertFreeCertificateContext(cert); } return result; } bool isCAPIURI(std::string uri) { return (boost::iequals(uri.substr(0, 10), "certstore:")); } }