Use KeyTools or OpenSSL to generate a KeyStore (including an SSL certificate) in P12 format and use the certificate to set up an HTTPS interface on the server with SpringBoot. For details about how to set up an HTTPS interface, see Related knowledge about HTTPS

Here’s how to use the Requests toolkit in Pyhon to invoke the HTTPS interface on the server side.

First attempt – direct call

import requests
if __name__ == '__main__':
    LOCAL_SERVICE_URL = 'https://localhost:1443/api/anno/success'
    REMOTE_SERVICE_URL = 'https://www.baidu.com/'
    print('\n\n-----request remote https-----')
    res = requests.get(REMOTE_SERVICE_URL)
    print(res.status_code)
    print('\n\n-----request local https-----')
    res = requests.get(LOCAL_SERVICE_URL)
    print(res.status_code)
Copy the code

Results: call REMOTE_SERVICE_URL success, call LOCAL_SERVICE_URL throws an exception: SSL. SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] Certificate verify failed: self signed certificate (_ssl.c:1131).

The list of trusted root certificate issuers is preset in the Cacert. pem file in the Certifi package installation directory. By default, only SSL certificates issued by the list and its subordinate organizations can pass the verification. REMOTE_SERVICE_URL was successfully invoked because the SSL certificate used by REMOTE_SERVICE_URL was issued by a certifi package. The Root certificate authority is GlobalSign Root CA, which is in the certifi package list of trusted Root certificate Cas. The self-issued SSL certificate used by LOCAL_SERVICE_URL is not in the list of trusted authorities, so validation failure throws an exception.

Workaround: One is to skip SSL certificate validation, and the other is to set the self-issuing authority to be trusted.

Second attempt – Skip SSL authentication

According to the Requests official documentation, it is not recommended, but you can skip SSL validation by setting the request parameter verify=False.

import requests from requests.packages import urllib3 if __name__ == '__main__': LOCAL_SERVICE_URL = 'https://localhost:1443/api/anno/success' REMOTE_SERVICE_URL = 'https://www.baidu.com/' # Urllib3. disable_warnings() print('\n\n-----request remote HTTPS -----') res =  requests.get(REMOTE_SERVICE_URL) print(res.status_code) print('\n\n-----request local https-----') res = requests.get(LOCAL_SERVICE_URL, verify=False) print(res.status_code)Copy the code

Third attempt – set the self-issuing authority to be trusted – temporary

According to the requests official documentation, you can set the request parameter verify to the path of the CA_BUNDLE file or the folder containing the trusted CA certificate file. (If verify is set to the folder path, Folders must be processed by the C_rehash tool provided by OpenSSL), which can also be verified by SSL certificates.

What is a CA Bundle and Where to Find It? The CA Bundle is a file that contains the root certificate and the intermediate certificate. The self-issued SSL certificate has only one layer, so the self-issued SSL certificate is the CA Boundle file.

The requests verify parameter requires that the CA Bundle file be in text format and not readable in binary. Here are two ways to get an SSL certificate in text format:

  1. Because the KeyStore in P12 format contains the SSL certificate and private key, extract the SSL certificate from the KeyStore and use the Python tool package of OpenSSL to convert the P12 format to pem format
import os
from OpenSSL import crypto
​
def p12_to_pem(cert_name, pwd):
    pem_file_path = cert_name + '.pem'
    pem_file = open(pem_file_path, 'wb')
    p12_file_path = cert_name + '.p12'
    p12_file = crypto.load_pkcs12(open(p12_file_path, 'rb').read(), pwd)
​
    print(crypto.dump_privatekey(crypto.FILETYPE_PEM, p12_file.get_privatekey()))
    print(crypto.dump_certificate(crypto.FILETYPE_PEM, p12_file.get_certificate()))
​
    pem_file.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, p12_file.get_privatekey()))
    pem_file.write(crypto.dump_certificate(crypto.FILETYPE_PEM, p12_file.get_certificate()))
    ca = p12_file.get_ca_certificates()
    if ca is not None:
        for cert in ca:
            pem_file.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
    pem_file.close()
    return pem_file_path
​
if __name__ == '__main__':
    root_path = 'E:\dataPython\data\cert'
    cert_pem_file_path = p12_to_pem(os.path.join(root_path, 'baeldung'), b'****')
Copy the code

The content of the BAeldung. Pem SSL certificate file is as follows: The PRIVATE KEY is not the content of the SSL certificate, and certificate verification is not affected after it is deleted.

-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCN1bHqnX4kceSh
wSlb4s8X7Hz+581Kyq2tPDBSwqe6b9SmC5Hq0m8EbsChy/OwM9FrZZF9bOdPHHUM
sCtl3EEmc0fHylHqBT9/JWM=
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIDgjCCAmqgAwIBAgIEZacX2zANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJD
TjESMBAGA1UECBMJZ3Vhbmdkb25nMREwDwYDVQQHEwhzaGVuemhlbjENMAsGA1UE
9o2PulnUgwok+63gcbkCA1In7tz+qylx/bhz8qT0eI6WpsPYc0Y=
-----END CERTIFICATE-----
Copy the code
  1. In addition to using OpenSSL to convert the P12 to an SSL certificate in PEM format, you can use the browser function to export the certificate. After accessing the HTTPS interface of the server, perform the following steps to export an SSL certificate in cer format.

