/////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002-2025, Open Design Alliance (the "Alliance"). // All rights reserved. // // This software and its documentation and related materials are owned by // the Alliance. The software may only be incorporated into application // programs owned by members of the Alliance, subject to a signed // Membership Agreement and Supplemental Software License Agreement with the // Alliance. The structure and organization of this software are the valuable // trade secrets of the Alliance and its suppliers. The software is also // protected by copyright law and international treaty provisions. Application // programs incorporating this software must include the following statement // with their copyright notices: // // This application incorporates Open Design Alliance software pursuant to a license // agreement with Open Design Alliance. // Open Design Alliance Copyright (C) 2002-2025 by Open Design Alliance. // All rights reserved. // // By use of this software, its documentation or related materials, you // acknowledge and accept the above terms. /////////////////////////////////////////////////////////////////////////////// #include "OdAlternativeCertificateStoreOpenSSLImpl.h" #include "OdCryptoServices/OdCertificateObjectImpl.h" #include #include #include #include #include "RxObjectImpl.h" FIRSTDLL_EXPORT OdStringArray findFilesInDir(const OdString& dirPath, const OdString& fileExtension = OdString::kEmpty); ODRX_CONS_DEFINE_MEMBERS(OdAlternativeCertificateStoreOpenSSLImpl, OdAlternativeCertificateStore, RXIMPL_CONSTR); OdAlternativeCertificateStoreOpenSSLImpl::OdAlternativeCertificateStoreOpenSSLImpl() : m_allowSelfSignedCerts(false) { } OdAlternativeCertificateStoreOpenSSLImpl::~OdAlternativeCertificateStoreOpenSSLImpl() { } EVP_PKEY* OdAlternativeCertificateStoreOpenSSLImpl::loadPrivateKeyForCert(X509* cert, const OdStringArray& privateKeyFiles) const { for (OdUInt32 i = 0; i < privateKeyFiles.size(); ++i) { const OdString& keyFile = privateKeyFiles[i]; BIO* keyBIO = BIO_new_file((const char*)keyFile, "rb"); if (!keyBIO) continue; EVP_PKEY* pkey = PEM_read_bio_PrivateKey(keyBIO, NULL, NULL, NULL); BIO_free(keyBIO); if (!pkey) continue; if (X509_check_private_key(cert, pkey) == 1) return pkey; EVP_PKEY_free(pkey); } return NULL; } bool OdAlternativeCertificateStoreOpenSSLImpl::certHasPrivateKey(X509* cert, const OdStringArray& privateKeyFiles) const { EVP_PKEY* pkey = loadPrivateKeyForCert(cert, privateKeyFiles); if (pkey) { EVP_PKEY_free(pkey); return true; } return false; } bool OdAlternativeCertificateStoreOpenSSLImpl::certIsTrustedByStore(X509* cert) const { X509_STORE* store = X509_STORE_new(); if (!store) return false; bool loaded = false; if (!m_caBundleFile.isEmpty()) { OdAnsiString caBundle((const char*)m_caBundleFile); loaded = (X509_STORE_load_locations(store, caBundle.c_str(), NULL) == 1); } else if (!m_caDirectory.isEmpty()) { OdAnsiString caDir((const char*)m_caDirectory); loaded = (X509_STORE_load_locations(store, NULL, caDir.c_str()) == 1); } if (!loaded) { X509_STORE_free(store); return false; } X509_STORE_CTX* ctx = X509_STORE_CTX_new(); if (!ctx) { X509_STORE_free(store); return false; } int ok = X509_STORE_CTX_init(ctx, store, cert, NULL); bool trusted = false; if (ok == 1 && X509_verify_cert(ctx) == 1) trusted = true; X509_STORE_CTX_free(ctx); X509_STORE_free(store); return trusted; } bool OdAlternativeCertificateStoreOpenSSLImpl::matchesShortDesc(OdCertificateObjectPtr pCert, const OdCertificateShortDesc& desc) const { bool res = false; OdCertificateDescription certDesc = pCert->getCertDescription(); if ((certDesc.m_CertSubject == desc.m_CertSubject) && (certDesc.m_CertIssuer == desc.m_CertIssuer)) { OdAnsiString buf2(certDesc.m_CertSerialNum.c_str(), CP_UTF_8); OdAnsiString buf1(desc.m_CertSerialNum.c_str(), CP_UTF_8); BIGNUM* bn2 = NULL; bn2 = BN_new(); BN_hex2bn(&bn2, buf2.c_str()); BIGNUM* bn1 = NULL; bn1 = BN_new(); BN_hex2bn(&bn1, buf1.c_str()); int cmpResult = BN_cmp(bn2, bn1); BN_free(bn1); BN_free(bn2); if (cmpResult == 0) { res = true; } } return res; } OdUInt32 OdAlternativeCertificateStoreOpenSSLImpl::getPersonalCertsWithTrustedStatus(OdArray& certificates) const { OdStringArray certFiles; OdStringArray keyFiles; certFiles = findFilesInDir(m_certsDir, OD_T("pem")); keyFiles = findFilesInDir(m_privateKeysDir, OD_T("pem")); OdUInt32 result = 0; for (OdUInt32 i = 0; i < certFiles.size(); ++i) { BIO* certBIO = BIO_new_file((const char*)certFiles[i], "rb"); if (!certBIO) continue; X509* cert = PEM_read_bio_X509(certBIO, NULL, NULL, NULL); BIO_free(certBIO); if (!cert) continue; if (certHasPrivateKey(cert, keyFiles)) { bool trusted = certIsTrustedByStore(cert); if (m_allowSelfSignedCerts || trusted) { OdCertificateObjectPtr obj = new OdCertificateObjectImpl(cert); OdCertificateDescription desc = obj->getCertDescription(); certificates.push_back(desc); result++; } } X509_free(cert); } return result; } OdCertificateObjectPtr OdAlternativeCertificateStoreOpenSSLImpl::getCertObjByShortDesc(const OdCertificateShortDesc& certShortDesc) const { OdStringArray certFiles; OdStringArray keyFiles; certFiles = findFilesInDir(m_certsDir, OD_T("pem")); keyFiles = findFilesInDir(m_privateKeysDir, OD_T("pem")); for (OdUInt32 i = 0; i < certFiles.size(); ++i) { BIO* certBIO = BIO_new_file((const char*)certFiles[i], "rb"); if (!certBIO) continue; X509* cert = PEM_read_bio_X509(certBIO, NULL, NULL, NULL); BIO_free(certBIO); if (!cert) continue; if (certHasPrivateKey(cert, keyFiles)) { OdCertificateObjectPtr obj = new OdCertificateObjectImpl(cert); if (matchesShortDesc(obj, certShortDesc)) { bool trusted = certIsTrustedByStore(cert); if (m_allowSelfSignedCerts || trusted) { X509_free(cert); return obj; } } } X509_free(cert); } return NULL; } bool OdAlternativeCertificateStoreOpenSSLImpl::isTrusted(OdCertificateObjectPtr cert) const { X509* x509 = NULL; if (!cert.isNull()) { x509 = ((OdCertificateObjectImpl*)(cert.get()))->getX509Cert(); } if (!x509) return false; bool trusted = certIsTrustedByStore(x509); return trusted; } void OdAlternativeCertificateStoreOpenSSLImpl::setCertsDirectory(const OdString& dir) { m_certsDir = dir; } OdString OdAlternativeCertificateStoreOpenSSLImpl::certsDirectory() const { return m_certsDir; } void OdAlternativeCertificateStoreOpenSSLImpl::setPrivateKeysDirectory(const OdString& dir) { m_privateKeysDir = dir; } OdString OdAlternativeCertificateStoreOpenSSLImpl::privateKeysDirectory() const { return m_privateKeysDir; } void OdAlternativeCertificateStoreOpenSSLImpl::setCaDirectory(const OdString& dir) { m_caDirectory = dir; } OdString OdAlternativeCertificateStoreOpenSSLImpl::caDirectory() const { return m_caDirectory; } void OdAlternativeCertificateStoreOpenSSLImpl::setCaBundleFile(const OdString& fullPathToCaBundle) { m_caBundleFile = fullPathToCaBundle; } OdString OdAlternativeCertificateStoreOpenSSLImpl::caBundleFile() const { return m_caBundleFile; } void OdAlternativeCertificateStoreOpenSSLImpl::setAllowSelfSignedCerts(bool allow) { m_allowSelfSignedCerts = allow; } void OdAlternativeCertificateStoreOpenSSLImpl::getAllPrivateKeyFileNames(OdStringArray& privateKeyFileNames) { privateKeyFileNames = findFilesInDir(m_privateKeysDir, OD_T("pem")); }