snowflake-connector-python 4.4.0__cp314-cp314-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- snowflake/connector/__init__.py +118 -0
- snowflake/connector/_query_context_cache.py +276 -0
- snowflake/connector/_sql_util.py +48 -0
- snowflake/connector/_utils.py +353 -0
- snowflake/connector/aio/README.md +88 -0
- snowflake/connector/aio/__init__.py +163 -0
- snowflake/connector/aio/_azure_storage_client.py +227 -0
- snowflake/connector/aio/_bind_upload_agent.py +69 -0
- snowflake/connector/aio/_connection.py +1216 -0
- snowflake/connector/aio/_cursor.py +1402 -0
- snowflake/connector/aio/_description.py +5 -0
- snowflake/connector/aio/_direct_file_operation_utils.py +88 -0
- snowflake/connector/aio/_file_transfer_agent.py +316 -0
- snowflake/connector/aio/_gcs_storage_client.py +360 -0
- snowflake/connector/aio/_network.py +860 -0
- snowflake/connector/aio/_ocsp_asn1crypto.py +51 -0
- snowflake/connector/aio/_ocsp_snowflake.py +608 -0
- snowflake/connector/aio/_pandas_tools.py +561 -0
- snowflake/connector/aio/_result_batch.py +442 -0
- snowflake/connector/aio/_result_set.py +309 -0
- snowflake/connector/aio/_s3_storage_client.py +460 -0
- snowflake/connector/aio/_session_manager.py +588 -0
- snowflake/connector/aio/_storage_client.py +331 -0
- snowflake/connector/aio/_telemetry.py +97 -0
- snowflake/connector/aio/_time_util.py +57 -0
- snowflake/connector/aio/_wif_util.py +324 -0
- snowflake/connector/aio/auth/__init__.py +52 -0
- snowflake/connector/aio/auth/_auth.py +406 -0
- snowflake/connector/aio/auth/_by_plugin.py +131 -0
- snowflake/connector/aio/auth/_default.py +28 -0
- snowflake/connector/aio/auth/_idtoken.py +54 -0
- snowflake/connector/aio/auth/_keypair.py +60 -0
- snowflake/connector/aio/auth/_no_auth.py +31 -0
- snowflake/connector/aio/auth/_oauth.py +27 -0
- snowflake/connector/aio/auth/_oauth_code.py +117 -0
- snowflake/connector/aio/auth/_oauth_credentials.py +100 -0
- snowflake/connector/aio/auth/_okta.py +247 -0
- snowflake/connector/aio/auth/_pat.py +27 -0
- snowflake/connector/aio/auth/_usrpwdmfa.py +30 -0
- snowflake/connector/aio/auth/_webbrowser.py +405 -0
- snowflake/connector/aio/auth/_workload_identity.py +60 -0
- snowflake/connector/arrow_context.py +211 -0
- snowflake/connector/auth/__init__.py +53 -0
- snowflake/connector/auth/_auth.py +669 -0
- snowflake/connector/auth/_http_server.py +257 -0
- snowflake/connector/auth/_oauth_base.py +472 -0
- snowflake/connector/auth/by_plugin.py +219 -0
- snowflake/connector/auth/default.py +36 -0
- snowflake/connector/auth/idtoken.py +72 -0
- snowflake/connector/auth/keypair.py +225 -0
- snowflake/connector/auth/no_auth.py +39 -0
- snowflake/connector/auth/oauth.py +49 -0
- snowflake/connector/auth/oauth_code.py +490 -0
- snowflake/connector/auth/oauth_credentials.py +71 -0
- snowflake/connector/auth/okta.py +339 -0
- snowflake/connector/auth/pat.py +40 -0
- snowflake/connector/auth/usrpwdmfa.py +69 -0
- snowflake/connector/auth/webbrowser.py +514 -0
- snowflake/connector/auth/workload_identity.py +110 -0
- snowflake/connector/azure_storage_client.py +278 -0
- snowflake/connector/backoff_policies.py +141 -0
- snowflake/connector/bind_upload_agent.py +89 -0
- snowflake/connector/cache.py +696 -0
- snowflake/connector/compat.py +127 -0
- snowflake/connector/config_manager.py +553 -0
- snowflake/connector/connection.py +2671 -0
- snowflake/connector/connection_diagnostic.py +793 -0
- snowflake/connector/constants.py +460 -0
- snowflake/connector/converter.py +809 -0
- snowflake/connector/converter_issue23517.py +87 -0
- snowflake/connector/converter_null.py +14 -0
- snowflake/connector/converter_snowsql.py +205 -0
- snowflake/connector/crl.py +919 -0
- snowflake/connector/crl_cache.py +734 -0
- snowflake/connector/cursor.py +2099 -0
- snowflake/connector/dbapi.py +53 -0
- snowflake/connector/description.py +21 -0
- snowflake/connector/direct_file_operation_utils.py +88 -0
- snowflake/connector/encryption_util.py +220 -0
- snowflake/connector/errorcode.py +94 -0
- snowflake/connector/errors.py +666 -0
- snowflake/connector/externals_utils/__init__.py +0 -0
- snowflake/connector/externals_utils/externals_setup.py +30 -0
- snowflake/connector/feature.py +4 -0
- snowflake/connector/file_compression_type.py +118 -0
- snowflake/connector/file_lock.py +72 -0
- snowflake/connector/file_transfer_agent.py +1244 -0
- snowflake/connector/file_util.py +153 -0
- snowflake/connector/gcs_storage_client.py +476 -0
- snowflake/connector/gzip_decoder.py +85 -0
- snowflake/connector/interval_util.py +26 -0
- snowflake/connector/local_storage_client.py +90 -0
- snowflake/connector/log_configuration.py +62 -0
- snowflake/connector/logging_utils/__init__.py +0 -0
- snowflake/connector/logging_utils/filters.py +72 -0
- snowflake/connector/minicore/__init__.py +0 -0
- snowflake/connector/minicore/aix_ppc64/libsf_mini_core.a +0 -0
- snowflake/connector/minicore/aix_ppc64/libsf_mini_core_static.a +0 -0
- snowflake/connector/minicore/linux_aarch64_glibc/libsf_mini_core.so +0 -0
- snowflake/connector/minicore/linux_aarch64_musl/libsf_mini_core.so +0 -0
- snowflake/connector/minicore/linux_x86_64_glibc/libsf_mini_core.so +0 -0
- snowflake/connector/minicore/linux_x86_64_musl/libsf_mini_core.so +0 -0
- snowflake/connector/minicore/macos_aarch64/libsf_mini_core.dylib +0 -0
- snowflake/connector/minicore/macos_x86_64/libsf_mini_core.dylib +0 -0
- snowflake/connector/minicore/windows_x86_64/sf_mini_core.dll +0 -0
- snowflake/connector/minicore/windows_x86_64/sf_mini_core_static.lib +0 -0
- snowflake/connector/nanoarrow_arrow_iterator.cp314-win_amd64.pyd +0 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/ArrayConverter.cpp +60 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/ArrayConverter.hpp +29 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/BinaryConverter.cpp +19 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/BinaryConverter.hpp +26 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/BooleanConverter.cpp +21 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/BooleanConverter.hpp +23 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowChunkIterator.cpp +570 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowChunkIterator.hpp +98 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowIterator.cpp +125 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowIterator.hpp +115 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowTableIterator.cpp +1140 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/CArrowTableIterator.hpp +138 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/DateConverter.cpp +47 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/DateConverter.hpp +46 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/DecFloatConverter.cpp +83 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/DecFloatConverter.hpp +35 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/DecimalConverter.cpp +97 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/DecimalConverter.hpp +72 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.cpp +73 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/FixedSizeListConverter.hpp +28 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/FloatConverter.cpp +30 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/FloatConverter.hpp +35 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/IColumnConverter.hpp +17 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/IntConverter.cpp +23 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/IntConverter.hpp +45 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/IntervalConverter.cpp +75 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/IntervalConverter.hpp +57 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/LICENSE.txt +209 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/MapConverter.cpp +75 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/MapConverter.hpp +30 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/ObjectConverter.cpp +46 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/ObjectConverter.hpp +29 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Common.cpp +8 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Common.hpp +95 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Helpers.cpp +57 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Python/Helpers.hpp +36 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/SnowflakeType.cpp +34 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/SnowflakeType.hpp +48 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/StringConverter.cpp +19 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/StringConverter.hpp +26 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeConverter.cpp +36 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeConverter.hpp +31 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeStampConverter.cpp +346 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/TimeStampConverter.hpp +145 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/macros.hpp +14 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/time.cpp +67 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/Util/time.hpp +68 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_accessors.h +101 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_alloc.h +127 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_assert.h +45 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_builder.h +1908 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_emitter.h +215 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_endian.h +125 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_epilogue.h +7 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_flatbuffers.h +55 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_identifier.h +148 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_iov.h +31 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_prologue.h +8 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_refmap.h +144 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_rtconfig.h +162 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_types.h +97 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/flatcc_verifier.h +239 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/flatcc_portable.h +14 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/paligned_alloc.h +210 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pattributes.h +84 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic.h +84 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_pop.h +20 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pdiagnostic_push.h +51 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian.h +206 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pendian_detect.h +118 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinline.h +19 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pinttypes.h +52 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable.h +2 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/portable_basic.h +25 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstatic_assert.h +67 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdalign.h +162 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pstdint.h +898 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/punaligned.h +190 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pversion.h +6 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc/portable/pwarnings.h +52 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/flatcc.c +3204 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.c +3217 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.h +3618 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow.hpp +379 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_arrow_iterator.pyx +262 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_device.c +512 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_device.h +350 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.c +33273 -0
- snowflake/connector/nanoarrow_cpp/ArrowIterator/nanoarrow_ipc.h +397 -0
- snowflake/connector/nanoarrow_cpp/Logging/logging.cpp +100 -0
- snowflake/connector/nanoarrow_cpp/Logging/logging.hpp +49 -0
- snowflake/connector/network.py +1227 -0
- snowflake/connector/ocsp_asn1crypto.py +447 -0
- snowflake/connector/ocsp_snowflake.py +1939 -0
- snowflake/connector/options.py +179 -0
- snowflake/connector/os_details.py +88 -0
- snowflake/connector/pandas_tools.py +734 -0
- snowflake/connector/platform_detection.py +555 -0
- snowflake/connector/proxy.py +28 -0
- snowflake/connector/py.typed +0 -0
- snowflake/connector/result_batch.py +917 -0
- snowflake/connector/result_set.py +340 -0
- snowflake/connector/s3_storage_client.py +614 -0
- snowflake/connector/secret_detector.py +181 -0
- snowflake/connector/session_manager.py +650 -0
- snowflake/connector/sf_dirs.py +64 -0
- snowflake/connector/sfbinaryformat.py +35 -0
- snowflake/connector/sfdatetime.py +345 -0
- snowflake/connector/snow_logging.py +144 -0
- snowflake/connector/sqlstate.py +9 -0
- snowflake/connector/ssd_internal_keys.py +30 -0
- snowflake/connector/ssl_wrap_socket.py +281 -0
- snowflake/connector/storage_client.py +486 -0
- snowflake/connector/telemetry.py +254 -0
- snowflake/connector/telemetry_oob.py +544 -0
- snowflake/connector/test_util.py +30 -0
- snowflake/connector/time_util.py +159 -0
- snowflake/connector/token_cache.py +457 -0
- snowflake/connector/tool/__init__.py +0 -0
- snowflake/connector/tool/dump_certs.py +57 -0
- snowflake/connector/tool/dump_ocsp_response.py +139 -0
- snowflake/connector/tool/dump_ocsp_response_cache.py +194 -0
- snowflake/connector/tool/probe_connection.py +69 -0
- snowflake/connector/url_util.py +55 -0
- snowflake/connector/util_text.py +320 -0
- snowflake/connector/vendored/__init__.py +3 -0
- snowflake/connector/vendored/requests/LICENSE +175 -0
- snowflake/connector/vendored/requests/__init__.py +184 -0
- snowflake/connector/vendored/requests/__version__.py +14 -0
- snowflake/connector/vendored/requests/_internal_utils.py +50 -0
- snowflake/connector/vendored/requests/adapters.py +696 -0
- snowflake/connector/vendored/requests/api.py +157 -0
- snowflake/connector/vendored/requests/auth.py +314 -0
- snowflake/connector/vendored/requests/certs.py +17 -0
- snowflake/connector/vendored/requests/compat.py +106 -0
- snowflake/connector/vendored/requests/cookies.py +561 -0
- snowflake/connector/vendored/requests/exceptions.py +151 -0
- snowflake/connector/vendored/requests/help.py +134 -0
- snowflake/connector/vendored/requests/hooks.py +33 -0
- snowflake/connector/vendored/requests/models.py +1039 -0
- snowflake/connector/vendored/requests/packages.py +23 -0
- snowflake/connector/vendored/requests/sessions.py +831 -0
- snowflake/connector/vendored/requests/status_codes.py +128 -0
- snowflake/connector/vendored/requests/structures.py +99 -0
- snowflake/connector/vendored/requests/utils.py +1086 -0
- snowflake/connector/vendored/urllib3/LICENSE.txt +21 -0
- snowflake/connector/vendored/urllib3/__init__.py +211 -0
- snowflake/connector/vendored/urllib3/_base_connection.py +165 -0
- snowflake/connector/vendored/urllib3/_collections.py +487 -0
- snowflake/connector/vendored/urllib3/_request_methods.py +278 -0
- snowflake/connector/vendored/urllib3/_version.py +34 -0
- snowflake/connector/vendored/urllib3/connection.py +1108 -0
- snowflake/connector/vendored/urllib3/connectionpool.py +1178 -0
- snowflake/connector/vendored/urllib3/contrib/__init__.py +0 -0
- snowflake/connector/vendored/urllib3/contrib/emscripten/__init__.py +17 -0
- snowflake/connector/vendored/urllib3/contrib/emscripten/connection.py +260 -0
- snowflake/connector/vendored/urllib3/contrib/emscripten/emscripten_fetch_worker.js +110 -0
- snowflake/connector/vendored/urllib3/contrib/emscripten/fetch.py +726 -0
- snowflake/connector/vendored/urllib3/contrib/emscripten/request.py +22 -0
- snowflake/connector/vendored/urllib3/contrib/emscripten/response.py +277 -0
- snowflake/connector/vendored/urllib3/contrib/pyopenssl.py +564 -0
- snowflake/connector/vendored/urllib3/contrib/socks.py +228 -0
- snowflake/connector/vendored/urllib3/exceptions.py +335 -0
- snowflake/connector/vendored/urllib3/fields.py +341 -0
- snowflake/connector/vendored/urllib3/filepost.py +89 -0
- snowflake/connector/vendored/urllib3/http2/__init__.py +53 -0
- snowflake/connector/vendored/urllib3/http2/connection.py +356 -0
- snowflake/connector/vendored/urllib3/http2/probe.py +87 -0
- snowflake/connector/vendored/urllib3/poolmanager.py +651 -0
- snowflake/connector/vendored/urllib3/py.typed +2 -0
- snowflake/connector/vendored/urllib3/response.py +1480 -0
- snowflake/connector/vendored/urllib3/util/__init__.py +42 -0
- snowflake/connector/vendored/urllib3/util/connection.py +137 -0
- snowflake/connector/vendored/urllib3/util/proxy.py +43 -0
- snowflake/connector/vendored/urllib3/util/request.py +263 -0
- snowflake/connector/vendored/urllib3/util/response.py +101 -0
- snowflake/connector/vendored/urllib3/util/retry.py +549 -0
- snowflake/connector/vendored/urllib3/util/ssl_.py +527 -0
- snowflake/connector/vendored/urllib3/util/ssl_match_hostname.py +159 -0
- snowflake/connector/vendored/urllib3/util/ssltransport.py +271 -0
- snowflake/connector/vendored/urllib3/util/timeout.py +275 -0
- snowflake/connector/vendored/urllib3/util/url.py +469 -0
- snowflake/connector/vendored/urllib3/util/util.py +42 -0
- snowflake/connector/vendored/urllib3/util/wait.py +124 -0
- snowflake/connector/version.py +3 -0
- snowflake/connector/wif_util.py +434 -0
- snowflake_connector_python-4.4.0.dist-info/DELVEWHEEL +2 -0
- snowflake_connector_python-4.4.0.dist-info/METADATA +1591 -0
- snowflake_connector_python-4.4.0.dist-info/RECORD +302 -0
- snowflake_connector_python-4.4.0.dist-info/WHEEL +5 -0
- snowflake_connector_python-4.4.0.dist-info/entry_points.txt +4 -0
- snowflake_connector_python-4.4.0.dist-info/licenses/LICENSE.txt +202 -0
- snowflake_connector_python-4.4.0.dist-info/licenses/NOTICE +8 -0
- snowflake_connector_python-4.4.0.dist-info/top_level.txt +1 -0
- snowflake_connector_python.libs/msvcp140-0f885b509a685d2bbfa652fed26b5fb3.dll +0 -0
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import typing
|
|
5
|
+
from base64 import b64decode, b64encode
|
|
6
|
+
from collections import OrderedDict
|
|
7
|
+
from datetime import datetime, timezone
|
|
8
|
+
from logging import getLogger
|
|
9
|
+
from os import getenv
|
|
10
|
+
|
|
11
|
+
from asn1crypto.algos import DigestAlgorithm
|
|
12
|
+
from asn1crypto.core import Integer, OctetString
|
|
13
|
+
from asn1crypto.ocsp import (
|
|
14
|
+
CertId,
|
|
15
|
+
OCSPRequest,
|
|
16
|
+
OCSPResponse,
|
|
17
|
+
Request,
|
|
18
|
+
Requests,
|
|
19
|
+
SingleResponse,
|
|
20
|
+
TBSRequest,
|
|
21
|
+
Version,
|
|
22
|
+
)
|
|
23
|
+
from asn1crypto.x509 import Certificate
|
|
24
|
+
from cryptography.exceptions import InvalidSignature
|
|
25
|
+
from cryptography.hazmat.backends import default_backend
|
|
26
|
+
from cryptography.hazmat.primitives import hashes, serialization
|
|
27
|
+
from cryptography.hazmat.primitives.asymmetric import padding, utils
|
|
28
|
+
from cryptography.hazmat.primitives.asymmetric.dsa import DSAPublicKey
|
|
29
|
+
from cryptography.hazmat.primitives.asymmetric.ec import ECDSA, EllipticCurvePublicKey
|
|
30
|
+
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
|
|
31
|
+
from OpenSSL.SSL import Connection
|
|
32
|
+
|
|
33
|
+
from snowflake.connector.errorcode import (
|
|
34
|
+
ER_OCSP_RESPONSE_ATTACHED_CERT_EXPIRED,
|
|
35
|
+
ER_OCSP_RESPONSE_ATTACHED_CERT_INVALID,
|
|
36
|
+
ER_OCSP_RESPONSE_CERT_STATUS_INVALID,
|
|
37
|
+
ER_OCSP_RESPONSE_INVALID_SIGNATURE,
|
|
38
|
+
ER_OCSP_RESPONSE_LOAD_FAILURE,
|
|
39
|
+
ER_OCSP_RESPONSE_STATUS_UNSUCCESSFUL,
|
|
40
|
+
)
|
|
41
|
+
from snowflake.connector.errors import RevocationCheckError
|
|
42
|
+
from snowflake.connector.ocsp_snowflake import SnowflakeOCSP, generate_cache_key
|
|
43
|
+
|
|
44
|
+
logger = getLogger(__name__)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class SnowflakeOCSPAsn1Crypto(SnowflakeOCSP):
|
|
48
|
+
"""OCSP checks by asn1crypto."""
|
|
49
|
+
|
|
50
|
+
# map signature algorithm name to digest class
|
|
51
|
+
SIGNATURE_ALGORITHM_TO_DIGEST_CLASS = {
|
|
52
|
+
"sha256": hashes.SHA256,
|
|
53
|
+
"sha384": hashes.SHA384,
|
|
54
|
+
"sha512": hashes.SHA512,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
def encode_cert_id_key(self, hkey):
|
|
58
|
+
issuer_name_hash, issuer_key_hash, serial_number = hkey
|
|
59
|
+
issuer_name_hash = OctetString.load(issuer_name_hash)
|
|
60
|
+
issuer_key_hash = OctetString.load(issuer_key_hash)
|
|
61
|
+
serial_number = Integer.load(serial_number)
|
|
62
|
+
cert_id = CertId(
|
|
63
|
+
{
|
|
64
|
+
"hash_algorithm": DigestAlgorithm(
|
|
65
|
+
{"algorithm": "sha1", "parameters": None}
|
|
66
|
+
),
|
|
67
|
+
"issuer_name_hash": issuer_name_hash,
|
|
68
|
+
"issuer_key_hash": issuer_key_hash,
|
|
69
|
+
"serial_number": serial_number,
|
|
70
|
+
}
|
|
71
|
+
)
|
|
72
|
+
return cert_id
|
|
73
|
+
|
|
74
|
+
def decode_cert_id_key(self, cert_id: CertId) -> tuple[bytes, bytes, bytes]:
|
|
75
|
+
return generate_cache_key(cert_id)
|
|
76
|
+
|
|
77
|
+
def decode_cert_id_base64(self, cert_id_base64):
|
|
78
|
+
return CertId.load(b64decode(cert_id_base64))
|
|
79
|
+
|
|
80
|
+
def encode_cert_id_base64(self, hkey):
|
|
81
|
+
return b64encode(self.encode_cert_id_key(hkey).dump()).decode("ascii")
|
|
82
|
+
|
|
83
|
+
def read_cert_bundle(self, ca_bundle_file, storage=None) -> None:
|
|
84
|
+
"""Reads a certificate file including certificates in PEM format."""
|
|
85
|
+
if storage is None:
|
|
86
|
+
storage = SnowflakeOCSP.ROOT_CERTIFICATES_DICT
|
|
87
|
+
logger.debug("reading certificate bundle: %s", ca_bundle_file)
|
|
88
|
+
with open(ca_bundle_file, "rb") as all_certs:
|
|
89
|
+
# don't lock storage
|
|
90
|
+
from asn1crypto import pem
|
|
91
|
+
|
|
92
|
+
pem_certs = pem.unarmor(all_certs.read(), multiple=True)
|
|
93
|
+
for type_name, _, der_bytes in pem_certs:
|
|
94
|
+
if type_name == "CERTIFICATE":
|
|
95
|
+
crt = Certificate.load(der_bytes)
|
|
96
|
+
storage[crt.subject.sha256] = crt
|
|
97
|
+
|
|
98
|
+
def create_ocsp_request(
|
|
99
|
+
self,
|
|
100
|
+
issuer: Certificate,
|
|
101
|
+
subject: Certificate,
|
|
102
|
+
) -> tuple[CertId, OCSPRequest]:
|
|
103
|
+
"""Creates CertId and OCSPRequest."""
|
|
104
|
+
cert_id = CertId(
|
|
105
|
+
{
|
|
106
|
+
"hash_algorithm": DigestAlgorithm(
|
|
107
|
+
{"algorithm": "sha1", "parameters": None}
|
|
108
|
+
),
|
|
109
|
+
"issuer_name_hash": OctetString(subject.issuer.sha1),
|
|
110
|
+
"issuer_key_hash": OctetString(issuer.public_key.sha1),
|
|
111
|
+
"serial_number": subject.serial_number,
|
|
112
|
+
}
|
|
113
|
+
)
|
|
114
|
+
ocsp_request = OCSPRequest(
|
|
115
|
+
{
|
|
116
|
+
"tbs_request": TBSRequest(
|
|
117
|
+
{
|
|
118
|
+
"version": Version(0),
|
|
119
|
+
"request_list": Requests(
|
|
120
|
+
[
|
|
121
|
+
Request(
|
|
122
|
+
{
|
|
123
|
+
"req_cert": cert_id,
|
|
124
|
+
}
|
|
125
|
+
)
|
|
126
|
+
]
|
|
127
|
+
),
|
|
128
|
+
}
|
|
129
|
+
),
|
|
130
|
+
}
|
|
131
|
+
)
|
|
132
|
+
return cert_id, ocsp_request
|
|
133
|
+
|
|
134
|
+
def extract_ocsp_url(self, cert):
|
|
135
|
+
urls = cert.ocsp_urls
|
|
136
|
+
ocsp_url = urls[0] if urls else None
|
|
137
|
+
return ocsp_url
|
|
138
|
+
|
|
139
|
+
def decode_ocsp_request(self, ocsp_request):
|
|
140
|
+
return ocsp_request.dump()
|
|
141
|
+
|
|
142
|
+
def decode_ocsp_request_b64(self, ocsp_request):
|
|
143
|
+
data = self.decode_ocsp_request(ocsp_request) # convert to DER
|
|
144
|
+
b64data = b64encode(data).decode("ascii")
|
|
145
|
+
return b64data
|
|
146
|
+
|
|
147
|
+
def extract_good_status(
|
|
148
|
+
self, single_response: SingleResponse
|
|
149
|
+
) -> tuple[datetime, datetime]:
|
|
150
|
+
"""Extracts GOOD status."""
|
|
151
|
+
this_update_native = single_response["this_update"].native
|
|
152
|
+
next_update_native = single_response["next_update"].native
|
|
153
|
+
|
|
154
|
+
return this_update_native, next_update_native
|
|
155
|
+
|
|
156
|
+
def extract_revoked_status(self, single_response):
|
|
157
|
+
"""Extracts REVOKED status."""
|
|
158
|
+
revoked_info = single_response["cert_status"]
|
|
159
|
+
revocation_time = revoked_info.native["revocation_time"]
|
|
160
|
+
revocation_reason = revoked_info.native["revocation_reason"]
|
|
161
|
+
return revocation_time, revocation_reason
|
|
162
|
+
|
|
163
|
+
def check_cert_time_validity(
|
|
164
|
+
self, cur_time: datetime, ocsp_cert: Certificate
|
|
165
|
+
) -> tuple[bool, str | None]:
|
|
166
|
+
val_start = ocsp_cert["tbs_certificate"]["validity"]["not_before"].native
|
|
167
|
+
val_end = ocsp_cert["tbs_certificate"]["validity"]["not_after"].native
|
|
168
|
+
|
|
169
|
+
if cur_time > val_end or cur_time < val_start:
|
|
170
|
+
debug_msg = (
|
|
171
|
+
"Certificate attached to OCSP response is invalid. OCSP response "
|
|
172
|
+
"current time - {} certificate not before time - {} certificate "
|
|
173
|
+
"not after time - {}. Consider running curl -o ocsp.der {}".format(
|
|
174
|
+
cur_time,
|
|
175
|
+
val_start,
|
|
176
|
+
val_end,
|
|
177
|
+
super().debug_ocsp_failure_url,
|
|
178
|
+
)
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
return False, debug_msg
|
|
182
|
+
else:
|
|
183
|
+
return True, None
|
|
184
|
+
|
|
185
|
+
"""
|
|
186
|
+
is_valid_time - checks various components of the OCSP Response
|
|
187
|
+
for expiry.
|
|
188
|
+
:param cert_id - certificate id corresponding to OCSP Response
|
|
189
|
+
:param ocsp_response
|
|
190
|
+
:return True/False depending on time validity within the response
|
|
191
|
+
"""
|
|
192
|
+
|
|
193
|
+
def is_valid_time(self, cert_id, ocsp_response) -> bool:
|
|
194
|
+
res = OCSPResponse.load(ocsp_response)
|
|
195
|
+
|
|
196
|
+
if res["response_status"].native != "successful":
|
|
197
|
+
raise RevocationCheckError(
|
|
198
|
+
msg="Invalid Status: {}".format(res["response_status"].native),
|
|
199
|
+
errno=ER_OCSP_RESPONSE_STATUS_UNSUCCESSFUL,
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
basic_ocsp_response = res.basic_ocsp_response
|
|
203
|
+
if basic_ocsp_response["certs"].native:
|
|
204
|
+
ocsp_cert = basic_ocsp_response["certs"][0]
|
|
205
|
+
logger.debug(
|
|
206
|
+
"Verifying the attached certificate is signed by "
|
|
207
|
+
"the issuer. Valid Not After: %s",
|
|
208
|
+
ocsp_cert["tbs_certificate"]["validity"]["not_after"].native,
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
cur_time = datetime.now(timezone.utc)
|
|
212
|
+
|
|
213
|
+
"""
|
|
214
|
+
Note:
|
|
215
|
+
We purposefully do not verify certificate signature here.
|
|
216
|
+
The OCSP Response is extracted from the OCSP Response Cache
|
|
217
|
+
which is expected to have OCSP Responses with verified
|
|
218
|
+
attached signature. Moreover this OCSP Response is eventually
|
|
219
|
+
going to be processed by the driver before being consumed by
|
|
220
|
+
the driver.
|
|
221
|
+
This step ensures that the OCSP Response cache does not have
|
|
222
|
+
any invalid entries.
|
|
223
|
+
"""
|
|
224
|
+
cert_valid, debug_msg = self.check_cert_time_validity(cur_time, ocsp_cert)
|
|
225
|
+
if not cert_valid:
|
|
226
|
+
logger.debug(debug_msg)
|
|
227
|
+
return False
|
|
228
|
+
|
|
229
|
+
tbs_response_data = basic_ocsp_response["tbs_response_data"]
|
|
230
|
+
|
|
231
|
+
single_response = tbs_response_data["responses"][0]
|
|
232
|
+
cert_status = single_response["cert_status"].name
|
|
233
|
+
|
|
234
|
+
try:
|
|
235
|
+
if cert_status == "good":
|
|
236
|
+
self._process_good_status(single_response, cert_id, ocsp_response)
|
|
237
|
+
except Exception as ex:
|
|
238
|
+
logger.debug("Failed to validate ocsp response %s", ex)
|
|
239
|
+
return False
|
|
240
|
+
|
|
241
|
+
return True
|
|
242
|
+
|
|
243
|
+
def process_ocsp_response(self, issuer, cert_id, ocsp_response):
|
|
244
|
+
try:
|
|
245
|
+
res = OCSPResponse.load(ocsp_response)
|
|
246
|
+
if self.test_mode is not None:
|
|
247
|
+
ocsp_load_failure = getenv("SF_TEST_OCSP_FORCE_BAD_OCSP_RESPONSE")
|
|
248
|
+
if ocsp_load_failure is not None:
|
|
249
|
+
raise RevocationCheckError(
|
|
250
|
+
msg="Force fail", errno=ER_OCSP_RESPONSE_LOAD_FAILURE
|
|
251
|
+
)
|
|
252
|
+
except Exception:
|
|
253
|
+
raise RevocationCheckError(
|
|
254
|
+
msg="Invalid OCSP Response", errno=ER_OCSP_RESPONSE_LOAD_FAILURE
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
if res["response_status"].native != "successful":
|
|
258
|
+
raise RevocationCheckError(
|
|
259
|
+
msg="Invalid Status: {}".format(res["response_status"].native),
|
|
260
|
+
errno=ER_OCSP_RESPONSE_STATUS_UNSUCCESSFUL,
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
basic_ocsp_response = res.basic_ocsp_response
|
|
264
|
+
if basic_ocsp_response["certs"].native:
|
|
265
|
+
logger.debug("Certificate is attached in Basic OCSP Response")
|
|
266
|
+
ocsp_cert = basic_ocsp_response["certs"][0]
|
|
267
|
+
logger.debug(
|
|
268
|
+
"Verifying the attached certificate is signed by " "the issuer"
|
|
269
|
+
)
|
|
270
|
+
logger.debug(
|
|
271
|
+
"Valid Not After: %s",
|
|
272
|
+
ocsp_cert["tbs_certificate"]["validity"]["not_after"].native,
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
cur_time = datetime.now(timezone.utc)
|
|
276
|
+
|
|
277
|
+
try:
|
|
278
|
+
"""
|
|
279
|
+
Signature verification should happen before any kind of
|
|
280
|
+
validation
|
|
281
|
+
"""
|
|
282
|
+
self.verify_signature(
|
|
283
|
+
ocsp_cert.hash_algo,
|
|
284
|
+
ocsp_cert.signature,
|
|
285
|
+
issuer,
|
|
286
|
+
ocsp_cert["tbs_certificate"],
|
|
287
|
+
)
|
|
288
|
+
except RevocationCheckError as rce:
|
|
289
|
+
raise RevocationCheckError(
|
|
290
|
+
msg=rce.msg, errno=ER_OCSP_RESPONSE_ATTACHED_CERT_INVALID
|
|
291
|
+
)
|
|
292
|
+
cert_valid, debug_msg = self.check_cert_time_validity(cur_time, ocsp_cert)
|
|
293
|
+
|
|
294
|
+
if not cert_valid:
|
|
295
|
+
raise RevocationCheckError(
|
|
296
|
+
msg=debug_msg, errno=ER_OCSP_RESPONSE_ATTACHED_CERT_EXPIRED
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
else:
|
|
300
|
+
logger.debug(
|
|
301
|
+
"Certificate is NOT attached in Basic OCSP Response. "
|
|
302
|
+
"Using issuer's certificate"
|
|
303
|
+
)
|
|
304
|
+
ocsp_cert = issuer
|
|
305
|
+
|
|
306
|
+
tbs_response_data = basic_ocsp_response["tbs_response_data"]
|
|
307
|
+
|
|
308
|
+
logger.debug("Verifying the OCSP response is signed by the issuer.")
|
|
309
|
+
try:
|
|
310
|
+
self.verify_signature(
|
|
311
|
+
basic_ocsp_response["signature_algorithm"].hash_algo,
|
|
312
|
+
basic_ocsp_response["signature"].native,
|
|
313
|
+
ocsp_cert,
|
|
314
|
+
tbs_response_data,
|
|
315
|
+
)
|
|
316
|
+
except RevocationCheckError as rce:
|
|
317
|
+
raise RevocationCheckError(
|
|
318
|
+
msg=rce.msg, errno=ER_OCSP_RESPONSE_INVALID_SIGNATURE
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
single_response = tbs_response_data["responses"][0]
|
|
322
|
+
cert_status = single_response["cert_status"].name
|
|
323
|
+
if self.test_mode is not None:
|
|
324
|
+
test_cert_status = getenv("SF_TEST_OCSP_CERT_STATUS")
|
|
325
|
+
if test_cert_status == "revoked":
|
|
326
|
+
cert_status = "revoked"
|
|
327
|
+
elif test_cert_status == "unknown":
|
|
328
|
+
cert_status = "unknown"
|
|
329
|
+
elif test_cert_status == "good":
|
|
330
|
+
cert_status = "good"
|
|
331
|
+
|
|
332
|
+
try:
|
|
333
|
+
if cert_status == "good":
|
|
334
|
+
self._process_good_status(single_response, cert_id, ocsp_response)
|
|
335
|
+
elif cert_status == "revoked":
|
|
336
|
+
self._process_revoked_status(single_response, cert_id)
|
|
337
|
+
elif cert_status == "unknown":
|
|
338
|
+
self._process_unknown_status(cert_id)
|
|
339
|
+
else:
|
|
340
|
+
debug_msg = (
|
|
341
|
+
"Unknown revocation status was returned."
|
|
342
|
+
"OCSP response may be malformed: {}.".format(cert_status)
|
|
343
|
+
)
|
|
344
|
+
raise RevocationCheckError(
|
|
345
|
+
msg=debug_msg, errno=ER_OCSP_RESPONSE_CERT_STATUS_INVALID
|
|
346
|
+
)
|
|
347
|
+
except RevocationCheckError as op_er:
|
|
348
|
+
debug_msg = "{} Consider running curl -o ocsp.der {}".format(
|
|
349
|
+
op_er.msg, self.debug_ocsp_failure_url
|
|
350
|
+
)
|
|
351
|
+
raise RevocationCheckError(msg=debug_msg, errno=op_er.errno)
|
|
352
|
+
|
|
353
|
+
def verify_signature(self, signature_algorithm, signature, cert, data):
|
|
354
|
+
backend = default_backend()
|
|
355
|
+
public_key = serialization.load_der_public_key(
|
|
356
|
+
cert.public_key.dump(), backend=default_backend()
|
|
357
|
+
)
|
|
358
|
+
if (
|
|
359
|
+
signature_algorithm
|
|
360
|
+
in SnowflakeOCSPAsn1Crypto.SIGNATURE_ALGORITHM_TO_DIGEST_CLASS
|
|
361
|
+
):
|
|
362
|
+
chosen_hash = SnowflakeOCSPAsn1Crypto.SIGNATURE_ALGORITHM_TO_DIGEST_CLASS[
|
|
363
|
+
signature_algorithm
|
|
364
|
+
]()
|
|
365
|
+
else:
|
|
366
|
+
# the last resort. should not happen.
|
|
367
|
+
chosen_hash = hashes.SHA1()
|
|
368
|
+
hasher = hashes.Hash(chosen_hash, backend)
|
|
369
|
+
hasher.update(data.dump())
|
|
370
|
+
digest = hasher.finalize()
|
|
371
|
+
additional_kwargs: dict[str, typing.Any] = dict()
|
|
372
|
+
if isinstance(public_key, RSAPublicKey):
|
|
373
|
+
additional_kwargs["padding"] = padding.PKCS1v15()
|
|
374
|
+
additional_kwargs["algorithm"] = utils.Prehashed(chosen_hash)
|
|
375
|
+
elif isinstance(public_key, DSAPublicKey):
|
|
376
|
+
additional_kwargs["algorithm"] = utils.Prehashed(chosen_hash)
|
|
377
|
+
elif isinstance(public_key, EllipticCurvePublicKey):
|
|
378
|
+
additional_kwargs["signature_algorithm"] = ECDSA(
|
|
379
|
+
utils.Prehashed(chosen_hash)
|
|
380
|
+
)
|
|
381
|
+
try:
|
|
382
|
+
public_key.verify(
|
|
383
|
+
signature,
|
|
384
|
+
digest,
|
|
385
|
+
**additional_kwargs,
|
|
386
|
+
)
|
|
387
|
+
except InvalidSignature:
|
|
388
|
+
raise RevocationCheckError(msg="Failed to verify the signature")
|
|
389
|
+
|
|
390
|
+
def extract_certificate_chain(
|
|
391
|
+
self, connection: Connection
|
|
392
|
+
) -> list[tuple[Certificate, Certificate]]:
|
|
393
|
+
"""Gets certificate chain and extract the key info from OpenSSL connection."""
|
|
394
|
+
from OpenSSL.crypto import FILETYPE_ASN1, dump_certificate
|
|
395
|
+
|
|
396
|
+
cert_map = OrderedDict()
|
|
397
|
+
cert_chain = connection.get_peer_cert_chain()
|
|
398
|
+
logger.debug("# of certificates: %s", len(cert_chain))
|
|
399
|
+
self._lazy_read_ca_bundle()
|
|
400
|
+
for cert_openssl in cert_chain:
|
|
401
|
+
cert_der = dump_certificate(FILETYPE_ASN1, cert_openssl)
|
|
402
|
+
cert = Certificate.load(cert_der)
|
|
403
|
+
logger.debug(
|
|
404
|
+
"subject: %s, issuer: %s", cert.subject.native, cert.issuer.native
|
|
405
|
+
)
|
|
406
|
+
cert_map[cert.subject.sha256] = cert
|
|
407
|
+
if cert.issuer.sha256 in SnowflakeOCSP.ROOT_CERTIFICATES_DICT:
|
|
408
|
+
logger.debug(
|
|
409
|
+
"A trusted root certificate found: %s, stopping chain traversal here",
|
|
410
|
+
cert.subject.native,
|
|
411
|
+
)
|
|
412
|
+
break
|
|
413
|
+
|
|
414
|
+
return self.create_pair_issuer_subject(cert_map)
|
|
415
|
+
|
|
416
|
+
def create_pair_issuer_subject(
|
|
417
|
+
self, cert_map: OrderedDict
|
|
418
|
+
) -> list[tuple[Certificate, Certificate]]:
|
|
419
|
+
"""Creates pairs of issuer and subject certificates."""
|
|
420
|
+
issuer_subject = []
|
|
421
|
+
for subject_der in cert_map:
|
|
422
|
+
subject = cert_map[subject_der]
|
|
423
|
+
if subject.ocsp_no_check_value or subject.ca and not subject.ocsp_urls:
|
|
424
|
+
# Root certificate will not be validated
|
|
425
|
+
# but it is used to validate the subject certificate
|
|
426
|
+
continue
|
|
427
|
+
issuer_hash = subject.issuer.sha256
|
|
428
|
+
if issuer_hash not in cert_map:
|
|
429
|
+
# IF NO ROOT certificate is attached in the certificate chain
|
|
430
|
+
# read it from the local disk
|
|
431
|
+
self._lazy_read_ca_bundle()
|
|
432
|
+
logger.debug("not found issuer_der: %s", subject.issuer.native)
|
|
433
|
+
if issuer_hash not in SnowflakeOCSP.ROOT_CERTIFICATES_DICT:
|
|
434
|
+
raise RevocationCheckError(
|
|
435
|
+
msg="CA certificate is NOT found in the root "
|
|
436
|
+
"certificate list. Make sure you use the latest "
|
|
437
|
+
"Python Connector package and the URL is valid."
|
|
438
|
+
)
|
|
439
|
+
issuer = SnowflakeOCSP.ROOT_CERTIFICATES_DICT[issuer_hash]
|
|
440
|
+
else:
|
|
441
|
+
issuer = cert_map[issuer_hash]
|
|
442
|
+
|
|
443
|
+
issuer_subject.append((issuer, subject))
|
|
444
|
+
return issuer_subject
|
|
445
|
+
|
|
446
|
+
def subject_name(self, subject: Certificate) -> OrderedDict:
|
|
447
|
+
return subject.subject.native
|