Skip to content

Commit 800c16e

Browse files
bretambroseBret Ambrose
and
Bret Ambrose
authored
Use ssl context wrap socket in Python3.12+ (#338)
* Use ssl context wrap socket in Python3.12+ * Remove redundant test modes --------- Co-authored-by: Bret Ambrose <[email protected]>
1 parent f78e330 commit 800c16e

File tree

4 files changed

+75
-59
lines changed

4 files changed

+75
-59
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,10 @@ jobs:
3636
strategy:
3737
fail-fast: false
3838
matrix:
39-
test-type: [ MutualAuth, MutualAuthT , Websocket, ALPN, ALPNT]
40-
python-version: [ '2.x', '3.x' ]
41-
#[MutualAuth, Websocket, ALPN]
39+
test-type: [ MutualAuth, Websocket, ALPN ]
40+
python-version: [ '3.7', '3.12' ]
4241
steps:
43-
- uses: actions/checkout@v2
42+
- uses: actions/checkout@v4
4443
- uses: actions/setup-python@v2
4544
with:
4645
python-version: ${{ matrix.python-version }}
@@ -49,4 +48,5 @@ jobs:
4948
pip install pytest
5049
pip install mock
5150
pip install boto3
51+
python --version
5252
./test-integration/run/run.sh ${{ matrix.test-type }} 1000 100 7

AWSIoTPythonSDK/core/greengrass/discovery/providers.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -261,17 +261,28 @@ def _create_ssl_connection(self, sock):
261261
ssl_sock = ssl_context.wrap_socket(sock, server_hostname=self._host, do_handshake_on_connect=False)
262262
ssl_sock.do_handshake()
263263
else:
264-
ssl_sock = ssl.wrap_socket(sock,
265-
certfile=self._cert_path,
266-
keyfile=self._key_path,
267-
ca_certs=self._ca_path,
268-
cert_reqs=ssl.CERT_REQUIRED,
269-
ssl_version=ssl_protocol_version)
264+
# To keep the SSL Context update minimal, only apply forced ssl context to python3.12+
265+
force_ssl_context = sys.version_info[0] > 3 or (sys.version_info[0] == 3 and sys.version_info[1] >= 12)
266+
if force_ssl_context:
267+
ssl_context = ssl.SSLContext(ssl_protocol_version)
268+
ssl_context.load_cert_chain(self._cert_path, self._key_path)
269+
ssl_context.load_verify_locations(self._ca_path)
270+
ssl_context.verify_mode = ssl.CERT_REQUIRED
271+
272+
ssl_sock = ssl_context.wrap_socket(sock)
273+
else:
274+
ssl_sock = ssl.wrap_socket(sock,
275+
certfile=self._cert_path,
276+
keyfile=self._key_path,
277+
ca_certs=self._ca_path,
278+
cert_reqs=ssl.CERT_REQUIRED,
279+
ssl_version=ssl_protocol_version)
270280

271281
self._logger.debug("Matching host name...")
272282
if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] < 2):
273283
self._tls_match_hostname(ssl_sock)
274-
else:
284+
elif sys.version_info[0] == 3 and sys.version_info[1] < 7:
285+
# host name verification is handled internally in Python3.7+
275286
ssl.match_hostname(ssl_sock.getpeercert(), self._host)
276287

277288
return ssl_sock

AWSIoTPythonSDK/core/protocol/paho/client.py

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -793,11 +793,22 @@ def reconnect(self):
793793

794794
verify_hostname = self._tls_insecure is False # Decide whether we need to verify hostname
795795