The exported SSL certificate file baeldung. Cer contains the following contents: Only the certificate content but no PRIVATE KEY.

-----BEGIN CERTIFICATE-----
MIIDgjCCAmqgAwIBAgIEZacX2zANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJD
TjESMBAGA1UECBMJZ3Vhbmdkb25nMREwDwYDVQQHEwhzaGVuemhlbjENMAsGA1UE
9o2PulnUgwok+63gcbkCA1In7tz+qylx/bhz8qT0eI6WpsPYc0Y=
-----END CERTIFICATE-----
Copy the code

Set the requests verify path to the CA BUNDLE file to verify that the certificate did not pass, either in pem or CER format.

import requests
from requests.packages import urllib3
if __name__ == '__main__':
    LOCAL_SERVICE_URL = 'https://localhost:1443/api/anno/success'
    REMOTE_SERVICE_URL = 'https://www.baidu.com/'
    print('\n-----request remote https-----')
    res = requests.get(REMOTE_SERVICE_URL)
    print(res.status_code)
    print('\n-----request local https-----')
    res = requests.get(LOCAL_SERVICE_URL, verify='E:/dataPython/data/cert/baeldung.pem')
    print(res.status_code)
    res = requests.get(LOCAL_SERVICE_URL, verify='E:/dataPython/data/cert/baeldung.cer')
    print(res.status_code)
Copy the code

Note: for https://www.baidu.com/, there are 3 layers of SSL certificates. Therefore, exporting only one layer of SSL certificates cannot be used as CA BUNDLE files. Otherwise, an error will be reported. The layer 3 certificate must be copied to a file from the bottom layer to the top layer (ROOT) to be used as a CA BUNDLE file. What is a CA Bundle and Where to Find It? Said operation.

Fourth attempt – set the self-issuing authority to be trusted – permanent

According to the result analysis of the first attempt, the list of trusted root certification authorities can be obtained from the cacert.pem file in the installation directory of the certifi package. Then, we can append the content of our self-issued certificate to the cacert.pem file to solve the SSL certificate verification problem once and for all. The cacert.pem file is as follows:

# Issuer: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA # Subject: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA # Label: "GlobalSign Root CA" # Serial: 4835703278459707669005204 # MD5 Fingerprint: 3e:45:52:15:09:51:92:e1:b7:5d:37:9f:b1:87:29:8a # SHA1 Fingerprint: b1:bc:96:8b:d4:f4:9d:62:2a:a8:9a:81:f2:15:01:52:a4:1d:82:9c # SHA256 Fingerprint: eb:d4:10:40:e4:bb:3e:c7:42:c9:e3:81:d3:1e:f2:a4:1a:48:b6:68:5c:96:e7:ce:f3:c1:df:6c:d4:33:1c:99 -----BEGIN CERTIFICATE----- MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== -----END CERTIFICATE----- # Issuer: CN=HARICA TLS ECC Root CA 2021 O=Hellenic Academic and Research Institutions CA # Subject: CN=HARICA TLS ECC Root CA 2021 O=Hellenic Academic and Research Institutions CA # Label: "HARICA TLS ECC Root CA 2021" # Serial: 137515985548005187474074462014555733966 # MD5 Fingerprint: ae:f7:4c:e5:66:35:d1:b7:9b:8c:22:93:74:d3:4b:b0 # SHA1 Fingerprint: bc:b0:c1:9d:e9:98:92:70:19:38:57:e9:8d:a7:b4:5d:6e:ee:01:48 # SHA256 Fingerprint: 3f:99:cc:47:4a:cf:ce:4d:fe:d5:87:94:66:5e:47:8d:15:47:73:9f:2e:78:0f:1b:b4:ca:9b:13:30:97:d4:01 -----BEGIN CERTIFICATE----- MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQsw nxS2PFOiTAZpffpskcYqSUXm7LcT4Tps -----END CERTIFICATE----- # omit other ROOT CA # SelfSigned -----BEGIN CERTIFICATE----- MIIDgjCCAmqgAwIBAgIEZacX2zANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJD TjESMBAGA1UECBMJZ3Vhbmdkb25nMREwDwYDVQQHEwhzaGVuemhlbjENMAsGA1UE 9o2PulnUgwok+63gcbkCA1In7tz+qylx/bhz8qT0eI6WpsPYc0Y= -----END CERTIFICATE-----Copy the code

Run the code from the first attempt again to invoke the HTTPS excuse, and the access is fine.

import requests
if __name__ == '__main__':
    LOCAL_SERVICE_URL = 'https://localhost:1443/api/anno/success'
    REMOTE_SERVICE_URL = 'https://www.baidu.com/'
    print('\n\n-----request remote https-----')
    res = requests.get(REMOTE_SERVICE_URL)
    print(res.status_code)
    print('\n\n-----request local https-----')
    res = requests.get(LOCAL_SERVICE_URL)
    print(res.status_code)
Copy the code

conclusion

Verify is used in the second, third, and fourth attempts. It is recommended that verify be set to the CA BUNDLE file path for better security.