diff options
Diffstat (limited to 'Swiften/TLS/Schannel/SchannelCertificate.cpp')
-rw-r--r-- | Swiften/TLS/Schannel/SchannelCertificate.cpp | 290 |
1 files changed, 148 insertions, 142 deletions
diff --git a/Swiften/TLS/Schannel/SchannelCertificate.cpp b/Swiften/TLS/Schannel/SchannelCertificate.cpp index 8aaec00..23c2479 100644 --- a/Swiften/TLS/Schannel/SchannelCertificate.cpp +++ b/Swiften/TLS/Schannel/SchannelCertificate.cpp @@ -4,6 +4,12 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2016 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + #include "Swiften/TLS/Schannel/SchannelCertificate.h" #include "Swiften/Base/ByteArray.h" @@ -20,176 +26,176 @@ namespace Swift { //------------------------------------------------------------------------ -SchannelCertificate::SchannelCertificate(const ScopedCertContext& certCtxt) -: m_cert(certCtxt) +SchannelCertificate::SchannelCertificate(const ScopedCertContext& certCtxt) +: m_cert(certCtxt) { - parse(); + parse(); } //------------------------------------------------------------------------ SchannelCertificate::SchannelCertificate(const ByteArray& der) { - if (!der.empty()) - { - // Convert the DER encoded certificate to a PCERT_CONTEXT - CERT_BLOB certBlob = {0}; - certBlob.cbData = der.size(); - certBlob.pbData = (BYTE*)&der[0]; - - if (!CryptQueryObject( - CERT_QUERY_OBJECT_BLOB, - &certBlob, - CERT_QUERY_CONTENT_FLAG_CERT, - CERT_QUERY_FORMAT_FLAG_ALL, - 0, - NULL, - NULL, - NULL, - NULL, - NULL, - (const void**)m_cert.Reset())) - { - // TODO: Because Swiften isn't exception safe, we have no way to indicate failure - } - } + if (!der.empty()) + { + // Convert the DER encoded certificate to a PCERT_CONTEXT + CERT_BLOB certBlob = {0}; + certBlob.cbData = der.size(); + certBlob.pbData = (BYTE*)&der[0]; + + if (!CryptQueryObject( + CERT_QUERY_OBJECT_BLOB, + &certBlob, + CERT_QUERY_CONTENT_FLAG_CERT, + CERT_QUERY_FORMAT_FLAG_ALL, + 0, + NULL, + NULL, + NULL, + NULL, + NULL, + (const void**)m_cert.Reset())) + { + // TODO: Because Swiften isn't exception safe, we have no way to indicate failure + } + } } //------------------------------------------------------------------------ -ByteArray SchannelCertificate::toDER() const +ByteArray SchannelCertificate::toDER() const { - ByteArray result; + ByteArray result; + + // Serialize the certificate. The CERT_CONTEXT is already DER encoded. + result.resize(m_cert->cbCertEncoded); + memcpy(&result[0], m_cert->pbCertEncoded, result.size()); - // Serialize the certificate. The CERT_CONTEXT is already DER encoded. - result.resize(m_cert->cbCertEncoded); - memcpy(&result[0], m_cert->pbCertEncoded, result.size()); - - return result; + return result; } //------------------------------------------------------------------------ std::string SchannelCertificate::wstrToStr(const std::wstring& wstr) { - if (wstr.empty()) - return ""; + if (wstr.empty()) + return ""; - // First request the size of the required UTF-8 buffer - int numRequiredBytes = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), wstr.size(), NULL, 0, NULL, NULL); - if (!numRequiredBytes) - return ""; + // First request the size of the required UTF-8 buffer + int numRequiredBytes = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), wstr.size(), NULL, 0, NULL, NULL); + if (!numRequiredBytes) + return ""; - // Allocate memory for the UTF-8 string - std::vector<char> utf8Str(numRequiredBytes); + // Allocate memory for the UTF-8 string + std::vector<char> utf8Str(numRequiredBytes); - int numConverted = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), wstr.size(), &utf8Str[0], numRequiredBytes, NULL, NULL); - if (!numConverted) - return ""; + int numConverted = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), wstr.size(), &utf8Str[0], numRequiredBytes, NULL, NULL); + if (!numConverted) + return ""; - std::string str(&utf8Str[0], numConverted); - return str; + std::string str(&utf8Str[0], numConverted); + return str; } //------------------------------------------------------------------------ -void SchannelCertificate::parse() +void SchannelCertificate::parse() { - // - // Subject name - // - DWORD requiredSize = CertNameToStr(X509_ASN_ENCODING, &m_cert->pCertInfo->Subject, CERT_OID_NAME_STR, NULL, 0); - if (requiredSize > 1) - { - vector<char> rawSubjectName(requiredSize); - CertNameToStr(X509_ASN_ENCODING, &m_cert->pCertInfo->Subject, CERT_OID_NAME_STR, &rawSubjectName[0], rawSubjectName.size()); - m_subjectName = std::string(&rawSubjectName[0]); - } - - // - // Common name - // - // Note: We only pull out one common name from the cert. - requiredSize = CertGetNameString(m_cert, CERT_NAME_ATTR_TYPE, 0, szOID_COMMON_NAME, NULL, 0); - if (requiredSize > 1) - { - vector<char> rawCommonName(requiredSize); - requiredSize = CertGetNameString(m_cert, CERT_NAME_ATTR_TYPE, 0, szOID_COMMON_NAME, &rawCommonName[0], rawCommonName.size()); - m_commonNames.push_back( std::string(&rawCommonName[0]) ); - } - - // - // Subject alternative names - // - PCERT_EXTENSION pExtensions = CertFindExtension(szOID_SUBJECT_ALT_NAME2, m_cert->pCertInfo->cExtension, m_cert->pCertInfo->rgExtension); - if (pExtensions) - { - CRYPT_DECODE_PARA decodePara = {0}; - decodePara.cbSize = sizeof(decodePara); - - CERT_ALT_NAME_INFO* pAltNameInfo = NULL; - DWORD altNameInfoSize = 0; - - BOOL status = CryptDecodeObjectEx( - X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - szOID_SUBJECT_ALT_NAME2, - pExtensions->Value.pbData, - pExtensions->Value.cbData, - CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, - &decodePara, - &pAltNameInfo, - &altNameInfoSize); - - if (status && pAltNameInfo) - { - for (int i = 0; i < pAltNameInfo->cAltEntry; i++) - { - if (pAltNameInfo->rgAltEntry[i].dwAltNameChoice == CERT_ALT_NAME_DNS_NAME) - addDNSName( wstrToStr( pAltNameInfo->rgAltEntry[i].pwszDNSName ) ); - } - } - } - - // if (pExtensions) - // { - // vector<wchar_t> subjectAlt - // CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, szOID_SUBJECT_ALT_NAME, pExtensions->Value->pbData, pExtensions->Value->cbData, ) - // } - // - // // subjectAltNames - // int subjectAltNameLoc = X509_get_ext_by_NID(cert.get(), NID_subject_alt_name, -1); - // if(subjectAltNameLoc != -1) { - // X509_EXTENSION* extension = X509_get_ext(cert.get(), subjectAltNameLoc); - // boost::shared_ptr<GENERAL_NAMES> generalNames(reinterpret_cast<GENERAL_NAMES*>(X509V3_EXT_d2i(extension)), GENERAL_NAMES_free); - // boost::shared_ptr<ASN1_OBJECT> xmppAddrObject(OBJ_txt2obj(ID_ON_XMPPADDR_OID, 1), ASN1_OBJECT_free); - // boost::shared_ptr<ASN1_OBJECT> dnsSRVObject(OBJ_txt2obj(ID_ON_DNSSRV_OID, 1), ASN1_OBJECT_free); - // for (int i = 0; i < sk_GENERAL_NAME_num(generalNames.get()); ++i) { - // GENERAL_NAME* generalName = sk_GENERAL_NAME_value(generalNames.get(), i); - // if (generalName->type == GEN_OTHERNAME) { - // OTHERNAME* otherName = generalName->d.otherName; - // if (OBJ_cmp(otherName->type_id, xmppAddrObject.get()) == 0) { - // // XmppAddr - // if (otherName->value->type != V_ASN1_UTF8STRING) { - // continue; - // } - // ASN1_UTF8STRING* xmppAddrValue = otherName->value->value.utf8string; - // addXMPPAddress(ByteArray(ASN1_STRING_data(xmppAddrValue), ASN1_STRING_length(xmppAddrValue)).toString()); - // } - // else if (OBJ_cmp(otherName->type_id, dnsSRVObject.get()) == 0) { - // // SRVName - // if (otherName->value->type != V_ASN1_IA5STRING) { - // continue; - // } - // ASN1_IA5STRING* srvNameValue = otherName->value->value.ia5string; - // addSRVName(ByteArray(ASN1_STRING_data(srvNameValue), ASN1_STRING_length(srvNameValue)).toString()); - // } - // } - // else if (generalName->type == GEN_DNS) { - // // DNSName - // addDNSName(ByteArray(ASN1_STRING_data(generalName->d.dNSName), ASN1_STRING_length(generalName->d.dNSName)).toString()); - // } - // } - // } + // + // Subject name + // + DWORD requiredSize = CertNameToStr(X509_ASN_ENCODING, &m_cert->pCertInfo->Subject, CERT_OID_NAME_STR, NULL, 0); + if (requiredSize > 1) + { + vector<char> rawSubjectName(requiredSize); + CertNameToStr(X509_ASN_ENCODING, &m_cert->pCertInfo->Subject, CERT_OID_NAME_STR, &rawSubjectName[0], rawSubjectName.size()); + m_subjectName = std::string(&rawSubjectName[0]); + } + + // + // Common name + // + // Note: We only pull out one common name from the cert. + requiredSize = CertGetNameString(m_cert, CERT_NAME_ATTR_TYPE, 0, szOID_COMMON_NAME, NULL, 0); + if (requiredSize > 1) + { + vector<char> rawCommonName(requiredSize); + requiredSize = CertGetNameString(m_cert, CERT_NAME_ATTR_TYPE, 0, szOID_COMMON_NAME, &rawCommonName[0], rawCommonName.size()); + m_commonNames.push_back( std::string(&rawCommonName[0]) ); + } + + // + // Subject alternative names + // + PCERT_EXTENSION pExtensions = CertFindExtension(szOID_SUBJECT_ALT_NAME2, m_cert->pCertInfo->cExtension, m_cert->pCertInfo->rgExtension); + if (pExtensions) + { + CRYPT_DECODE_PARA decodePara = {0}; + decodePara.cbSize = sizeof(decodePara); + + CERT_ALT_NAME_INFO* pAltNameInfo = NULL; + DWORD altNameInfoSize = 0; + + BOOL status = CryptDecodeObjectEx( + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + szOID_SUBJECT_ALT_NAME2, + pExtensions->Value.pbData, + pExtensions->Value.cbData, + CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, + &decodePara, + &pAltNameInfo, + &altNameInfoSize); + + if (status && pAltNameInfo) + { + for (int i = 0; i < pAltNameInfo->cAltEntry; i++) + { + if (pAltNameInfo->rgAltEntry[i].dwAltNameChoice == CERT_ALT_NAME_DNS_NAME) + addDNSName( wstrToStr( pAltNameInfo->rgAltEntry[i].pwszDNSName ) ); + } + } + } + + // if (pExtensions) + // { + // vector<wchar_t> subjectAlt + // CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, szOID_SUBJECT_ALT_NAME, pExtensions->Value->pbData, pExtensions->Value->cbData, ) + // } + // + // // subjectAltNames + // int subjectAltNameLoc = X509_get_ext_by_NID(cert.get(), NID_subject_alt_name, -1); + // if(subjectAltNameLoc != -1) { + // X509_EXTENSION* extension = X509_get_ext(cert.get(), subjectAltNameLoc); + // std::shared_ptr<GENERAL_NAMES> generalNames(reinterpret_cast<GENERAL_NAMES*>(X509V3_EXT_d2i(extension)), GENERAL_NAMES_free); + // std::shared_ptr<ASN1_OBJECT> xmppAddrObject(OBJ_txt2obj(ID_ON_XMPPADDR_OID, 1), ASN1_OBJECT_free); + // std::shared_ptr<ASN1_OBJECT> dnsSRVObject(OBJ_txt2obj(ID_ON_DNSSRV_OID, 1), ASN1_OBJECT_free); + // for (int i = 0; i < sk_GENERAL_NAME_num(generalNames.get()); ++i) { + // GENERAL_NAME* generalName = sk_GENERAL_NAME_value(generalNames.get(), i); + // if (generalName->type == GEN_OTHERNAME) { + // OTHERNAME* otherName = generalName->d.otherName; + // if (OBJ_cmp(otherName->type_id, xmppAddrObject.get()) == 0) { + // // XmppAddr + // if (otherName->value->type != V_ASN1_UTF8STRING) { + // continue; + // } + // ASN1_UTF8STRING* xmppAddrValue = otherName->value->value.utf8string; + // addXMPPAddress(ByteArray(ASN1_STRING_data(xmppAddrValue), ASN1_STRING_length(xmppAddrValue)).toString()); + // } + // else if (OBJ_cmp(otherName->type_id, dnsSRVObject.get()) == 0) { + // // SRVName + // if (otherName->value->type != V_ASN1_IA5STRING) { + // continue; + // } + // ASN1_IA5STRING* srvNameValue = otherName->value->value.ia5string; + // addSRVName(ByteArray(ASN1_STRING_data(srvNameValue), ASN1_STRING_length(srvNameValue)).toString()); + // } + // } + // else if (generalName->type == GEN_DNS) { + // // DNSName + // addDNSName(ByteArray(ASN1_STRING_data(generalName->d.dNSName), ASN1_STRING_length(generalName->d.dNSName)).toString()); + // } + // } + // } } //------------------------------------------------------------------------ |