796+
# To keep the SSL Context update minimal, only apply forced ssl context to python3.12+
797+
force_ssl_context = sys.version_info[0] > 3 or (sys.version_info[0] == 3 and sys.version_info[1] >= 12)
798+
796799
if self._tls_ca_certs is not None:
797800
if self._useSecuredWebsocket:
798801
# Never assign to ._ssl before wss handshake is finished
799802
# Non-None value for ._ssl will allow ops before wss-MQTT connection is established
800-
rawSSL = ssl.wrap_socket(sock, ca_certs=self._tls_ca_certs, cert_reqs=ssl.CERT_REQUIRED) # Add server certificate verification
803+
if force_ssl_context:
804+
ssl_context = ssl.SSLContext()
805+
ssl_context.load_verify_locations(self._tls_ca_certs)
806+
ssl_context.verify_mode = ssl.CERT_REQUIRED
807+
808+
rawSSL = ssl_context.wrap_socket(sock)
809+
else:
810+
rawSSL = ssl.wrap_socket(sock, ca_certs=self._tls_ca_certs, cert_reqs=ssl.CERT_REQUIRED) # Add server certificate verification
811+
801812
rawSSL.setblocking(0) # Non-blocking socket
802813
self._ssl = SecuredWebSocketCore(rawSSL, self._host, self._port, self._AWSAccessKeyIDCustomConfig, self._AWSSecretAccessKeyCustomConfig, self._AWSSessionTokenCustomConfig) # Override the _ssl socket
803814
# self._ssl.enableDebug()
@@ -816,19 +827,30 @@ def reconnect(self):
816827
verify_hostname = False # Since check_hostname in SSLContext is already set to True, no need to verify it again
817828
self._ssl.do_handshake()
818829
else:
819-
self._ssl = ssl.wrap_socket(
820-
sock,
821-
certfile=self._tls_certfile,
822-
keyfile=self._tls_keyfile,
823-
ca_certs=self._tls_ca_certs,
824-
cert_reqs=self._tls_cert_reqs,
825-
ssl_version=self._tls_version,
826-
ciphers=self._tls_ciphers)
830+
if force_ssl_context:
831+
ssl_context = ssl.SSLContext(self._tls_version)
832+
ssl_context.load_cert_chain(self._tls_certfile, self._tls_keyfile)
833+
ssl_context.load_verify_locations(self._tls_ca_certs)
834+
ssl_context.verify_mode = self._tls_cert_reqs
835+
if self._tls_ciphers is not None:
836+
ssl_context.set_ciphers(self._tls_ciphers)
837+
838+
self._ssl = ssl_context.wrap_socket(sock)
839+
else:
840+
self._ssl = ssl.wrap_socket(
841+
sock,
842+
certfile=self._tls_certfile,
843+
keyfile=self._tls_keyfile,
844+
ca_certs=self._tls_ca_certs,
845+
cert_reqs=self._tls_cert_reqs,
846+
ssl_version=self._tls_version,
847+
ciphers=self._tls_ciphers)
827848

828849
if verify_hostname:
829850
if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] < 5): # No IP host match before 3.5.x
830851
self._tls_match_hostname()
831-
else:
852+
elif sys.version_info[0] == 3 and sys.version_info[1] < 7:
853+
# host name verification is handled internally in Python3.7+
832854
ssl.match_hostname(self._ssl.getpeercert(), self._host)
833855

834856
self._sock = sock

test-integration/run/run.sh

Lines changed: 21 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,13 @@ USAGE="usage: run.sh <testMode> <NumberOfMQTTMessages> <LengthOfShadowRandomStri
3535

3636
AWSMutualAuth_TodWorker_private_key="arn:aws:secretsmanager:us-east-1:123124136734:secret:V1IotSdkIntegrationTestPrivateKey-vNUQU8"
3737
AWSMutualAuth_TodWorker_certificate="arn:aws:secretsmanager:us-east-1:123124136734:secret:V1IotSdkIntegrationTestCertificate-vTRwjE"
38-
AWSMutualAuth_Desktop_private_key="arn:aws:secretsmanager:us-east-1:123124136734:secret:V1IotSdkIntegrationTestDesktopPrivateKey-DdC7nv"
39-
AWSMutualAuth_Desktop_certificate="arn:aws:secretsmanager:us-east-1:123124136734:secret:V1IotSdkIntegrationTestDesktopCertificate-IA4xbj"
4038

4139
AWSGGDiscovery_TodWorker_private_key="arn:aws:secretsmanager:us-east-1:123124136734:secret:V1IotSdkIntegrationTestGGDiscoveryPrivateKey-YHQI1F"
4240
AWSGGDiscovery_TodWorker_certificate="arn:aws:secretsmanager:us-east-1:123124136734:secret:V1IotSdkIntegrationTestGGDiscoveryCertificate-TwlAcS"
4341

4442
AWSSecretForWebsocket_TodWorker_KeyId="arn:aws:secretsmanager:us-east-1:123124136734:secret:V1IotSdkIntegrationTestWebsocketAccessKeyId-1YdB9z"
4543
AWSSecretForWebsocket_TodWorker_SecretKey="arn:aws:secretsmanager:us-east-1:123124136734:secret:V1IotSdkIntegrationTestWebsocketSecretAccessKey-MKTSaV"
46-
AWSSecretForWebsocket_Desktop_KeyId="arn:aws:secretsmanager:us-east-1:123124136734:secret:V1IotSdkIntegrationTestWebsocketAccessKeyId-1YdB9z"
47-
AWSSecretForWebsocket_Desktop_SecretKey="arn:aws:secretsmanager:us-east-1:123124136734:secret:V1IotSdkIntegrationTestWebsocketSecretAccessKey-MKTSaV"
44+
4845

4946
SDKLocation="./AWSIoTPythonSDK"
5047
RetrieveAWSKeys="./test-integration/Tools/retrieve-key.py"
@@ -72,55 +69,41 @@ else
7269
TestMode=""
7370
echo "[STEP] Retrieve credentials from AWS"
7471
echo "***************************************************"
75-
if [ "$1"x == "MutualAuth"x -o "$1"x == "MutualAuthT"x ]; then
72+
if [ "$1"x == "MutualAuth"x ]; then
7673
AWSSetName_privatekey=${AWSMutualAuth_TodWorker_private_key}
77-
AWSSetName_certificate=${AWSMutualAuth_TodWorker_certificate}
78-
AWSDRSName_privatekey=${AWSGGDiscovery_TodWorker_private_key}
74+
AWSSetName_certificate=${AWSMutualAuth_TodWorker_certificate}
75+
AWSDRSName_privatekey=${AWSGGDiscovery_TodWorker_private_key}
7976
AWSDRSName_certificate=${AWSGGDiscovery_TodWorker_certificate}
8077
TestMode="MutualAuth"
81-
if [ "$1"x == "MutualAuthT"x ]; then
82-
AWSSetName_privatekey=${AWSMutualAuth_Desktop_private_key}
83-
AWSSetName_certificate=${AWSMutualAuth_Desktop_certificate}
84-
fi
85-
python ${RetrieveAWSKeys} ${AWSSetName_certificate} > ${CREDENTIAL_DIR}certificate.pem.crt
86-
python ${RetrieveAWSKeys} ${AWSSetName_privatekey} > ${CREDENTIAL_DIR}privateKey.pem.key
78+
python ${RetrieveAWSKeys} ${AWSSetName_certificate} > ${CREDENTIAL_DIR}certificate.pem.crt
79+
python ${RetrieveAWSKeys} ${AWSSetName_privatekey} > ${CREDENTIAL_DIR}privateKey.pem.key
8780
curl -s "${CA_CERT_URL}" > ${CA_CERT_PATH}
88-
echo -e "URL retrieved certificate data:\n$(cat ${CA_CERT_PATH})\n"
89-
python ${RetrieveAWSKeys} ${AWSDRSName_certificate} > ${CREDENTIAL_DIR}certificate_drs.pem.crt
90-
python ${RetrieveAWSKeys} ${AWSDRSName_privatekey} > ${CREDENTIAL_DIR}privateKey_drs.pem.key
91-
elif [ "$1"x == "Websocket"x -o "$1"x == "WebsocketT"x ]; then
92-
ACCESS_KEY_ID_ARN=$(python ${RetrieveAWSKeys} ${AWSSecretForWebsocket_TodWorker_KeyId})
81+
echo -e "URL retrieved certificate data\n"
82+
python ${RetrieveAWSKeys} ${AWSDRSName_certificate} > ${CREDENTIAL_DIR}certificate_drs.pem.crt
83+
python ${RetrieveAWSKeys} ${AWSDRSName_privatekey} > ${CREDENTIAL_DIR}privateKey_drs.pem.key
84+
elif [ "$1"x == "Websocket"x ]; then
85+
ACCESS_KEY_ID_ARN=$(python ${RetrieveAWSKeys} ${AWSSecretForWebsocket_TodWorker_KeyId})
9386
ACCESS_SECRET_KEY_ARN=$(python ${RetrieveAWSKeys} ${AWSSecretForWebsocket_TodWorker_SecretKey})
9487
TestMode="Websocket"
95-
if [ "$1"x == "WebsocketT"x ]; then
96-
ACCESS_KEY_ID_ARN=$(python ${RetrieveAWSKeys} ${AWSSecretForWebsocket_Desktop_KeyId})
97-
ACCESS_SECRET_KEY_ARN=$(python ${RetrieveAWSKeys} ${AWSSecretForWebsocket_Desktop_SecretKey})
98-
fi
99-
echo ${ACCESS_KEY_ID_ARN}
100-
echo ${ACCESS_SECRET_KEY_ARN}
10188
export AWS_ACCESS_KEY_ID=${ACCESS_KEY_ID_ARN}
10289
export AWS_SECRET_ACCESS_KEY=${ACCESS_SECRET_KEY_ARN}
10390
curl -s "${CA_CERT_URL}" > ${CA_CERT_PATH}
104-
echo -e "URL retrieved certificate data:\n$(cat ${CA_CERT_PATH})\n"
105-
elif [ "$1"x == "ALPN"x -o "$1"x == "ALPNT"x ]; then
91+
echo -e "URL retrieved certificate data\n"
92+
elif [ "$1"x == "ALPN"x ]; then
10693
AWSSetName_privatekey=${AWSMutualAuth_TodWorker_private_key}
107-
AWSSetName_certificate=${AWSMutualAuth_TodWorker_certificate}
108-
AWSDRSName_privatekey=${AWSGGDiscovery_TodWorker_private_key}
94+
AWSSetName_certificate=${AWSMutualAuth_TodWorker_certificate}
95+
AWSDRSName_privatekey=${AWSGGDiscovery_TodWorker_private_key}
10996
AWSDRSName_certificate=${AWSGGDiscovery_TodWorker_certificate}
11097
TestMode="ALPN"
111-
if [ "$1"x == "ALPNT"x ]; then
112-
AWSSetName_privatekey=${AWSMutualAuth_Desktop_private_key}
113-
AWSSetName_certificate=${AWSMutualAuth_Desktop_certificate}
114-
fi
11598
python ${RetrieveAWSKeys} ${AWSSetName_certificate} > ${CREDENTIAL_DIR}certificate.pem.crt
116-
python ${RetrieveAWSKeys} ${AWSSetName_privatekey} > ${CREDENTIAL_DIR}privateKey.pem.key
99+
python ${RetrieveAWSKeys} ${AWSSetName_privatekey} > ${CREDENTIAL_DIR}privateKey.pem.key
117100
curl -s "${CA_CERT_URL}" > ${CA_CERT_PATH}
118-
echo -e "URL retrieved certificate data:\n$(cat ${CA_CERT_PATH})\n"
119-
python ${RetrieveAWSKeys} ${AWSDRSName_certificate} > ${CREDENTIAL_DIR}certificate_drs.pem.crt
120-
python ${RetrieveAWSKeys} ${AWSDRSName_privatekey} > ${CREDENTIAL_DIR}privateKey_drs.pem.key
101+
echo -e "URL retrieved certificate data\n"
102+
python ${RetrieveAWSKeys} ${AWSDRSName_certificate} > ${CREDENTIAL_DIR}certificate_drs.pem.crt
103+
python ${RetrieveAWSKeys} ${AWSDRSName_privatekey} > ${CREDENTIAL_DIR}privateKey_drs.pem.key
121104
else
122-
echo "Mode not supported"
123-
exit 1
105+
echo "Mode not supported"
106+
exit 1
124107
fi
125108
# Obtain ZIP package and unzip it locally
126109
echo ${TestMode}

0 commit comments

Comments
 (0)