├── tst ├── data │ ├── sign.txt │ ├── sign-tampered.txt │ ├── gibberish.pem │ ├── sign.txt.sha256 │ ├── raymii.org.2023.der │ ├── sign.tampered.sha256.txt │ ├── sign.txt.sha256.txt │ ├── expired.addtrusu.root.pem │ ├── expired.baddssl.com.cert.pem │ ├── Staat_der_Nederlanden_Root_CA.pem │ ├── expired.comodo.rsa.certification.authority.pem │ ├── expired-rsa-dv-ssl-com.pem │ ├── tst_sign.crt │ ├── USERTrust_RSA_Certification_Authority.pem │ ├── FAKE_USERTrust_RSA_Certification_Authority.pem │ ├── Incomplete-Chain-Sectigo_UserTRUST_RSA.pem │ ├── Sectigo_RSA_Domain_Validation_Secure_Server_CA.pem │ ├── example.org.crt │ ├── Staat_der_Nederlanden_Organisatie_Persoon_CA_G3.pem │ ├── chain-with-gibberish-root.pem │ ├── raymii.org.2023.pem │ ├── Digidentity_BV_PKIoverheid_Organisatie_Persoon_CA_G3.pem │ ├── example.org.key │ ├── tst_sign.key │ ├── chain-with-gibberish-intermidiate.pem │ ├── Chain-Staat_der_Nederlanden_Organisatie.pem │ ├── Chain-Sectigo_UserTRUST_RSA.pem │ ├── Fake-Chain-Sectigo_UserTRUST_RSA.pem │ ├── INCOMPLETE-expired-rsa-dv-ssl-com-chain.pem │ ├── expired.baddssl.com.chain.pem │ └── expired-rsa-dv-ssl-com-chain.pem ├── main.cpp ├── CMakeLists.txt └── OpenSSL-test.cpp ├── .gitmodules ├── CMakeLists.txt ├── .gitignore ├── sonar-project.properties ├── src ├── CMakeLists.txt ├── main.cpp ├── OpenSSL.h └── OpenSSL.cpp ├── .github └── workflows │ ├── cmake.yml │ └── codeql.yml ├── README.md └── LICENSE /tst/data/sign.txt: -------------------------------------------------------------------------------- 1 | Hello, World! 2 | -------------------------------------------------------------------------------- /tst/data/sign-tampered.txt: -------------------------------------------------------------------------------- 1 | Bye world 2 | -------------------------------------------------------------------------------- /tst/data/gibberish.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIF8zCCA9ugAwIBAgIULMvWbtN 3 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /tst/data/sign.txt.sha256: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaymiiOrg/openssl-modern-cpp/master/tst/data/sign.txt.sha256 -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/googletest"] 2 | path = lib/googletest 3 | url = git@github.com:google/googletest.git 4 | -------------------------------------------------------------------------------- /tst/data/raymii.org.2023.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaymiiOrg/openssl-modern-cpp/master/tst/data/raymii.org.2023.der -------------------------------------------------------------------------------- /tst/main.cpp: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | 3 | int main(int argc, char **argv) { 4 | ::testing::InitGoogleTest(&argc, argv); 5 | return RUN_ALL_TESTS(); 6 | } 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.24) 2 | project(openssl_modern_cpp) 3 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 4 | 5 | set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} --coverage") 6 | set(CMAKE_CXX_STANDARD 17) 7 | 8 | include_directories(src) 9 | 10 | add_subdirectory(src) 11 | add_subdirectory(tst) 12 | 13 | -------------------------------------------------------------------------------- /tst/data/sign.tampered.sha256.txt: -------------------------------------------------------------------------------- 1 | mXdfFBXWGMpM9GeGhGDGX/RJR6IYk85nH5kgB9dRDoLa+4Pr59eI8dU5V3oU1T6SgYvJFfJ3mqx7 2 | DXsi0ebkLPIUgwhfjOu3ItPDCT8KQzvWPB8qaR0Pm5iagf3H9K9wRRe08UDkGeGcO2ZtJouKiCa8 3 | wjqqZIrDLEXlC2KgoCJkwlKaATxIFMMECmYIKYkcyv2avc/gaF4NwfH+kYND+lO07ObRsscgFw0p 4 | WPCA7ZJryZHTOV6i/LsUBUPiqAAwnnCUkqo/qbhkzyoH+tLHvST63hCxiFc6RcB9fYJ+18fntJA= -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | 35 | .idea/** 36 | cmake-build-debug/** 37 | 38 | -------------------------------------------------------------------------------- /tst/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(BINARY ${CMAKE_PROJECT_NAME}_tst) 2 | 3 | file(GLOB_RECURSE TEST_SOURCES LIST_DIRECTORIES false *.h *.cpp) 4 | set(SOURCES ${TEST_SOURCES}) 5 | 6 | add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../lib/googletest ${CMAKE_CURRENT_BINARY_DIR}/googletest) 7 | include(GoogleTest) 8 | enable_testing() 9 | 10 | add_executable(${BINARY} ${TEST_SOURCES}) 11 | add_test(NAME ${BINARY} COMMAND ${BINARY}) 12 | 13 | target_link_libraries(${BINARY} PUBLIC ${CMAKE_PROJECT_NAME}_lib gtest) 14 | -------------------------------------------------------------------------------- /sonar-project.properties: -------------------------------------------------------------------------------- 1 | sonar.projectKey=RaymiiOrg_openssl-modern-cpp 2 | sonar.organization=rve 3 | 4 | sonar.sources=. 5 | sonar.cfamily.compile-commands=build/compile_commands.json 6 | sonar.coverageReportPaths=coverage.xml 7 | sonar.exclusions=lib/**,build/** 8 | sonar.coverage.exclusions=tst/**,src/main.cpp 9 | 10 | # This is the name and version displayed in the SonarCloud UI. 11 | #sonar.projectName=openssl-modern-cpp 12 | #sonar.projectVersion=1.0 13 | 14 | # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. 15 | #sonar.sources=. 16 | 17 | # Encoding of the source code. Default is default system encoding 18 | #sonar.sourceEncoding=UTF-8 19 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(BINARY ${CMAKE_PROJECT_NAME}) 2 | 3 | file(GLOB_RECURSE SOURCES LIST_DIRECTORIES true *.h *.cpp) 4 | 5 | set(SOURCES ${SOURCES}) 6 | 7 | add_executable(${BINARY}_run ${SOURCES}) 8 | 9 | add_library(${BINARY}_lib STATIC ${SOURCES}) 10 | 11 | find_package(OpenSSL REQUIRED) 12 | if(OPENSSL_FOUND) 13 | MESSAGE(STATUS "Using OpenSSL: ${OPENSSL_VERSION} from: ${OPENSSL_LIBRARIES}") 14 | target_link_libraries(${BINARY}_run ${OPENSSL_LIBRARIES}) 15 | target_include_directories(${BINARY}_run PUBLIC ${OPENSSL_INCLUDE_DIR}) 16 | target_link_libraries(${BINARY}_lib ${OPENSSL_LIBRARIES}) 17 | target_include_directories(${BINARY}_lib PUBLIC ${OPENSSL_INCLUDE_DIR}) 18 | endif() 19 | -------------------------------------------------------------------------------- /tst/data/sign.txt.sha256.txt: -------------------------------------------------------------------------------- 1 | mXdfFBXWGMpM9GeGhGDGX/RJR6IYk85nH5kgB9dRDoLa+4Pr59eI8dU5V3oU1T6SgYvJFfJ3mqx7 2 | nhVHn0eji9meRjfFqedeuNdOCCn/IiOo2u2kO42DXOlQ7ONAN1WW9U/kGYFXy3ibxGS93AepTho4 3 | g0nMkpGq/4ymzPP4t7bRDmHaFfiWIYVa4AT4lPuqxd42078E3KWL+6NhfDagDRgAZTsmBPNrZ9k7 4 | pRBDDdFzFIFWJSWATg/xt0fGePuEqYLv1ycHWKU8P0V7XfUb+g1NtwjhwX6jTqpGBaEBxb7CKgcD 5 | ow5cpIdaZbmGCfZGl6bU0Znxq0n5Mpf4vSbuUJruf8K5Hw5f4iN4XFjKQh7RzvW9wdU4Jo2rX0Ln 6 | lXcVm0Ue3sXZY5QC0CZ0Rv5DXKo3xzLgGhTBvx7D1/Nqoot/T7vvEXJfGt/kPdt5qeMAf/wyetvc 7 | DXsi0ebkLPIUgwhfjOu3ItPDCT8KQzvWPB8qaR0Pm5iagf3H9K9wRRe08UDkGeGcO2ZtJouKiCa8 8 | wjqqZIrDLEXlC2KgoCJkwlKaATxIFMMECmYIKYkcyv2avc/gaF4NwfH+kYND+lO07ObRsscgFw0p 9 | WPCA7ZJryZHTOV6i/LsUBUPiqAAwnnCUkqo/qbhkzyoH+tLHvST63hCxiFc6RcB9fYJ+18fntJA= -------------------------------------------------------------------------------- /tst/data/expired.addtrusu.root.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU 3 | MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN1IEV4dGVybmFs 4 | IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 5 | MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux 6 | FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h 7 | bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v 8 | dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt 9 | H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 10 | uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX 11 | mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX 12 | a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN 13 | E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 14 | WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD 15 | VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 16 | Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU 17 | cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx 18 | IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN 19 | AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH 20 | YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 21 | 6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC 22 | Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX 23 | c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a 24 | mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= 25 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /.github/workflows/cmake.yml: -------------------------------------------------------------------------------- 1 | name: CMake 2 | 3 | on: push 4 | 5 | env: 6 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 7 | BUILD_TYPE: Release 8 | 9 | jobs: 10 | build: 11 | # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. 12 | # You can convert this to a matrix build if you need cross-platform coverage. 13 | # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v3 18 | with: 19 | submodules: recursive 20 | 21 | - name: Install sonar-scanner and build-wrapper 22 | uses: SonarSource/sonarcloud-github-c-cpp@v1 23 | 24 | - name: Install gcovr 25 | run: pip install gcovr 26 | 27 | - name: Configure CMake 28 | # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. 29 | # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type 30 | run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_EXPORT_COMPILE_COMMANDS=1 31 | 32 | - name: Build 33 | # Build your program with the given configuration 34 | run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}xd 35 | 36 | - name: Run tests 37 | working-directory: ${{github.workspace}}/build/tst 38 | run: ctest -C ${{env.BUILD_TYPE}} 39 | 40 | - name: Collect coverage into one XML report 41 | run: | 42 | gcovr --sonarqube > coverage.xml 43 | 44 | - name: Run sonar-scanner 45 | env: 46 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 47 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 48 | run: | 49 | sonar-scanner 50 | 51 | -------------------------------------------------------------------------------- /tst/data/expired.baddssl.com.cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFSzCCBDOgAwIBAgIQSueVSfqavj8QDxekeOFpCTANBgkqhkiG9w0BAQsFADCB 3 | kDELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G 4 | A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxNjA0BgNV 5 | BAMTLUNPTU9ETyBSU0EgRG9tYWluIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZlciBD 6 | QTAeFw0xNTA0MDkwMDAwMDBaFw0xNTA0MTIyMzU5NTlaMFkxITAfBgNVBAsTGERv 7 | bWFpbiBDb250cm9sIFZhbGlkYXRlZDEdMBsGA1UECxMUUG9zaXRpdmVTU0wgV2ls 8 | ZGNhcmQxFTATBgNVBAMUDCouYmFkc3NsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD 9 | ggEPADCCAQoCggEBAMIE7PiM7gTCs9hQ1XBYzJMY61yoaEmwIrX5lZ6xKyx2PmzA 10 | S2BMTOqytMAPgLaw+XLJhgL5XEFdEyt/ccRLvOmULlA3pmccYYz2QULFRtMWhyef 11 | dOsKnRFSJiFzbIRMeVXk0WvoBj1IFVKtsyjbqv9u/2CVSndrOfEk0TG23U3AxPxT 12 | uW1CrbV8/q71FdIzSOciccfCFHpsKOo3St/qbLVytH5aohbcabFXRNsKEqveww9H 13 | dFxBIuGa+RuT5q0iBikusbpJHAwnnqP7i/dAcgCskgjZjFeEU4EFy+b+a1SYQCeF 14 | xxC7c3DvaRhBB0VVfPlkPz0sw6l865MaTIbRyoUCAwEAAaOCAdUwggHRMB8GA1Ud 15 | IwQYMBaAFJCvajqUWgvYkOoSVnPfQ7Q6KNrnMB0GA1UdDgQWBBSd7sF7gQs6R2lx 16 | GH0RN5O8pRs/+zAOBgNVHQ8BAf8EBAMCBaAwDAYDVR0TAQH/BAIwADAdBgNVHSUE 17 | FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwTwYDVR0gBEgwRjA6BgsrBgEEAbIxAQIC 18 | BzArMCkGCCsGAQUFBwIBFh1odHRwczovL3NlY3VyZS5jb21vZG8uY29tL0NQUzAI 19 | BgZngQwBAgEwVAYDVR0fBE0wSzBJoEegRYZDaHR0cDovL2NybC5jb21vZG9jYS5j 20 | b20vQ09NT0RPUlNBRG9tYWluVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNybDCB 21 | hQYIKwYBBQUHAQEEeTB3ME8GCCsGAQUFBzAChkNodHRwOi8vY3J0LmNvbW9kb2Nh 22 | LmNvbS9DT01PRE9SU0FEb21haW5WYWxpZGF0aW9uU2VjdXJlU2VydmVyQ0EuY3J0 23 | MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wIwYDVR0RBBww 24 | GoIMKi5iYWRzc2wuY29tggpiYWRzc2wuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQBq 25 | evHa/wMHcnjFZqFPRkMOXxQhjHUa6zbgH6QQFezaMyV8O7UKxwE4PSf9WNnM6i1p 26 | OXy+l+8L1gtY54x/v7NMHfO3kICmNnwUW+wHLQI+G1tjWxWrAPofOxkt3+IjEBEH 27 | fnJ/4r+3ABuYLyw/zoWaJ4wQIghBK4o+gk783SHGVnRwpDTysUCeK1iiWQ8dSO/r 28 | ET7BSp68ZVVtxqPv1dSWzfGuJ/ekVxQ8lEEFeouhN0fX9X3c+s5vMaKwjOrMEpsi 29 | 8TRwz311SotoKQwe6Zaoz7ASH1wq7mcvf71z81oBIgxw+s1F73hczg36TuHvzmWf 30 | RwxPuzZEaFZcVlmtqoq8 31 | -----END CERTIFICATE----- 32 | -------------------------------------------------------------------------------- /tst/data/Staat_der_Nederlanden_Root_CA.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | 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 31 | 94B7IWcnMFk= 32 | -----END CERTIFICATE----- 33 | 34 | -------------------------------------------------------------------------------- /tst/data/expired.comodo.rsa.certification.authority.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFdDCCBFygAwIBAgIQJ2buVutJ846r13Ci/ITeIjANBgkqhkiG9w0BAQwFADBv 3 | MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk 4 | ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF 5 | eHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFow 6 | gYUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO 7 | BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYD 8 | VQQDEyJDT01PRE8gUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkq 9 | hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAkehUktIKVrGsDSTdxc9EZ3SZKzejfSNw 10 | AHG8U9/E+ioSj0t/EFa9n3Byt2F/yUsPF6c947AEYe7/EZfH9IY+Cvo+XPmT5jR6 11 | 2RRr55yzhaCCenavcZDX7P0N+pxs+t+wgvQUfvm+xKYvT3+Zf7X8Z0NyvQwA1onr 12 | ayzT7Y+YHBSrfuXjbvzYqOSSJNpDa2K4Vf3qwbxstovzDo2a5JtsaZn4eEgwRdWt 13 | 4Q08RWD8MpZRJ7xnw8outmvqRsfHIKCxH2XeSAi6pE6p8oNGN4Tr6MyBSENnTnIq 14 | m1y9TBsoilwie7SrmNnu4FGDwwlGTm0+mfqVF9p8M1dBPI1R7Qu2XK8sYxrfV8g/ 15 | vOldxJuvRZnio1oktLqpVj3Pb6r/SVi+8Kj/9Lit6Tf7urj0Czr56ENCHonYhMsT 16 | 8dm74YlguIwoVqwUHZwK53Hrzw7dPamWoUi9PPevtQ0iTMARgexWO/bTouJbt7IE 17 | IlKVgJNp6I5MZfGRAy1wdALqi2cVKWlSArvX31BqVUa/oKMoYX9w0MOiqiwhqkfO 18 | KJwGRXa/ghgntNWutMtQ5mv0TIZxMOmm3xaG4Nj/QN370EKIf6MzOi5cHkERgWPO 19 | GHFrK+ymircxXDpqR+DDeVnWIBqv8mqYqnK8V0rSS527EPywTEHl7R09XiidnMy/ 20 | s1Hap0flhFMCAwEAAaOB9DCB8TAfBgNVHSMEGDAWgBStvZh6NLQm9/rEJlTvA73g 21 | JMtUGjAdBgNVHQ4EFgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQD 22 | AgGGMA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAGBgRVHSAAMEQGA1UdHwQ9 23 | MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9BZGRUcnVzdEV4dGVy 24 | bmFsQ0FSb290LmNybDA1BggrBgEFBQcBAQQpMCcwJQYIKwYBBQUHMAGGGWh0dHA6 25 | Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggEBAGS/g/FfmoXQ 26 | zbihKVcN6Fr30ek+8nYEbvFScLsePP9NDXRqzIGCJdPDoCpdTPW6i6FtxFQJdcfj 27 | Jw5dhHk3QBN39bSsHNA7qxcS1u80GH4r6XnTq1dFDK8o+tDb5VCViLvfhVdpfZLY 28 | Uspzgb8c8+a4bmYRBbMelC1/kZWSWfFMzqORcUx8Rww7Cxn2obFshj5cqsQugsv5 29 | B5a6SE2Q8pTIqXOi6wZ7I53eovNNVZ96YUWYGGjHXkBrI/V5eu+MtWuLt29G9Hvx 30 | PUsE2JOAWVrgQSQdso8VYFhH2+9uRv0V9dlfmrPb2LjkQLPNlzmuhbsdjrzch5vR 31 | pu/xO28QOG8= 32 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /tst/data/expired-rsa-dv-ssl-com.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFpjCCA46gAwIBAgIIRyCT6kmYDVMwDQYJKoZIhvcNAQELBQAwaTELMAkGA1UE 3 | BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK 4 | DA9TU0wgQ29ycG9yYXRpb24xHjAcBgNVBAMMFVNTTC5jb20gUlNBIFNTTCBzdWJD 5 | QTAeFw0xNjA4MDEyMDQ4MzBaFw0xNjA4MDIyMDQ4MzBaMCExHzAdBgNVBAMMFmV4 6 | cGlyZWQtcnNhLWR2LnNzbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK 7 | AoIBAQCaMDqEemvY/MyKWNa2qLgdvKp0WwyLepukVj5TQpdNCxWoi6oVdzYiveAq 8 | biZUCZLw8zP8aVix86P6CGNmUShWB1T/YovFeX+uatbjoYDEbPd9pLmcEXpV6n/d 9 | /A07H257+oSn9QPB7uWQSy6QTZvqfHDWz8LFw7SVbEL9S09JTm++9VDQZOBxJD/4 10 | yW6LZtIbXNkHd7Ms8uFQpFqSGXGjE0PfLkAKhPKpLyven+pDu4Tb2bktVAkDcO/F 11 | r14utC/yDp4bBIwD7/VHKSIDgBBNyVN2XRAOu2Z8S/YaKhvuhLXhj5qBDe+cb/Dv 12 | gTT6WIarInEepWMaUDEUHzVGSXc5AgMBAAGjggGYMIIBlDAfBgNVHSMEGDAWgBQm 13 | FH7g3Nem9+LUBCffYfHC7OcyyjBxBggrBgEFBQcBAQRlMGMwPwYIKwYBBQUHMAKG 14 | M2h0dHA6Ly93d3cuc3NsLmNvbS9yZXBvc2l0b3J5L1NTTGNvbVJTQVNTTHN1YkNB 15 | LmNlcjAgBggrBgEFBQcwAYYUaHR0cDovL29jc3BzLnNzbC5jb20wIQYDVR0RBBow 16 | GIIWZXhwaXJlZC1yc2EtZHYuc3NsLmNvbTBRBgNVHSAESjBIMDwGDCsGAQQBgqkw 17 | AQEBADAsMCoGCCsGAQUFBwIBFh5odHRwczovL3d3dy5zc2wuY29tL3JlcG9zaXRv 18 | cnkwCAYGZ4EMAQIBMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATA6BgNV 19 | HR8EMzAxMC+gLaArhilodHRwOi8vY3Jscy5zc2wuY29tL1NTTGNvbVJTQVNTTHN1 20 | YkNBLmNybDAdBgNVHQ4EFgQUY+Ay4OqtPYRt4+l7lXrYlqg72DwwDgYDVR0PAQH/ 21 | BAQDAgWgMA0GCSqGSIb3DQEBCwUAA4ICAQBFet1IDrHxXKj0j4EoJ+/Belksj4dp 22 | QADGuwPE2FOxWeTiBUfe3GZ2c6ObZj9HkZOhX8668SWwdTz2rYH4iyeVcikUby3u 23 | zO3vSUzwj5GS9VFnpp4XNJQ6m7lN3teL8N0tV2feTCBrYfJFxzbzo+QXrD7rMiX1 24 | Y9GgMuGxoGwlycVyMI04eDi4qOSb7GOrzHzqjtFpG58OyRccJyjmeIGD2cVvGUVA 25 | 7EiIjW3ZHY1Lr2HsHvrJGhCS+Yepr1vb1LSVNSK6z9irD610NKnDnVVWT8MA4ZmY 26 | 2MiXMvRPahafbo2VXy3sNJOvIq5YCeMWVNQGZhIKUmfWTPOwpzyW/nZMTprnG0q6 27 | DKCfypMMCzlkaLK+i2XCPjJjyLL4KoCs+hZks2hgdQ8qzdiUyHuRm30L8jJ+q8bP 28 | QERe9KKFBaKueGbjiL5aYD3sgMf9wC4LuJ89PQsJ+RKU7VHFpVxcH11JBPnlRAcF 29 | qeA5xnEKpnkHoQFIggzJ8gkNRuqCIW9VAi2jKNE4Beik9G8opr5WDAzapSrLMqIn 30 | Ob1DCPLMhJiQpHFpPtrSp8PKY7fU9nL8/pRfW0vNP+ntdGpm3p19sdvqsvekVZti 31 | 7fWCDUVfIxJzKY0zklMHBKn0/7Dp3LLLK30MiyJCtBhsISpz/ITsY3oIO28p7Zqt 32 | Yt1CKrI0cgiClQ== 33 | -----END CERTIFICATE----- 34 | -------------------------------------------------------------------------------- /tst/data/tst_sign.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | 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 33 | 1L4QPZ7DhA== 34 | -----END CERTIFICATE----- 35 | -------------------------------------------------------------------------------- /tst/data/USERTrust_RSA_Certification_Authority.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB 3 | iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl 4 | cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV 5 | BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw 6 | MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV 7 | BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU 8 | aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy 9 | dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK 10 | AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B 11 | 3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY 12 | tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ 13 | Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 14 | VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT 15 | 79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 16 | c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT 17 | Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l 18 | c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee 19 | UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE 20 | Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd 21 | BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G 22 | A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF 23 | Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO 24 | VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 25 | ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs 26 | 8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR 27 | iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze 28 | Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ 29 | XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ 30 | qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB 31 | VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB 32 | L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG 33 | jjxDah2nGN59PRbxYvnKkKj9 34 | -----END CERTIFICATE----- 35 | -------------------------------------------------------------------------------- /tst/data/FAKE_USERTrust_RSA_Certification_Authority.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIF8zCCA9ugAwIBAgIULMvWbtNN62Z97rdPcBUbSUNC6B4wDQYJKoZIhvcNAQEL 3 | BQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApOZXcgSmVyc2V5MRQwEgYDVQQH 4 | DAtKZXJzZXkgQ2l0eTEeMBwGA1UECgwVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4w 5 | LAYDVQQDDCVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X 6 | DTIzMDMxMjE5NDMyMFoXDTI0MDMxMTE5NDMyMFowgYgxCzAJBgNVBAYTAlVTMRMw 7 | EQYDVQQIDApOZXcgSmVyc2V5MRQwEgYDVQQHDAtKZXJzZXkgQ2l0eTEeMBwGA1UE 8 | CgwVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQDDCVVU0VSVHJ1c3QgUlNB 9 | IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A 10 | MIICCgKCAgEAwPua5Rj2q930/AQo+EFFWorzi4AUTEQ4mRhb1f8KhYOqVeO9chp9 11 | mUdbe2jsBKhO9JXLIbfAxBj+M2uqz99TbnPpUrWjsR6XkAvEEZjRITRV9hD+bds0 12 | JnUtg+PXKaqb2znfNfqTB+Ws5N2lxeeWyGNRAwgzASigynJsXPU6NsvxDJcKkkEf 13 | HihLQsiNFlhxnMhRn2lcH/OhZLt2Yjsd5vbKVgs6Bk6hYBvUiShRSSNLOgzZaL/q 14 | IkrcfKodUvT04zhhm9WExpcaInoEOl3qevyC2MFzbna3RaQBeKFZFB2kKXJW3roj 15 | 7pVSHP1Odi5q/Gji+HZlu60VZZ/WmWt1UpNkdnV/7F0udw54XodnVZ038+Cpov8l 16 | vVhtPK7jQIcvOhStNA9kQ5ID+cd9IGuQTp0u2H4fY4rF2yr35Nsw0hBPI/uSXUPa 17 | FqxzTskRjWLFuSTgfhAtDz4mTqwqAW1OI9VwkysZZPD2tLiIfFDdxiLqJLUqPyL2 18 | GgSJqrDXU9HC4qM6ZZgwVWG7SGn38CBEhC2AhakcxMn9gfvK7XCjNkBNXfq6FhGc 19 | cYPDzbQxbLZNK6lGmiAJ5N0RNG7SqlwX5DoKxHAO5+0eOIEI2wg2jc3eU2r82jUo 20 | wpgveEDW7GRUI/2iK/dJpDdg5c1DOsRJ1/eXQ5F8QNpGt507k1zjUkECAwEAAaNT 21 | MFEwHQYDVR0OBBYEFEdwqqwTnMinDnYQTLnd4cR0iYADMB8GA1UdIwQYMBaAFEdw 22 | qqwTnMinDnYQTLnd4cR0iYADMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL 23 | BQADggIBAFXYCYdmfbwyfCWQ0T26gZYdxuDDi4yM6WJt+uKIKZ9lvB+3Llfk8hq9 24 | w+qzbdFHpO7hKCgAGi30dkRFBENyZa7J31sHBpsiwKpDNdxo3v5R5wgdiEQsdq3V 25 | JU665B0hrv1eWSLK5hH023kRlwGYJBYJtDWXCku4eI/zV8SI64FdVCzi6bptH7OO 26 | 2s+PdcSrxTeJflu4+Dn3TdauokU7Z+Xk/LGETyl8PMmGyaHNGGyfdWbARwzQadxW 27 | +6UIa89HlVFkO2+uQS4dZkTyuPJ7zvDt0075vJlRVPwSK/lI/icXnomgL6Op7qOQ 28 | +3GKLKXzQhSjwI/X4Xc2MDJ+YSy67upUStlGxV0wEsq04s7sghs3r29+cFmJ/whc 29 | j+e+xHIoq64CnDtk7+nR4U2iJiwbFjy2Stk7pOlnk/thtt3k90MwW0HA7niEx3sx 30 | xk8LcFOmU3eKwtVBihhlkGUVl/WxQeWFh9HrTsiY3FOAABYOymWY2GfHchEbv7Tn 31 | k4BmSd9XdPzDZYy8r+AVb6vthuqVkweMcLI+j3/P7FFPunc+fLTWU8L6m0qWgs4O 32 | KztYdN53eJPmPSsooRVuxYpweune8TQK035io9KHe/ybahn/j4fg3E0LFFdGHISM 33 | 1U76kiqlqitGwLTx9fz9aSJ+judsoZaVJW2p1pUzaT5A2b+gNkcf 34 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /tst/data/Incomplete-Chain-Sectigo_UserTRUST_RSA.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIGEzCCA/ugAwIBAgIQfVtRJrR2uhHbdBYLvFMNpzANBgkqhkiG9w0BAQwFADCB 3 | iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl 4 | cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV 5 | BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx 6 | MTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBjzELMAkGA1UEBhMCR0IxGzAZBgNV 7 | BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE 8 | ChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQDEy5TZWN0aWdvIFJTQSBEb21haW4g 9 | VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC 10 | AQ8AMIIBCgKCAQEA1nMz1tc8INAA0hdFuNY+B6I/x0HuMjDJsGz99J/LEpgPLT+N 11 | TQEMgg8Xf2Iu6bhIefsWg06t1zIlk7cHv7lQP6lMw0Aq6Tn/2YHKHxYyQdqAJrkj 12 | eocgHuP/IJo8lURvh3UGkEC0MpMWCRAIIz7S3YcPb11RFGoKacVPAXJpz9OTTG0E 13 | oKMbgn6xmrntxZ7FN3ifmgg0+1YuWMQJDgZkW7w33PGfKGioVrCSo1yfu4iYCBsk 14 | Haswha6vsC6eep3BwEIc4gLw6uBK0u+QDrTBQBbwb4VCSmT3pDCg/r8uoydajotY 15 | uK3DGReEY+1vVv2Dy2A0xHS+5p3b4eTlygxfFQIDAQABo4IBbjCCAWowHwYDVR0j 16 | BBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFI2MXsRUrYrhd+mb 17 | +ZsF4bgBjWHhMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0G 18 | A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAbBgNVHSAEFDASMAYGBFUdIAAw 19 | CAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0 20 | LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2Bggr 21 | BgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNv 22 | bS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDov 23 | L29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAMr9hvQ5Iw0/H 24 | ukdN+Jx4GQHcEx2Ab/zDcLRSmjEzmldS+zGea6TvVKqJjUAXaPgREHzSyrHxVYbH 25 | 7rM2kYb2OVG/Rr8PoLq0935JxCo2F57kaDl6r5ROVm+yezu/Coa9zcV3HAO4OLGi 26 | H19+24rcRki2aArPsrW04jTkZ6k4Zgle0rj8nSg6F0AnwnJOKf0hPHzPE/uWLMUx 27 | RP0T7dWbqWlod3zu4f+k+TY4CFM5ooQ0nBnzvg6s1SQ36yOoeNDT5++SR2RiOSLv 28 | xvcRviKFxmZEJCaOEDKNyJOuB56DPi/Z+fVGjmO+wea03KbNIaiGCpXZLoUmGv38 29 | sbZXQm2V0TP2ORQGgkE49Y9Y3IBbpNV9lXj9p5v//cWoaasm56ekBYdbqbe4oyAL 30 | l6lFhd2zi+WJN44pDfwGF/Y4QA5C5BIG+3vzxhFoYt/jmPQT2BVPi7Fp2RBgvGQq 31 | 6jG35LWjOhSbJuMLe/0CjraZwTiXWTb2qHSihrZe68Zk6s+go/lunrotEbaGmAhY 32 | LcmsJWTyXnW0OMGuf1pGg+pRyrbxmRE1a6Vqe8YAsOf4vmSyrcjC8azjUeqkk+B5 33 | yOGBQMkKW+ESPMFgKuOXwIlCypTPRpgSabuY0MLTDXJLR27lk8QyKGOHQ+SwMj4K 34 | 00u/I5sUKUErmgQfky3xxzlIPK1aEn8= 35 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /tst/data/Sectigo_RSA_Domain_Validation_Secure_Server_CA.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIGEzCCA/ugAwIBAgIQfVtRJrR2uhHbdBYLvFMNpzANBgkqhkiG9w0BAQwFADCB 3 | iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl 4 | cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV 5 | BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx 6 | MTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBjzELMAkGA1UEBhMCR0IxGzAZBgNV 7 | BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE 8 | ChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQDEy5TZWN0aWdvIFJTQSBEb21haW4g 9 | VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC 10 | AQ8AMIIBCgKCAQEA1nMz1tc8INAA0hdFuNY+B6I/x0HuMjDJsGz99J/LEpgPLT+N 11 | TQEMgg8Xf2Iu6bhIefsWg06t1zIlk7cHv7lQP6lMw0Aq6Tn/2YHKHxYyQdqAJrkj 12 | eocgHuP/IJo8lURvh3UGkEC0MpMWCRAIIz7S3YcPb11RFGoKacVPAXJpz9OTTG0E 13 | oKMbgn6xmrntxZ7FN3ifmgg0+1YuWMQJDgZkW7w33PGfKGioVrCSo1yfu4iYCBsk 14 | Haswha6vsC6eep3BwEIc4gLw6uBK0u+QDrTBQBbwb4VCSmT3pDCg/r8uoydajotY 15 | uK3DGReEY+1vVv2Dy2A0xHS+5p3b4eTlygxfFQIDAQABo4IBbjCCAWowHwYDVR0j 16 | BBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFI2MXsRUrYrhd+mb 17 | +ZsF4bgBjWHhMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0G 18 | A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAbBgNVHSAEFDASMAYGBFUdIAAw 19 | CAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0 20 | LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2Bggr 21 | BgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNv 22 | bS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDov 23 | L29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAMr9hvQ5Iw0/H 24 | ukdN+Jx4GQHcEx2Ab/zDcLRSmjEzmldS+zGea6TvVKqJjUAXaPgREHzSyrHxVYbH 25 | 7rM2kYb2OVG/Rr8PoLq0935JxCo2F57kaDl6r5ROVm+yezu/Coa9zcV3HAO4OLGi 26 | H19+24rcRki2aArPsrW04jTkZ6k4Zgle0rj8nSg6F0AnwnJOKf0hPHzPE/uWLMUx 27 | RP0T7dWbqWlod3zu4f+k+TY4CFM5ooQ0nBnzvg6s1SQ36yOoeNDT5++SR2RiOSLv 28 | xvcRviKFxmZEJCaOEDKNyJOuB56DPi/Z+fVGjmO+wea03KbNIaiGCpXZLoUmGv38 29 | sbZXQm2V0TP2ORQGgkE49Y9Y3IBbpNV9lXj9p5v//cWoaasm56ekBYdbqbe4oyAL 30 | l6lFhd2zi+WJN44pDfwGF/Y4QA5C5BIG+3vzxhFoYt/jmPQT2BVPi7Fp2RBgvGQq 31 | 6jG35LWjOhSbJuMLe/0CjraZwTiXWTb2qHSihrZe68Zk6s+go/lunrotEbaGmAhY 32 | LcmsJWTyXnW0OMGuf1pGg+pRyrbxmRE1a6Vqe8YAsOf4vmSyrcjC8azjUeqkk+B5 33 | yOGBQMkKW+ESPMFgKuOXwIlCypTPRpgSabuY0MLTDXJLR27lk8QyKGOHQ+SwMj4K 34 | 00u/I5sUKUErmgQfky3xxzlIPK1aEn8= 35 | -----END CERTIFICATE----- 36 | -------------------------------------------------------------------------------- /tst/data/example.org.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | 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 35 | QUA= 36 | -----END CERTIFICATE----- 37 | -------------------------------------------------------------------------------- /tst/data/Staat_der_Nederlanden_Organisatie_Persoon_CA_G3.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIGSDCCBDCgAwIBAgIEAJiiRjANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO 3 | TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh 4 | dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEczMB4XDTEzMTExNDE1MDkzN1oX 5 | DTI4MTExMjIzMDAwMFowaTELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl 6 | ciBOZWRlcmxhbmRlbjE6MDgGA1UEAwwxU3RhYXQgZGVyIE5lZGVybGFuZGVuIE9y 7 | Z2FuaXNhdGllIFBlcnNvb24gQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIP 8 | ADCCAgoCggIBAL5i6Bk6ei6+96HCdS3EBJGBcN9Zn3vNRRex4IRjbwAWeAVI6SR3 9 | 9R6YNiL/lOeTQkvnWsRb1cpWSFCCLExY65UzjwxWUD/Qw55Yx/6uxoJ4bYjI33Ud 10 | QZuUyx1vbf97d4KadXLpixkwbswLMuF6o+P4vd8Kl0ZEfoFI7Ky3Lt6Z1V1s3C2D 11 | 0sIH+EvxA143s6imwkRFz1ffKEl34D2QAFBcIUt4hRIW88emy0QCDY/rQjOJvfGu 12 | BrnSQXDLVDQGh/vAM2nLz9hr9pz7sK+KxJOa4PYqSpwgyPV1O25IQNU8M22OPask 13 | Q5DhaW7wahXZVjoBhJJqIwl5CVWTidOh9/N4J9gkfdLj8Um99BApfyTLSZdXzHm9 14 | FOvJB2boXJLsOonpNwWtqd69CDlGqaXVnApUKwWNvA8pul++6J6ErorHlISuSlLD 15 | ULlDyAk6K2zdqK9OjYInUY2BkJFkygzTkOjg0oa63ksln1NekN/tyXDFFvFZB1IQ 16 | Q24RrXMYqXN8dX/wWuxDDCj+lmQyMjf0j+QzcVJIGmgm1eZLA/9wQWRypzlpbyyh 17 | Yp1ShPzzs4CyQB9DqpzAohm39TR0EwN63AaTNlyO7c4z7aIVu2c7bYgJdd30J6MC 18 | gW0d6e3d7+jtGtyf4jhOCVK0F+2Vl5HreZIGxTYFDA+FKspOBse7xd6nAgMBAAGj 19 | ggEFMIIBATAPBgNVHRMBAf8EBTADAQH/MF0GA1UdIARWMFQwDAYKYIQQAYdrAQIF 20 | ATAMBgpghBABh2sBAgUCMDYGCmCEEAGHawECBQMwKDAmBggrBgEFBQcCARYaaHR0 21 | cHM6Ly9jcHMucGtpb3ZlcmhlaWQubmwwDgYDVR0PAQH/BAQDAgEGMB8GA1UdIwQY 22 | MBaAFFSt+seSV67KNZwuEvvkul0g3JRXMD8GA1UdHwQ4MDYwNKAyoDCGLmh0dHA6 23 | Ly9jcmwucGtpb3ZlcmhlaWQubmwvUm9vdExhdGVzdENSTC1HMy5jcmwwHQYDVR0O 24 | BBYEFO6sbUDq1QRqhyxVe/U/Ldru26ziMA0GCSqGSIb3DQEBCwUAA4ICAQAc0SFs 25 | KlBFkqBzLK5lYqEK2QLsFRL8LUs/M0lgPagWV6s821nXdpsizZN5ogXzHwspo+vw 26 | wHh0q88CNZ8tsm2pwVNz36eQsPRL2sPlz82VVVZf59gYsfoTcH2ID7n5mtT0YeHT 27 | k5ESYIJhQfxv9JGa24QMN3EXPetPNpJYdW0yQUbejwpsE4eSV95FPweb7DqfsEfW 28 | 1kNgsZ2lF2CJQ3KvKOlJmuQHRCiS9FC278ysBHQZHUK4WcabDKg2/C3B1JH2QeaI 29 | +S1Vdy3hldxgfrhj2jiUGbddDvLah3vxWeu0FuymAfyz1xmPSOsllKqms6aevdF4 30 | JW8kBBUaNI5d8X+9TpRFMrV79udP7amHxpreX3XRBrF4mG1EK4zCVUDxSm+4BjvZ 31 | y2cfMdTV6PpAzHI2I2ljqy7eofDphlILUSvKBD/OUmaFvvGmj8/nXWj4lo6Zj8Yw 32 | huM3/B/ivITuqgyJkAXsFc4r5135VT+h6UVFk6G9rrMBaqBCO5nSwt8woXs9e85T 33 | v7kLA1lSezbKCeJ6QPoKLQbSJL/aVNyv6BAR/1ySUH5jsTeXHg/yEI42KfszLaM6 34 | ckD1Q+nXlqscn0toycwkA93mt7pfHxote8UGv+qyIky8MW1+lDXLjhqfHt7Hkdlv 35 | nRbsryYG+8XwaaUqYyo74oTC45c56ey4gAGgBQ== 36 | -----END CERTIFICATE----- 37 | -------------------------------------------------------------------------------- /tst/data/chain-with-gibberish-root.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIGEzCCA/ugAwIBAgIQfVtRJrR2uhHbdBYLvFMNpzANBgkqhkiG9w0BAQwFADCB 3 | iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl 4 | cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV 5 | BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx 6 | MTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBjzELMAkGA1UEBhMCR0IxGzAZBgNV 7 | BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE 8 | ChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQDEy5TZWN0aWdvIFJTQSBEb21haW4g 9 | VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC 10 | AQ8AMIIBCgKCAQEA1nMz1tc8INAA0hdFuNY+B6I/x0HuMjDJsGz99J/LEpgPLT+N 11 | TQEMgg8Xf2Iu6bhIefsWg06t1zIlk7cHv7lQP6lMw0Aq6Tn/2YHKHxYyQdqAJrkj 12 | eocgHuP/IJo8lURvh3UGkEC0MpMWCRAIIz7S3YcPb11RFGoKacVPAXJpz9OTTG0E 13 | oKMbgn6xmrntxZ7FN3ifmgg0+1YuWMQJDgZkW7w33PGfKGioVrCSo1yfu4iYCBsk 14 | Haswha6vsC6eep3BwEIc4gLw6uBK0u+QDrTBQBbwb4VCSmT3pDCg/r8uoydajotY 15 | uK3DGReEY+1vVv2Dy2A0xHS+5p3b4eTlygxfFQIDAQABo4IBbjCCAWowHwYDVR0j 16 | BBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFI2MXsRUrYrhd+mb 17 | +ZsF4bgBjWHhMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0G 18 | A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAbBgNVHSAEFDASMAYGBFUdIAAw 19 | CAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0 20 | LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2Bggr 21 | BgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNv 22 | bS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDov 23 | L29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAMr9hvQ5Iw0/H 24 | ukdN+Jx4GQHcEx2Ab/zDcLRSmjEzmldS+zGea6TvVKqJjUAXaPgREHzSyrHxVYbH 25 | 7rM2kYb2OVG/Rr8PoLq0935JxCo2F57kaDl6r5ROVm+yezu/Coa9zcV3HAO4OLGi 26 | H19+24rcRki2aArPsrW04jTkZ6k4Zgle0rj8nSg6F0AnwnJOKf0hPHzPE/uWLMUx 27 | RP0T7dWbqWlod3zu4f+k+TY4CFM5ooQ0nBnzvg6s1SQ36yOoeNDT5++SR2RiOSLv 28 | xvcRviKFxmZEJCaOEDKNyJOuB56DPi/Z+fVGjmO+wea03KbNIaiGCpXZLoUmGv38 29 | sbZXQm2V0TP2ORQGgkE49Y9Y3IBbpNV9lXj9p5v//cWoaasm56ekBYdbqbe4oyAL 30 | l6lFhd2zi+WJN44pDfwGF/Y4QA5C5BIG+3vzxhFoYt/jmPQT2BVPi7Fp2RBgvGQq 31 | 6jG35LWjOhSbJuMLe/0CjraZwTiXWTb2qHSihrZe68Zk6s+go/lunrotEbaGmAhY 32 | LcmsJWTyXnW0OMGuf1pGg+pRyrbxmRE1a6Vqe8YAsOf4vmSyrcjC8azjUeqkk+B5 33 | yOGBQMkKW+ESPMFgKuOXwIlCypTPRpgSabuY0MLTDXJLR27lk8QyKGOHQ+SwMj4K 34 | 00u/I5sUKUErmgQfky3xxzlIPK1aEn8= 35 | -----END CERTIFICATE----- 36 | -----BEGIN CERTIFICATE----- 37 | MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB 38 | jjxDah2nGN59PRbxYvnKkKj9 39 | -----END CERTIFICATE----- 40 | -------------------------------------------------------------------------------- /tst/data/raymii.org.2023.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIHLjCCBhagAwIBAgIQcAuZ3LmvyqD6VkaeqMrkszANBgkqhkiG9w0BAQsFADCB 3 | jzELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G 4 | A1UEBxMHU2FsZm9yZDEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQD 5 | Ey5TZWN0aWdvIFJTQSBEb21haW4gVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENB 6 | MB4XDTIzMDEwODAwMDAwMFoXDTI0MDEyNDIzNTk1OVowFTETMBEGA1UEAxMKcmF5 7 | bWlpLm9yZzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL8+S6wObdQb 8 | +KsyV/vm0JskdHmD6QXv64MxIeRIRgz6E+iXdYLQOfVWiDx65GoNHjmN8XJZKN0z 9 | 0qOQn7RjIGkFmvP4aPHwoUubIwpbnGpzEs++PidDvRhNBsNFpnIV8J1A2j69FNfF 10 | QOTI+ZsPsd3CfWB2aWWZId6u1z9V+djERe9+XhVVwGkXLsa11GH/fgnBGfWoXVP6 11 | 7T9fdrhbEaYWGA1hZOWeQbHMspAi4ImkJcKrOaQ0DRAbdiOFis5lMvG10UR0AuCC 12 | rvF9a2w0G/Du1euFXdKopiwzCovggPo7b4pwu5oZFTgvBRuqGYLEdMayEeBWO/Mg 13 | A1wx5ed0I4lJi3ljtIXzUwDX/hhrjaNanFV6WyVURbydR6U0nKfHPdvhlZkoKs+B 14 | CAhx/dshcJvpTsh3W4++0bajw04Ujxb4YCkIcEm84b2otyZ7INCX9GbFJvyiRqzE 15 | DRVg+HBksMT5/zFrCxhhRkIC0rsOkaMpSh01lBE5TxSnfwC1xE7LVmfwhDow+vkI 16 | 9Qb8vRqYaxa8mawjCu373bAY5wz+TjHHXjYHsBhfPWqlueW405DnzCEgW9a0XWCn 17 | 1vDdGgO4Ut4Vt4GMDERaOMcmS+PqEYPf6DNCXChsLimmao2hQ7nDYqQ9hhQ7HZJu 18 | 2WI/AiMSe8r0y+ANcdsRza4O35p7dRh1AgMBAAGjggL9MIIC+TAfBgNVHSMEGDAW 19 | gBSNjF7EVK2K4Xfpm/mbBeG4AY1h4TAdBgNVHQ4EFgQUXqg5HcIH3nzbUZfLW8F4 20 | /n9sWc4wDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYI 21 | KwYBBQUHAwEGCCsGAQUFBwMCMEkGA1UdIARCMEAwNAYLKwYBBAGyMQECAgcwJTAj 22 | BggrBgEFBQcCARYXaHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwCAYGZ4EMAQIBMIGE 23 | BggrBgEFBQcBAQR4MHYwTwYIKwYBBQUHMAKGQ2h0dHA6Ly9jcnQuc2VjdGlnby5j 24 | b20vU2VjdGlnb1JTQURvbWFpblZhbGlkYXRpb25TZWN1cmVTZXJ2ZXJDQS5jcnQw 25 | IwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3RpZ28uY29tMCUGA1UdEQQeMByC 26 | CnJheW1paS5vcmeCDnd3dy5yYXltaWkub3JnMIIBfwYKKwYBBAHWeQIEAgSCAW8E 27 | ggFrAWkAdwB2/4g/Crb7lVHCYcz1h7o0tKTNuyncaEIKn+ZnTFo6dAAAAYWRTHPq 28 | AAAEAwBIMEYCIQCeYN9L9aWzXyXUP2c0xyWjdOZznUI8mvzFTqS+qWKezQIhAIbg 29 | ggrtQo3d2bKl8nCOzGZXx/W8NaRBvEj/df59jXkxAHYA2ra/az+1tiKfm8K7XGvo 30 | cJFxbLtRhIU0vaQ9MEjX+6sAAAGFkUxzvQAABAMARzBFAiEAj5GVP8VEdj61cP9o 31 | pFkiGBoi2uOXbN6slDOink0rzOQCIFaE6d9Poif0Ms16BnHpaWA+FfdeVK/3u30x 32 | DobBMdmfAHYA7s3QZNXbGs7FXLedtM0TojKHRny87N7DUUhZRnEftZsAAAGFkUxz 33 | iQAABAMARzBFAiBN96pJVZ3kpOiJOqdrm6xjIpoQ61lgJIYHW+j3Yd7GgQIhANxg 34 | tntpgYEIDOS+G8D4/KkcoqYYaGhh1mIhnd5T4ZS0MA0GCSqGSIb3DQEBCwUAA4IB 35 | AQChWuF/uOnEmzmiCo8BWbf3PALgevmDaPmy6PcdxfIWg8TR2PsOAmIVkv3YxiKv 36 | JYBdtiLXliFvPdsaojk5mwRKayPehUgJgzawfrVIPxMUPMPCt9ULGVN8PnkeosvG 37 | 1gNjw6JuYDrxYooBy1zV3RtZXQfQhSb96R27wuCEECr871AuH0Cott0HBjiwxEnd 38 | ICgdbUJf4n4e5rs2Z5QWnssc1ZD6OpofWnW//1bG6JILTegNbDX163JBLEVxAmj6 39 | lLsbTfGaoJSTAtGDYOF7zRMuNDgQnw9+dIE6nTmOMI72x7Mnx1/LrD//LMlfN0kZ 40 | gjbupuLLn6D6MjP2UyKpahqc 41 | -----END CERTIFICATE----- 42 | -------------------------------------------------------------------------------- /tst/data/Digidentity_BV_PKIoverheid_Organisatie_Persoon_CA_G3.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIHVDCCBTygAwIBAgIUTCAvTLEaU7ToLOG4iPY+q8IbmI8wDQYJKoZIhvcNAQEL 3 | BQAwaTELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRl 4 | bjE6MDgGA1UEAwwxU3RhYXQgZGVyIE5lZGVybGFuZGVuIE9yZ2FuaXNhdGllIFBl 5 | cnNvb24gQ0EgLSBHMzAeFw0xOTA0MTcwODQyMDRaFw0yODExMTIwMDAwMDBaMIGC 6 | MQswCQYDVQQGEwJOTDEZMBcGA1UECgwQRGlnaWRlbnRpdHkgQi5WLjEXMBUGA1UE 7 | YQwOTlRSTkwtMjczMjI2MzExPzA9BgNVBAMMNkRpZ2lkZW50aXR5IEJWIFBLSW92 8 | ZXJoZWlkIE9yZ2FuaXNhdGllIFBlcnNvb24gQ0EgLSBHMzCCAiIwDQYJKoZIhvcN 9 | AQEBBQADggIPADCCAgoCggIBAL/MtUDP+XQNHP9/3GDw2B0iFojRaaEHGHi1bpyX 10 | i5dsElWMEBZ6XJKY93YaRcslKlEpeQJ4pPo78Zl+rY8Spp2Ox5bXewrLa/85Wmda 11 | HnrfG1hxCkyR0LM03Ayo3xo0eVu6TZp1cQLnUXb4rH+8qfzdz52EhbUUJdI7lEoV 12 | O4xLC3ydmzFtRmAsSb37xT/vTR3vs7IFlRxFBFwjQTtc1D6PBTijf8mv8aGqtMrj 13 | WqU7thdh1e19kxXFlsl9VkWVpGmfDdGsr35huXPPMS2rrGKWdtIgKDmintYcVPyG 14 | wsr9OL2Xxk4w5rFrE+YooOj2rqmwl5pT+InAjbZuuCpd6zxg/XqI1n+GFXtQvPP9 15 | CAs/CaeghW+BQeXiMTnzOByUFsbk2Rpr8emw47fAsufxqisXE2bQnpVv+oEvUhZi 16 | 2eQPA6rTizcdINICZpC8i+mWmvhnKB8uhcSIhB1tbB3jKPYW3z+QCV1trNAMIRO8 17 | MiHyWjkyDRnS5O6GyuLU1wOjhCklqDyI4pXW1Mpf+rbFaQieIfcvoBZNOCD3aQJj 18 | g+/cOHLS/tbfUEu9nlwag1gUmG6fQNJvj6FMcWU1KkcC8EgfGRHYZTeFhx1Qp/bN 19 | Ncw9t91XPVDaqWdi13ohrPg/7qlSpMu61veUFUsWiymb8Qse4drr0bfx8RH/dpFu 20 | Z/n/AgMBAAGjggHYMIIB1DBVBggrBgEFBQcBAQRJMEcwRQYIKwYBBQUHMAKGOWh0 21 | dHA6Ly9jZXJ0LnBraW92ZXJoZWlkLm5sL0RvbU9yZ2FuaXNhdGllUGVyc29vbkNB 22 | LUczLmNlcjAdBgNVHQ4EFgQUZG1d46hMpTbuJjYv9VdUT7hSff8wEgYDVR0TAQH/ 23 | BAgwBgEB/wIBADAfBgNVHSMEGDAWgBTurG1A6tUEaocsVXv1Py3a7tus4jAlBggr 24 | BgEFBQcBAwQZMBcwFQYIKwYBBQUHCwIwCQYHBACL7EkBAjBdBgNVHSAEVjBUMAwG 25 | CmCEEAGHawECBQEwNgYKYIQQAYdrAQIFAjAoMCYGCCsGAQUFBwIBFhpodHRwczov 26 | L2Nwcy5wa2lvdmVyaGVpZC5ubDAMBgpghBABh2sBAgUDMFAGA1UdHwRJMEcwRaBD 27 | oEGGP2h0dHA6Ly9jcmwucGtpb3ZlcmhlaWQubmwvRG9tT3JnYW5pc2F0aWVQZXJz 28 | b29uTGF0ZXN0Q1JMLUczLmNybDAOBgNVHQ8BAf8EBAMCAQYwPwYDVR0lBDgwNgYI 29 | KwYBBQUHAwIGCCsGAQUFBwMEBgorBgEEAYI3CgMMBgorBgEEAYI3CgMEBggrBgEF 30 | BQcDCTANBgkqhkiG9w0BAQsFAAOCAgEAPihRUdJik1NSvghFQT3PWGumPGO+/Yjd 31 | gQ+AkdZgDd/PB/NuJD6K0tNIJ+siKf1RuFnniZIx9hM6W7YrbamCi/MRLh5Ikpig 32 | 00wm3M0l9WwCr9UFeIv1wi1kR7HEEg7h7ltkZnH0ueigBse5QhVxUhQLZHd6WsUJ 33 | oHE1MPxCkX59VKsagx0yRwOWhV83OJfZHCrx9rnMO74mdfpwfjZ96CzJIyjWlumd 34 | +HUMxI+FsceM1f6SZ3XYLEfmNu3SM6zMF2bsSYsnH7X3o1L8gdyRHYZa3vJ6/EzV 35 | Et4fHO7K+qZhtX+O8/n0bV18QtjZchLhiCKiGK2NjHGSL55dLLzFlNM7OnViw7v5 36 | +9hCORZBCeKwVsuJxYIMM1hXARyiSJmrJWlzYBQ3/e1Z52Ev2QzI0YeTlTgqzK8Y 37 | ydGPmOufdIDZhdM76hw2xo+4qeNirh47O1Op4Lt/wfJxkf00Czu+xWluFnYfpuoL 38 | ldHRYYRFFb3JYkerG+wDzcVyd/582OYUTo86O0XqzRYkrcL3jqYgMDCk/ynHePiq 39 | PToBvYEjFt68rGNFTvhNdFeQk3D0fyQqulW6ANLwyvpmN3ghfjjCKZIPYUv4nOKi 40 | FPj+UNisBIvRvgzfcc8thGKZVdMtrQNGNtdCXeT50p89Q97SrslO6SigoL11oXRG 41 | Uh4MClcBULE= 42 | -----END CERTIFICATE----- 43 | 44 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 Remy van Elst 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, version 3. 7 | * 8 | * This program is distributed in the hope that it will be useful, but 9 | * WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | * General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | */ 17 | 18 | #include "OpenSSL.h" 19 | #include 20 | #include 21 | #include 22 | 23 | void printSignatureValidationResult(int goodSignature) { 24 | switch(goodSignature) { 25 | case 1: 26 | std::cout << "Signature valid" << std::endl; 27 | break; 28 | case 0: 29 | std::cout << "Signature INVALID"<< std::endl; 30 | break; 31 | default: 32 | std::cout << "Failed to verify signature. Cert incomplete, " 33 | "ill-formed or other erro" << std::endl; 34 | break; 35 | } 36 | } 37 | 38 | int main(int argc, char **argv) 39 | { 40 | 41 | // runs in build/src folder, certs are in tst folder 42 | std::string cert_pem_filename = "../../tst/data/raymii.org.2023.pem"; 43 | std::string pem_chain_filename = "../../tst/data/Chain-Sectigo_UserTRUST_RSA.pem"; 44 | 45 | 46 | if(!std::filesystem::exists(cert_pem_filename) || 47 | !std::filesystem::exists(pem_chain_filename)) 48 | return 1; 49 | 50 | std::ifstream cert_pem_in(cert_pem_filename); 51 | std::string cert_pem((std::istreambuf_iterator(cert_pem_in)), 52 | std::istreambuf_iterator()); 53 | 54 | std::ifstream pem_chain_in(pem_chain_filename); 55 | std::string pem_chain((std::istreambuf_iterator(pem_chain_in)), 56 | std::istreambuf_iterator()); 57 | 58 | 59 | X509_uptr cert_x509 = OpenSSL::cert_to_x509(cert_pem); 60 | 61 | std::cout << "certificate subject: " << OpenSSL::x509_subject(cert_x509.get()) << std::endl; 62 | std::cout << "certificate sans : "; 63 | for(const auto& s : OpenSSL::x509_subject_alternative_dns_names(cert_x509.get())) 64 | std::cout << s << " "; 65 | std::cout << std::endl; 66 | std::cout << "certificate issuer : " << OpenSSL::x509_issuer(cert_x509.get()) << std::endl; 67 | 68 | int goodSignature = OpenSSL::verify_cert_signed_by_chain(cert_pem, pem_chain); 69 | std::cout << "Issuer signed by chain (should be valid): "; 70 | printSignatureValidationResult(goodSignature); 71 | 72 | 73 | std::cout << std::endl << "** Take a look at the unit tests for more usage examples! **" << std::endl; 74 | } 75 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push 16 | 17 | 18 | jobs: 19 | analyze: 20 | name: Analyze 21 | runs-on: ubuntu-latest 22 | permissions: 23 | actions: read 24 | contents: read 25 | security-events: write 26 | 27 | strategy: 28 | fail-fast: false 29 | matrix: 30 | language: [ 'cpp' ] 31 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 32 | # Use only 'java' to analyze code written in Java, Kotlin or both 33 | # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both 34 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 35 | 36 | steps: 37 | - name: Checkout repository 38 | uses: actions/checkout@v3 39 | with: 40 | submodules: recursive 41 | 42 | # Initializes the CodeQL tools for scanning. 43 | - name: Initialize CodeQL 44 | uses: github/codeql-action/init@v2 45 | with: 46 | languages: ${{ matrix.language }} 47 | # If you wish to specify custom queries, you can do so here or in a config file. 48 | # By default, queries listed here will override any specified in a config file. 49 | # Prefix the list here with "+" to use these queries and those in the config file. 50 | 51 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 52 | # queries: security-extended,security-and-quality 53 | 54 | 55 | # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). 56 | # If this step fails, then you should remove it and run the build manually (see below) 57 | - name: Autobuild 58 | uses: github/codeql-action/autobuild@v2 59 | 60 | # ℹ️ Command-line programs to run using the OS shell. 61 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 62 | 63 | # If the Autobuild fails above, remove it and uncomment the following three lines. 64 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 65 | 66 | # - run: | 67 | # echo "Run, Build Application using script" 68 | # ./location_of_script_within_repo/buildscript.sh 69 | 70 | - name: Perform CodeQL Analysis 71 | uses: github/codeql-action/analyze@v2 72 | with: 73 | category: "/language:${{matrix.language}}" 74 | -------------------------------------------------------------------------------- /tst/data/example.org.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | 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 51 | Et5KhQNegv1NlDNCebxJ3UbWtbvd 52 | -----END PRIVATE KEY----- 53 | -------------------------------------------------------------------------------- /tst/data/tst_sign.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | 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 51 | 5T/pEV1vrFMhHpv7TP61Hm65RMu7 52 | -----END PRIVATE KEY----- 53 | -------------------------------------------------------------------------------- /tst/data/chain-with-gibberish-intermidiate.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIGEzCCA/ugAwIBAgIQfVtRJrR2uhHbdBYLvFMNpzANBgkqhkiG9w0BAQwFADCB 3 | iDELMAkGA1UEBhMCVVMxEzARBgEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE 4 | ChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQDEy5TZWN0aWdvIFJTQSBEb21haW4g 5 | VmFsaWRhdGlvbiBTZWN1cmUgU2V9lXj9p5v//cWoaasm56ekBYdbqbe4oyAL 6 | l6lFhd2zi+WJN44pDfwGF/Y4QA5C5BIG+3vzxhFoYt/jmPQT2BVPi7Fp2RBgvGQq 7 | 6jG35LWjOhSbJuMLe/0CjraZwTiXWTb2qHSihrZe68Zk6s+go/lunrotEbaGmAhY 8 | LcmsJWTyXnW0OMGuf1pGg+pRyrbxmRE1a6Vqe8YAsOf4vmSyrcjC8azjUeqkk+B5 9 | yOGBQMkKW+ESPMFgKuOXwIlCypTPRpgSabuY0MLTDXJLR27lk8QyKGOHQ+SwMj4K 10 | 00u/I5sUKUErmgQfky3xxzlIPK1aEn8= 11 | -----END CERTIFICATE----- 12 | -----BEGIN CERTIFICATE----- 13 | MIIGEzCCA/ugAwIBAgIQfVtRJrR2uhHbdBYLvFMNpzANBgkqhkiG9w0BAQwFADCB 14 | iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl 15 | cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV 16 | BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx 17 | MTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBjzELMAkGA1UEBhMCR0IxGzAZBgNV 18 | BAgTEkdyZWF0ZXIgTWFu/cWoaasm56ekBYdbqbe4oyAL 19 | l6lFhd2zi+WJN44pDfwGF/Y4QA5C5BIG+3vzxhFoYt/jmPQT2BVPi7Fp2RBgvGQq 20 | 6jG35LWjOhSbJuMLe/0CjraZwTiXWTb2qHSihrZe68Zk6s+go/lunrotEbaGmAhY 21 | LcmsJWTyXnW0OMGuf1pGg+pRyrbxmRE1a6Vqe8YAsOf4vmSyrcjC8azjUeqkk+B5 22 | yOGBQMkKW+ESPMFgKuOXwIlCypTPRpgSabuY0MLTDXJLR27lk8QyKGOHQ+SwMj4K 23 | 00u/I5sUKUErmgQfky3xxzlIPK1aEn8= 24 | -----END CERTIFICATE----- 25 | -----BEGIN CERTIFICATE----- 26 | MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB 27 | iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl 28 | cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV 29 | BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw 30 | MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV 31 | BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU 32 | aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy 33 | dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK 34 | AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B 35 | 3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY 36 | tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ 37 | Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 38 | VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT 39 | 79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 40 | c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT 41 | Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l 42 | c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee 43 | UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE 44 | Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd 45 | BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G 46 | A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF 47 | Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO 48 | VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 49 | ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs 50 | 8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR 51 | iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze 52 | Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ 53 | XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ 54 | qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB 55 | VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB 56 | L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG 57 | jjxDah2nGN59PRbxYvnKkKj9 58 | -----END CERTIFICATE----- 59 | -------------------------------------------------------------------------------- /tst/data/Chain-Staat_der_Nederlanden_Organisatie.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIGSDCCBDCgAwIBAgIEAJiiRjANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO 3 | TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh 4 | dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEczMB4XDTEzMTExNDE1MDkzN1oX 5 | DTI4MTExMjIzMDAwMFowaTELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl 6 | ciBOZWRlcmxhbmRlbjE6MDgGA1UEAwwxU3RhYXQgZGVyIE5lZGVybGFuZGVuIE9y 7 | Z2FuaXNhdGllIFBlcnNvb24gQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIP 8 | ADCCAgoCggIBAL5i6Bk6ei6+96HCdS3EBJGBcN9Zn3vNRRex4IRjbwAWeAVI6SR3 9 | 9R6YNiL/lOeTQkvnWsRb1cpWSFCCLExY65UzjwxWUD/Qw55Yx/6uxoJ4bYjI33Ud 10 | QZuUyx1vbf97d4KadXLpixkwbswLMuF6o+P4vd8Kl0ZEfoFI7Ky3Lt6Z1V1s3C2D 11 | 0sIH+EvxA143s6imwkRFz1ffKEl34D2QAFBcIUt4hRIW88emy0QCDY/rQjOJvfGu 12 | BrnSQXDLVDQGh/vAM2nLz9hr9pz7sK+KxJOa4PYqSpwgyPV1O25IQNU8M22OPask 13 | Q5DhaW7wahXZVjoBhJJqIwl5CVWTidOh9/N4J9gkfdLj8Um99BApfyTLSZdXzHm9 14 | FOvJB2boXJLsOonpNwWtqd69CDlGqaXVnApUKwWNvA8pul++6J6ErorHlISuSlLD 15 | ULlDyAk6K2zdqK9OjYInUY2BkJFkygzTkOjg0oa63ksln1NekN/tyXDFFvFZB1IQ 16 | Q24RrXMYqXN8dX/wWuxDDCj+lmQyMjf0j+QzcVJIGmgm1eZLA/9wQWRypzlpbyyh 17 | Yp1ShPzzs4CyQB9DqpzAohm39TR0EwN63AaTNlyO7c4z7aIVu2c7bYgJdd30J6MC 18 | gW0d6e3d7+jtGtyf4jhOCVK0F+2Vl5HreZIGxTYFDA+FKspOBse7xd6nAgMBAAGj 19 | ggEFMIIBATAPBgNVHRMBAf8EBTADAQH/MF0GA1UdIARWMFQwDAYKYIQQAYdrAQIF 20 | ATAMBgpghBABh2sBAgUCMDYGCmCEEAGHawECBQMwKDAmBggrBgEFBQcCARYaaHR0 21 | cHM6Ly9jcHMucGtpb3ZlcmhlaWQubmwwDgYDVR0PAQH/BAQDAgEGMB8GA1UdIwQY 22 | MBaAFFSt+seSV67KNZwuEvvkul0g3JRXMD8GA1UdHwQ4MDYwNKAyoDCGLmh0dHA6 23 | Ly9jcmwucGtpb3ZlcmhlaWQubmwvUm9vdExhdGVzdENSTC1HMy5jcmwwHQYDVR0O 24 | BBYEFO6sbUDq1QRqhyxVe/U/Ldru26ziMA0GCSqGSIb3DQEBCwUAA4ICAQAc0SFs 25 | KlBFkqBzLK5lYqEK2QLsFRL8LUs/M0lgPagWV6s821nXdpsizZN5ogXzHwspo+vw 26 | wHh0q88CNZ8tsm2pwVNz36eQsPRL2sPlz82VVVZf59gYsfoTcH2ID7n5mtT0YeHT 27 | k5ESYIJhQfxv9JGa24QMN3EXPetPNpJYdW0yQUbejwpsE4eSV95FPweb7DqfsEfW 28 | 1kNgsZ2lF2CJQ3KvKOlJmuQHRCiS9FC278ysBHQZHUK4WcabDKg2/C3B1JH2QeaI 29 | +S1Vdy3hldxgfrhj2jiUGbddDvLah3vxWeu0FuymAfyz1xmPSOsllKqms6aevdF4 30 | JW8kBBUaNI5d8X+9TpRFMrV79udP7amHxpreX3XRBrF4mG1EK4zCVUDxSm+4BjvZ 31 | y2cfMdTV6PpAzHI2I2ljqy7eofDphlILUSvKBD/OUmaFvvGmj8/nXWj4lo6Zj8Yw 32 | huM3/B/ivITuqgyJkAXsFc4r5135VT+h6UVFk6G9rrMBaqBCO5nSwt8woXs9e85T 33 | v7kLA1lSezbKCeJ6QPoKLQbSJL/aVNyv6BAR/1ySUH5jsTeXHg/yEI42KfszLaM6 34 | ckD1Q+nXlqscn0toycwkA93mt7pfHxote8UGv+qyIky8MW1+lDXLjhqfHt7Hkdlv 35 | nRbsryYG+8XwaaUqYyo74oTC45c56ey4gAGgBQ== 36 | -----END CERTIFICATE----- 37 | -----BEGIN CERTIFICATE----- 38 | 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 67 | 94B7IWcnMFk= 68 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /tst/data/Chain-Sectigo_UserTRUST_RSA.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIGEzCCA/ugAwIBAgIQfVtRJrR2uhHbdBYLvFMNpzANBgkqhkiG9w0BAQwFADCB 3 | iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl 4 | cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV 5 | BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx 6 | MTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBjzELMAkGA1UEBhMCR0IxGzAZBgNV 7 | BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE 8 | ChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQDEy5TZWN0aWdvIFJTQSBEb21haW4g 9 | VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC 10 | AQ8AMIIBCgKCAQEA1nMz1tc8INAA0hdFuNY+B6I/x0HuMjDJsGz99J/LEpgPLT+N 11 | TQEMgg8Xf2Iu6bhIefsWg06t1zIlk7cHv7lQP6lMw0Aq6Tn/2YHKHxYyQdqAJrkj 12 | eocgHuP/IJo8lURvh3UGkEC0MpMWCRAIIz7S3YcPb11RFGoKacVPAXJpz9OTTG0E 13 | oKMbgn6xmrntxZ7FN3ifmgg0+1YuWMQJDgZkW7w33PGfKGioVrCSo1yfu4iYCBsk 14 | Haswha6vsC6eep3BwEIc4gLw6uBK0u+QDrTBQBbwb4VCSmT3pDCg/r8uoydajotY 15 | uK3DGReEY+1vVv2Dy2A0xHS+5p3b4eTlygxfFQIDAQABo4IBbjCCAWowHwYDVR0j 16 | BBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFI2MXsRUrYrhd+mb 17 | +ZsF4bgBjWHhMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0G 18 | A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAbBgNVHSAEFDASMAYGBFUdIAAw 19 | CAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0 20 | LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2Bggr 21 | BgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNv 22 | bS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDov 23 | L29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAMr9hvQ5Iw0/H 24 | ukdN+Jx4GQHcEx2Ab/zDcLRSmjEzmldS+zGea6TvVKqJjUAXaPgREHzSyrHxVYbH 25 | 7rM2kYb2OVG/Rr8PoLq0935JxCo2F57kaDl6r5ROVm+yezu/Coa9zcV3HAO4OLGi 26 | H19+24rcRki2aArPsrW04jTkZ6k4Zgle0rj8nSg6F0AnwnJOKf0hPHzPE/uWLMUx 27 | RP0T7dWbqWlod3zu4f+k+TY4CFM5ooQ0nBnzvg6s1SQ36yOoeNDT5++SR2RiOSLv 28 | xvcRviKFxmZEJCaOEDKNyJOuB56DPi/Z+fVGjmO+wea03KbNIaiGCpXZLoUmGv38 29 | sbZXQm2V0TP2ORQGgkE49Y9Y3IBbpNV9lXj9p5v//cWoaasm56ekBYdbqbe4oyAL 30 | l6lFhd2zi+WJN44pDfwGF/Y4QA5C5BIG+3vzxhFoYt/jmPQT2BVPi7Fp2RBgvGQq 31 | 6jG35LWjOhSbJuMLe/0CjraZwTiXWTb2qHSihrZe68Zk6s+go/lunrotEbaGmAhY 32 | LcmsJWTyXnW0OMGuf1pGg+pRyrbxmRE1a6Vqe8YAsOf4vmSyrcjC8azjUeqkk+B5 33 | yOGBQMkKW+ESPMFgKuOXwIlCypTPRpgSabuY0MLTDXJLR27lk8QyKGOHQ+SwMj4K 34 | 00u/I5sUKUErmgQfky3xxzlIPK1aEn8= 35 | -----END CERTIFICATE----- 36 | -----BEGIN CERTIFICATE----- 37 | MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB 38 | iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl 39 | cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV 40 | BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw 41 | MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV 42 | BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU 43 | aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy 44 | dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK 45 | AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B 46 | 3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY 47 | tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ 48 | Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 49 | VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT 50 | 79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 51 | c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT 52 | Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l 53 | c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee 54 | UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE 55 | Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd 56 | BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G 57 | A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF 58 | Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO 59 | VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 60 | ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs 61 | 8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR 62 | iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze 63 | Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ 64 | XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ 65 | qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB 66 | VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB 67 | L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG 68 | jjxDah2nGN59PRbxYvnKkKj9 69 | -----END CERTIFICATE----- 70 | -------------------------------------------------------------------------------- /tst/data/Fake-Chain-Sectigo_UserTRUST_RSA.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIGEzCCA/ugAwIBAgIQfVtRJrR2uhHbdBYLvFMNpzANBgkqhkiG9w0BAQwFADCB 3 | iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl 4 | cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV 5 | BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx 6 | MTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBjzELMAkGA1UEBhMCR0IxGzAZBgNV 7 | BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE 8 | ChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQDEy5TZWN0aWdvIFJTQSBEb21haW4g 9 | VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC 10 | AQ8AMIIBCgKCAQEA1nMz1tc8INAA0hdFuNY+B6I/x0HuMjDJsGz99J/LEpgPLT+N 11 | TQEMgg8Xf2Iu6bhIefsWg06t1zIlk7cHv7lQP6lMw0Aq6Tn/2YHKHxYyQdqAJrkj 12 | eocgHuP/IJo8lURvh3UGkEC0MpMWCRAIIz7S3YcPb11RFGoKacVPAXJpz9OTTG0E 13 | oKMbgn6xmrntxZ7FN3ifmgg0+1YuWMQJDgZkW7w33PGfKGioVrCSo1yfu4iYCBsk 14 | Haswha6vsC6eep3BwEIc4gLw6uBK0u+QDrTBQBbwb4VCSmT3pDCg/r8uoydajotY 15 | uK3DGReEY+1vVv2Dy2A0xHS+5p3b4eTlygxfFQIDAQABo4IBbjCCAWowHwYDVR0j 16 | BBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFI2MXsRUrYrhd+mb 17 | +ZsF4bgBjWHhMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0G 18 | A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAbBgNVHSAEFDASMAYGBFUdIAAw 19 | CAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0 20 | LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2Bggr 21 | BgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNv 22 | bS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDov 23 | L29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAMr9hvQ5Iw0/H 24 | ukdN+Jx4GQHcEx2Ab/zDcLRSmjEzmldS+zGea6TvVKqJjUAXaPgREHzSyrHxVYbH 25 | 7rM2kYb2OVG/Rr8PoLq0935JxCo2F57kaDl6r5ROVm+yezu/Coa9zcV3HAO4OLGi 26 | H19+24rcRki2aArPsrW04jTkZ6k4Zgle0rj8nSg6F0AnwnJOKf0hPHzPE/uWLMUx 27 | RP0T7dWbqWlod3zu4f+k+TY4CFM5ooQ0nBnzvg6s1SQ36yOoeNDT5++SR2RiOSLv 28 | xvcRviKFxmZEJCaOEDKNyJOuB56DPi/Z+fVGjmO+wea03KbNIaiGCpXZLoUmGv38 29 | sbZXQm2V0TP2ORQGgkE49Y9Y3IBbpNV9lXj9p5v//cWoaasm56ekBYdbqbe4oyAL 30 | l6lFhd2zi+WJN44pDfwGF/Y4QA5C5BIG+3vzxhFoYt/jmPQT2BVPi7Fp2RBgvGQq 31 | 6jG35LWjOhSbJuMLe/0CjraZwTiXWTb2qHSihrZe68Zk6s+go/lunrotEbaGmAhY 32 | LcmsJWTyXnW0OMGuf1pGg+pRyrbxmRE1a6Vqe8YAsOf4vmSyrcjC8azjUeqkk+B5 33 | yOGBQMkKW+ESPMFgKuOXwIlCypTPRpgSabuY0MLTDXJLR27lk8QyKGOHQ+SwMj4K 34 | 00u/I5sUKUErmgQfky3xxzlIPK1aEn8= 35 | -----END CERTIFICATE----- 36 | -----BEGIN CERTIFICATE----- 37 | MIIF8zCCA9ugAwIBAgIULMvWbtNN62Z97rdPcBUbSUNC6B4wDQYJKoZIhvcNAQEL 38 | BQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApOZXcgSmVyc2V5MRQwEgYDVQQH 39 | DAtKZXJzZXkgQ2l0eTEeMBwGA1UECgwVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4w 40 | LAYDVQQDDCVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X 41 | DTIzMDMxMjE5NDMyMFoXDTI0MDMxMTE5NDMyMFowgYgxCzAJBgNVBAYTAlVTMRMw 42 | EQYDVQQIDApOZXcgSmVyc2V5MRQwEgYDVQQHDAtKZXJzZXkgQ2l0eTEeMBwGA1UE 43 | CgwVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQDDCVVU0VSVHJ1c3QgUlNB 44 | IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A 45 | MIICCgKCAgEAwPua5Rj2q930/AQo+EFFWorzi4AUTEQ4mRhb1f8KhYOqVeO9chp9 46 | mUdbe2jsBKhO9JXLIbfAxBj+M2uqz99TbnPpUrWjsR6XkAvEEZjRITRV9hD+bds0 47 | JnUtg+PXKaqb2znfNfqTB+Ws5N2lxeeWyGNRAwgzASigynJsXPU6NsvxDJcKkkEf 48 | HihLQsiNFlhxnMhRn2lcH/OhZLt2Yjsd5vbKVgs6Bk6hYBvUiShRSSNLOgzZaL/q 49 | IkrcfKodUvT04zhhm9WExpcaInoEOl3qevyC2MFzbna3RaQBeKFZFB2kKXJW3roj 50 | 7pVSHP1Odi5q/Gji+HZlu60VZZ/WmWt1UpNkdnV/7F0udw54XodnVZ038+Cpov8l 51 | vVhtPK7jQIcvOhStNA9kQ5ID+cd9IGuQTp0u2H4fY4rF2yr35Nsw0hBPI/uSXUPa 52 | FqxzTskRjWLFuSTgfhAtDz4mTqwqAW1OI9VwkysZZPD2tLiIfFDdxiLqJLUqPyL2 53 | GgSJqrDXU9HC4qM6ZZgwVWG7SGn38CBEhC2AhakcxMn9gfvK7XCjNkBNXfq6FhGc 54 | cYPDzbQxbLZNK6lGmiAJ5N0RNG7SqlwX5DoKxHAO5+0eOIEI2wg2jc3eU2r82jUo 55 | wpgveEDW7GRUI/2iK/dJpDdg5c1DOsRJ1/eXQ5F8QNpGt507k1zjUkECAwEAAaNT 56 | MFEwHQYDVR0OBBYEFEdwqqwTnMinDnYQTLnd4cR0iYADMB8GA1UdIwQYMBaAFEdw 57 | qqwTnMinDnYQTLnd4cR0iYADMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL 58 | BQADggIBAFXYCYdmfbwyfCWQ0T26gZYdxuDDi4yM6WJt+uKIKZ9lvB+3Llfk8hq9 59 | w+qzbdFHpO7hKCgAGi30dkRFBENyZa7J31sHBpsiwKpDNdxo3v5R5wgdiEQsdq3V 60 | JU665B0hrv1eWSLK5hH023kRlwGYJBYJtDWXCku4eI/zV8SI64FdVCzi6bptH7OO 61 | 2s+PdcSrxTeJflu4+Dn3TdauokU7Z+Xk/LGETyl8PMmGyaHNGGyfdWbARwzQadxW 62 | +6UIa89HlVFkO2+uQS4dZkTyuPJ7zvDt0075vJlRVPwSK/lI/icXnomgL6Op7qOQ 63 | +3GKLKXzQhSjwI/X4Xc2MDJ+YSy67upUStlGxV0wEsq04s7sghs3r29+cFmJ/whc 64 | j+e+xHIoq64CnDtk7+nR4U2iJiwbFjy2Stk7pOlnk/thtt3k90MwW0HA7niEx3sx 65 | xk8LcFOmU3eKwtVBihhlkGUVl/WxQeWFh9HrTsiY3FOAABYOymWY2GfHchEbv7Tn 66 | k4BmSd9XdPzDZYy8r+AVb6vthuqVkweMcLI+j3/P7FFPunc+fLTWU8L6m0qWgs4O 67 | KztYdN53eJPmPSsooRVuxYpweune8TQK035io9KHe/ybahn/j4fg3E0LFFdGHISM 68 | 1U76kiqlqitGwLTx9fz9aSJ+judsoZaVJW2p1pUzaT5A2b+gNkcf 69 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Modern C++ OpenSSL examples 2 | 3 | This repository shows how to use 4 | the OpenSSL C API with modern C++. 5 | 6 | This mainly shows using the OpenSSL C API 7 | primitives as smart pointers (no 8 | XXX_free needed) and has a bunch of 9 | unit tests demonstrating different 10 | validation methods as well as a few 11 | example data gathering methods (for example 12 | to get a certificate subject as a `std::string`). 13 | 14 | It also shows how to link against OpenSSL 15 | using CMake and `CMakeLists.txt`. 16 | 17 | The OpenSSL C API is horrible for (spoiled) modern 18 | C++ developers. Manual frees all over the place, 19 | every `_sk_TYPE` has its own `_new` and `_free`, 20 | internal pointers here and there, and most important, 21 | the documentation sucks. It's extensive, but not useful. 22 | For example, every C method call is described, but not the 23 | overall picture. Every individual method is described, the command 24 | line tools are as well, but not something like, 25 | "Here's how to do X with the C API", where X 26 | could be anything from validating a certificate 27 | against the system-provided chain, a self signed chain, 28 | or checking the purpose, extensions, signing a message, 29 | generating a keypair, or whatever. 30 | 31 | Note that cloning this repository does not automatically include the nested git projects. 32 | They can be included by adding the `--recurse-submodules` when cloning. 33 | 34 | [Read more over here](https://raymii.org). 35 | 36 | [SonarCloud runs static analysis on the code, scans coverage and 37 | checks for vulnerabilities](https://sonarcloud.io/project/overview?id=RaymiiOrg_openssl-modern-cpp). 38 | 39 | Valgrind shows no issues when running the tests. You might even say 40 | this repo is memory-safe. 41 | 42 | 43 | ## Example unit tests 44 | 45 | The `tst` folder has a boatload of unit tests checking 46 | valid, invalid and other scenarios, like expired 47 | certificates or custom `(*verify_cb)(int, X509_STORE_CTX *)` 48 | lambdas that are passed as function pointers 49 | (because they don't capture anything). 50 | 51 | [Take a look at the unit tests!](https://github.com/RaymiiOrg/openssl-modern-cpp/blob/master/tst/OpenSSL-test.cpp) 52 | 53 | ## Included examples 54 | 55 | The code shows how to validate 56 | if a certificate (PEM encoded) 57 | is signed by another certificate. 58 | 59 | The code also shows how to validate a certificate against a chain, building a trust store up to a trusted root. 60 | 61 | The repo includes a fake root certificate 62 | with the same subject, to show that 63 | the code does not validate by comparing 64 | issuer <> subject, but uses the actual 65 | OpenSSL `x509_verify` method. 66 | 67 | The code shows how to use the OpenSSL 68 | primitives as `unique_ptr`. When those 69 | go out of scope, no manual `delete` or 70 | `free` is needed. This is important because 71 | in between the `new` and the `free`, you 72 | might get an exception which leaves a 73 | memory leak. 74 | 75 | The code also shows how to print the 76 | `issuer` and `subject` field of a 77 | certificate. It includes an intermediate 78 | method to convert a PEM file to an 79 | `X509` object. 80 | 81 | 82 | Furthermore the code shows how to parse the subjectAlternativeName. 83 | 84 | The unit tests further show how to use the code. 85 | 86 | 87 | ## Expired certificate validation 88 | 89 | To validate an expired certificate, you can either 90 | pass the `X509_V_FLAG_NO_CHECK_TIME` as 91 | `X509_VERIFY_PARAM*` (also provided as `unique_ptr`), 92 | or provide a custom callback lambda mimicking a 93 | `int (*verify_cb)(int, X509_STORE_CTX *)`: 94 | 95 | auto verify_callback_accept_exipred = [](int ok, X509_STORE_CTX *ctx) -> int { 96 | /* Tolerate certificate expiration */ 97 | if (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_CERT_HAS_EXPIRED) 98 | return 1; 99 | /* Otherwise don't override */ 100 | return ok; 101 | }; 102 | 103 | 104 | ## Usage 105 | 106 | The repo was tested with OpenSSL 3.0.2 on Ubuntu 22.04. 107 | Make sure to `apt install libssl-dev`. 108 | 109 | Compile: 110 | 111 | mkdir build 112 | cd build 113 | cmake .. 114 | make 115 | 116 | Example output: 117 | 118 | 119 | /home/remy/CLionProjects/cert-test/cmake-build-debug/cert_test 120 | 121 | certificate subject: CN=raymii.org 122 | certificate sans : raymii.org www.raymii.org 123 | certificate issuer : C=GB,ST=Greater Manchester,L=Salford,O=Sectigo Limited,CN=Sectigo RSA Domain Validation Secure Server CA 124 | Issuer signed by chain (should be valid): Signature valid 125 | 126 | ** Take a look at the unit tests for more usage examples! ** 127 | 128 | 129 | ## License 130 | 131 | GNU GPL v3 132 | 133 | ``` 134 | Copyright (c) 2023 Remy van Elst 135 | 136 | This program is free software: you can redistribute it and/or modify 137 | it under the terms of the GNU General Public License as published by 138 | the Free Software Foundation, version 3. 139 | 140 | This program is distributed in the hope that it will be useful, but 141 | WITHOUT ANY WARRANTY; without even the implied warranty of 142 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 143 | General Public License for more details. 144 | 145 | You should have received a copy of the GNU General Public License 146 | along with this program. If not, see . 147 | ``` 148 | -------------------------------------------------------------------------------- /tst/data/INCOMPLETE-expired-rsa-dv-ssl-com-chain.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFpjCCA46gAwIBAgIIRyCT6kmYDVMwDQYJKoZIhvcNAQELBQAwaTELMAkGA1UE 3 | BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK 4 | DA9TU0wgQ29ycG9yYXRpb24xHjAcBgNVBAMMFVNTTC5jb20gUlNBIFNTTCBzdWJD 5 | QTAeFw0xNjA4MDEyMDQ4MzBaFw0xNjA4MDIyMDQ4MzBaMCExHzAdBgNVBAMMFmV4 6 | cGlyZWQtcnNhLWR2LnNzbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK 7 | AoIBAQCaMDqEemvY/MyKWNa2qLgdvKp0WwyLepukVj5TQpdNCxWoi6oVdzYiveAq 8 | biZUCZLw8zP8aVix86P6CGNmUShWB1T/YovFeX+uatbjoYDEbPd9pLmcEXpV6n/d 9 | /A07H257+oSn9QPB7uWQSy6QTZvqfHDWz8LFw7SVbEL9S09JTm++9VDQZOBxJD/4 10 | yW6LZtIbXNkHd7Ms8uFQpFqSGXGjE0PfLkAKhPKpLyven+pDu4Tb2bktVAkDcO/F 11 | r14utC/yDp4bBIwD7/VHKSIDgBBNyVN2XRAOu2Z8S/YaKhvuhLXhj5qBDe+cb/Dv 12 | gTT6WIarInEepWMaUDEUHzVGSXc5AgMBAAGjggGYMIIBlDAfBgNVHSMEGDAWgBQm 13 | FH7g3Nem9+LUBCffYfHC7OcyyjBxBggrBgEFBQcBAQRlMGMwPwYIKwYBBQUHMAKG 14 | M2h0dHA6Ly93d3cuc3NsLmNvbS9yZXBvc2l0b3J5L1NTTGNvbVJTQVNTTHN1YkNB 15 | LmNlcjAgBggrBgEFBQcwAYYUaHR0cDovL29jc3BzLnNzbC5jb20wIQYDVR0RBBow 16 | GIIWZXhwaXJlZC1yc2EtZHYuc3NsLmNvbTBRBgNVHSAESjBIMDwGDCsGAQQBgqkw 17 | AQEBADAsMCoGCCsGAQUFBwIBFh5odHRwczovL3d3dy5zc2wuY29tL3JlcG9zaXRv 18 | cnkwCAYGZ4EMAQIBMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATA6BgNV 19 | HR8EMzAxMC+gLaArhilodHRwOi8vY3Jscy5zc2wuY29tL1NTTGNvbVJTQVNTTHN1 20 | YkNBLmNybDAdBgNVHQ4EFgQUY+Ay4OqtPYRt4+l7lXrYlqg72DwwDgYDVR0PAQH/ 21 | BAQDAgWgMA0GCSqGSIb3DQEBCwUAA4ICAQBFet1IDrHxXKj0j4EoJ+/Belksj4dp 22 | QADGuwPE2FOxWeTiBUfe3GZ2c6ObZj9HkZOhX8668SWwdTz2rYH4iyeVcikUby3u 23 | zO3vSUzwj5GS9VFnpp4XNJQ6m7lN3teL8N0tV2feTCBrYfJFxzbzo+QXrD7rMiX1 24 | Y9GgMuGxoGwlycVyMI04eDi4qOSb7GOrzHzqjtFpG58OyRccJyjmeIGD2cVvGUVA 25 | 7EiIjW3ZHY1Lr2HsHvrJGhCS+Yepr1vb1LSVNSK6z9irD610NKnDnVVWT8MA4ZmY 26 | 2MiXMvRPahafbo2VXy3sNJOvIq5YCeMWVNQGZhIKUmfWTPOwpzyW/nZMTprnG0q6 27 | DKCfypMMCzlkaLK+i2XCPjJjyLL4KoCs+hZks2hgdQ8qzdiUyHuRm30L8jJ+q8bP 28 | QERe9KKFBaKueGbjiL5aYD3sgMf9wC4LuJ89PQsJ+RKU7VHFpVxcH11JBPnlRAcF 29 | qeA5xnEKpnkHoQFIggzJ8gkNRuqCIW9VAi2jKNE4Beik9G8opr5WDAzapSrLMqIn 30 | Ob1DCPLMhJiQpHFpPtrSp8PKY7fU9nL8/pRfW0vNP+ntdGpm3p19sdvqsvekVZti 31 | 7fWCDUVfIxJzKY0zklMHBKn0/7Dp3LLLK30MiyJCtBhsISpz/ITsY3oIO28p7Zqt 32 | Yt1CKrI0cgiClQ== 33 | -----END CERTIFICATE----- 34 | -----BEGIN CERTIFICATE----- 35 | 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 69 | y702dmPTKEdEfwhgLx0LxJr/Aw== 70 | -----END CERTIFICATE----- 71 | -----BEGIN CERTIFICATE----- 72 | MIIF2DCCBMCgAwIBAgIRAOQnBJX2jJHW0Ox7SU6k3xwwDQYJKoZIhvcNAQELBQAw 73 | fjELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu 74 | QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEiMCAG 75 | A1UEAxMZQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQTAeFw0xODA5MTEwOTI2NDda 76 | Fw0yMzA5MTEwOTI2NDdaMHwxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQ 77 | MA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTEwLwYD 78 | VQQDDChTU0wuY29tIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBMIIC 79 | IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA+Q/doyt9y9Aq/uxnhabnLhu6 80 | d+Hj9a+k7PpKXZHEV0drGHdrdvL9k+Q9D8IWngtmw1aUnheDhc5W7/IW/QBi9SIJ 81 | VOhlF05BueBPRpeqG8i4bmJeabFf2yoCfvxsyvNB2O3Q6Pw/YUjtsAMUHRAOSxng 82 | u07shmX/NvNeZwILnYZVYf16OO3+4hkAt2+hUGJ1dDyg+sglkrRueiLH+B6h47Ld 83 | kTGrKx0E/6VKBDfphaQzK/3i1lU0fBmkSmjHsqjTt8qhk4jrwZe8jPkd2SKEJHTH 84 | BD1qqSmTzOu4W+H+XyWqNFjIwSNUnRuYEcM4nH49hmylD0CGfAL0XAJPKMuucZ8P 85 | Osgz/hElNer8usVgPdl8GNWyqdN1eANyIso6wx/vLOUuqfqeLLZRRv2vA9bqYGjq 86 | hRY2a4XpHsCz3cQk3IAqgUFtlD7I4MmBQQCeXr9/xQiYohgsQkCz+W84J0tOgPQ9 87 | gUfgiHzqHM61dVxRLhwrfxpyKOcAtdF0xtfkn60Hk7ZTNTX8N+TD9l0WviFz3pIK 88 | +KBjaryWkmo++LxlVZve9Q2JJgT8JRqmJWnLwm3KfOJZX5es6+8uyLzXG1k8K8zy 89 | GciTaydjGc/86Sb4ynGbf5P+NGeETpnr/LN4CTNwumamdu0bc+sapQ3EIhMglFYK 90 | TixsTrH9z5wJuqIz7YcCAwEAAaOCAVEwggFNMBIGA1UdEwEB/wQIMAYBAf8CAQIw 91 | HQYDVR0OBBYEFN0ECQei9Xp9UlMSkpXuOIAlDaZZMB8GA1UdIwQYMBaAFAh2zcsH 92 | /yT2xc3tu5C84oQ3RnX3MA4GA1UdDwEB/wQEAwIBBjA2BgNVHR8ELzAtMCugKaAn 93 | hiVodHRwOi8vc3NsY29tLmNybC5jZXJ0dW0ucGwvY3RuY2EuY3JsMHMGCCsGAQUF 94 | BwEBBGcwZTApBggrBgEFBQcwAYYdaHR0cDovL3NzbGNvbS5vY3NwLWNlcnR1bS5j 95 | b20wOAYIKwYBBQUHMAKGLGh0dHA6Ly9zc2xjb20ucmVwb3NpdG9yeS5jZXJ0dW0u 96 | cGwvY3RuY2EuY2VyMDoGA1UdIAQzMDEwLwYEVR0gADAnMCUGCCsGAQUFBwIBFhlo 97 | dHRwczovL3d3dy5jZXJ0dW0ucGwvQ1BTMA0GCSqGSIb3DQEBCwUAA4IBAQAflZoj 98 | VO6FwvPUb7npBI9Gfyz3MsCnQ6wHAO3gqUUt/Rfh7QBAyK+YrPXAGa0boJcwQGzs 99 | W/ujk06MiWIbfPA6X6dCz1jKdWWcIky/dnuYk5wVgzOxDtxROId8lZwSaZQeAHh0 100 | ftzABne6cC2HLNdoneO6ha1J849ktBUGg5LGl6RAk4ut8WeUtLlaZ1Q8qBvZBc/k 101 | pPmIEgAGiCWF1F7u85NX1oH4LK739VFIq7ZiOnnb7C7yPxRWOsjZy6SiTyWo0Zur 102 | LTAgUAcab/HxlB05g2PoH/1J0OgdRrJGgia9nJ3homhBSFFuevw1lvRU0rwrROVH 103 | 13eCpUqrX5czqyQR 104 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /tst/data/expired.baddssl.com.chain.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFSzCCBDOgAwIBAgIQSueVSfqavj8QDxekeOFpCTANBgkqhkiG9w0BAQsFADCB 3 | kDELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G 4 | A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxNjA0BgNV 5 | BAMTLUNPTU9ETyBSU0EgRG9tYWluIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZlciBD 6 | QTAeFw0xNTA0MDkwMDAwMDBaFw0xNTA0MTIyMzU5NTlaMFkxITAfBgNVBAsTGERv 7 | bWFpbiBDb250cm9sIFZhbGlkYXRlZDEdMBsGA1UECxMUUG9zaXRpdmVTU0wgV2ls 8 | ZGNhcmQxFTATBgNVBAMUDCouYmFkc3NsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD 9 | ggEPADCCAQoCggEBAMIE7PiM7gTCs9hQ1XBYzJMY61yoaEmwIrX5lZ6xKyx2PmzA 10 | S2BMTOqytMAPgLaw+XLJhgL5XEFdEyt/ccRLvOmULlA3pmccYYz2QULFRtMWhyef 11 | dOsKnRFSJiFzbIRMeVXk0WvoBj1IFVKtsyjbqv9u/2CVSndrOfEk0TG23U3AxPxT 12 | uW1CrbV8/q71FdIzSOciccfCFHpsKOo3St/qbLVytH5aohbcabFXRNsKEqveww9H 13 | dFxBIuGa+RuT5q0iBikusbpJHAwnnqP7i/dAcgCskgjZjFeEU4EFy+b+a1SYQCeF 14 | xxC7c3DvaRhBB0VVfPlkPz0sw6l865MaTIbRyoUCAwEAAaOCAdUwggHRMB8GA1Ud 15 | IwQYMBaAFJCvajqUWgvYkOoSVnPfQ7Q6KNrnMB0GA1UdDgQWBBSd7sF7gQs6R2lx 16 | GH0RN5O8pRs/+zAOBgNVHQ8BAf8EBAMCBaAwDAYDVR0TAQH/BAIwADAdBgNVHSUE 17 | FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwTwYDVR0gBEgwRjA6BgsrBgEEAbIxAQIC 18 | BzArMCkGCCsGAQUFBwIBFh1odHRwczovL3NlY3VyZS5jb21vZG8uY29tL0NQUzAI 19 | BgZngQwBAgEwVAYDVR0fBE0wSzBJoEegRYZDaHR0cDovL2NybC5jb21vZG9jYS5j 20 | b20vQ09NT0RPUlNBRG9tYWluVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNybDCB 21 | hQYIKwYBBQUHAQEEeTB3ME8GCCsGAQUFBzAChkNodHRwOi8vY3J0LmNvbW9kb2Nh 22 | LmNvbS9DT01PRE9SU0FEb21haW5WYWxpZGF0aW9uU2VjdXJlU2VydmVyQ0EuY3J0 23 | MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wIwYDVR0RBBww 24 | GoIMKi5iYWRzc2wuY29tggpiYWRzc2wuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQBq 25 | evHa/wMHcnjFZqFPRkMOXxQhjHUa6zbgH6QQFezaMyV8O7UKxwE4PSf9WNnM6i1p 26 | OXy+l+8L1gtY54x/v7NMHfO3kICmNnwUW+wHLQI+G1tjWxWrAPofOxkt3+IjEBEH 27 | fnJ/4r+3ABuYLyw/zoWaJ4wQIghBK4o+gk783SHGVnRwpDTysUCeK1iiWQ8dSO/r 28 | ET7BSp68ZVVtxqPv1dSWzfGuJ/ekVxQ8lEEFeouhN0fX9X3c+s5vMaKwjOrMEpsi 29 | 8TRwz311SotoKQwe6Zaoz7ASH1wq7mcvf71z81oBIgxw+s1F73hczg36TuHvzmWf 30 | RwxPuzZEaFZcVlmtqoq8 31 | -----END CERTIFICATE----- 32 | -----BEGIN CERTIFICATE----- 33 | MIIGCDCCA/CgAwIBAgIQKy5u6tl1NmwUim7bo3yMBzANBgkqhkiG9w0BAQwFADCB 34 | hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G 35 | A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV 36 | BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQwMjEy 37 | MDAwMDAwWhcNMjkwMjExMjM1OTU5WjCBkDELMAkGA1UEBhMCR0IxGzAZBgNVBAgT 38 | EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR 39 | Q09NT0RPIENBIExpbWl0ZWQxNjA0BgNVBAMTLUNPTU9ETyBSU0EgRG9tYWluIFZh 40 | bGlkYXRpb24gU2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP 41 | ADCCAQoCggEBAI7CAhnhoFmk6zg1jSz9AdDTScBkxwtiBUUWOqigwAwCfx3M28Sh 42 | bXcDow+G+eMGnD4LgYqbSRutA776S9uMIO3Vzl5ljj4Nr0zCsLdFXlIvNN5IJGS0 43 | Qa4Al/e+Z96e0HqnU4A7fK31llVvl0cKfIWLIpeNs4TgllfQcBhglo/uLQeTnaG6 44 | ytHNe+nEKpooIZFNb5JPJaXyejXdJtxGpdCsWTWM/06RQ1A/WZMebFEh7lgUq/51 45 | UHg+TLAchhP6a5i84DuUHoVS3AOTJBhuyydRReZw3iVDpA3hSqXttn7IzW3uLh0n 46 | c13cRTCAquOyQQuvvUSH2rnlG51/ruWFgqUCAwEAAaOCAWUwggFhMB8GA1UdIwQY 47 | MBaAFLuvfgI9+qbxPISOre44mOzZMjLUMB0GA1UdDgQWBBSQr2o6lFoL2JDqElZz 48 | 30O0Oija5zAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNV 49 | HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwGwYDVR0gBBQwEjAGBgRVHSAAMAgG 50 | BmeBDAECATBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9kb2NhLmNv 51 | bS9DT01PRE9SU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcB 52 | AQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NPTU9E 53 | T1JTQUFkZFRydXN0Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21v 54 | ZG9jYS5jb20wDQYJKoZIhvcNAQEMBQADggIBAE4rdk+SHGI2ibp3wScF9BzWRJ2p 55 | mj6q1WZmAT7qSeaiNbz69t2Vjpk1mA42GHWx3d1Qcnyu3HeIzg/3kCDKo2cuH1Z/ 56 | e+FE6kKVxF0NAVBGFfKBiVlsit2M8RKhjTpCipj4SzR7JzsItG8kO3KdY3RYPBps 57 | P0/HEZrIqPW1N+8QRcZs2eBelSaz662jue5/DJpmNXMyYE7l3YphLG5SEXdoltMY 58 | dVEVABt0iN3hxzgEQyjpFv3ZBdRdRydg1vs4O2xyopT4Qhrf7W8GjEXCBgCq5Ojc 59 | 2bXhc3js9iPc0d1sjhqPpepUfJa3w/5Vjo1JXvxku88+vZbrac2/4EjxYoIQ5QxG 60 | V/Iz2tDIY+3GH5QFlkoakdH368+PUq4NCNk+qKBR6cGHdNXJ93SrLlP7u3r7l+L4 61 | HyaPs9Kg4DdbKDsx5Q5XLVq4rXmsXiBmGqW5prU5wfWYQ//u+aen/e7KJD2AFsQX 62 | j4rBYKEMrltDR5FL1ZoXX/nUh8HCjLfn4g8wGTeGrODcQgPmlKidrv0PJFGUzpII 63 | 0fxQ8ANAe4hZ7Q7drNJ3gjTcBpUC2JD5Leo31Rpg0Gcg19hCC0Wvgmje3WYkN5Ap 64 | lBlGGSW4gNfL1IYoakRwJiNiqZ+Gb7+6kHDSVneFeO/qJakXzlByjAA6quPbYzSf 65 | +AZxAeKCINT+b72x 66 | -----END CERTIFICATE----- 67 | -----BEGIN CERTIFICATE----- 68 | MIIFdDCCBFygAwIBAgIQJ2buVutJ846r13Ci/ITeIjANBgkqhkiG9w0BAQwFADBv 69 | MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk 70 | ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF 71 | eHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFow 72 | gYUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO 73 | BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYD 74 | VQQDEyJDT01PRE8gUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkq 75 | hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAkehUktIKVrGsDSTdxc9EZ3SZKzejfSNw 76 | AHG8U9/E+ioSj0t/EFa9n3Byt2F/yUsPF6c947AEYe7/EZfH9IY+Cvo+XPmT5jR6 77 | 2RRr55yzhaCCenavcZDX7P0N+pxs+t+wgvQUfvm+xKYvT3+Zf7X8Z0NyvQwA1onr 78 | ayzT7Y+YHBSrfuXjbvzYqOSSJNpDa2K4Vf3qwbxstovzDo2a5JtsaZn4eEgwRdWt 79 | 4Q08RWD8MpZRJ7xnw8outmvqRsfHIKCxH2XeSAi6pE6p8oNGN4Tr6MyBSENnTnIq 80 | m1y9TBsoilwie7SrmNnu4FGDwwlGTm0+mfqVF9p8M1dBPI1R7Qu2XK8sYxrfV8g/ 81 | vOldxJuvRZnio1oktLqpVj3Pb6r/SVi+8Kj/9Lit6Tf7urj0Czr56ENCHonYhMsT 82 | 8dm74YlguIwoVqwUHZwK53Hrzw7dPamWoUi9PPevtQ0iTMARgexWO/bTouJbt7IE 83 | IlKVgJNp6I5MZfGRAy1wdALqi2cVKWlSArvX31BqVUa/oKMoYX9w0MOiqiwhqkfO 84 | KJwGRXa/ghgntNWutMtQ5mv0TIZxMOmm3xaG4Nj/QN370EKIf6MzOi5cHkERgWPO 85 | GHFrK+ymircxXDpqR+DDeVnWIBqv8mqYqnK8V0rSS527EPywTEHl7R09XiidnMy/ 86 | s1Hap0flhFMCAwEAAaOB9DCB8TAfBgNVHSMEGDAWgBStvZh6NLQm9/rEJlTvA73g 87 | JMtUGjAdBgNVHQ4EFgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQD 88 | AgGGMA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAGBgRVHSAAMEQGA1UdHwQ9 89 | MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9BZGRUcnVzdEV4dGVy 90 | bmFsQ0FSb290LmNybDA1BggrBgEFBQcBAQQpMCcwJQYIKwYBBQUHMAGGGWh0dHA6 91 | Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggEBAGS/g/FfmoXQ 92 | zbihKVcN6Fr30ek+8nYEbvFScLsePP9NDXRqzIGCJdPDoCpdTPW6i6FtxFQJdcfj 93 | Jw5dhHk3QBN39bSsHNA7qxcS1u80GH4r6XnTq1dFDK8o+tDb5VCViLvfhVdpfZLY 94 | Uspzgb8c8+a4bmYRBbMelC1/kZWSWfFMzqORcUx8Rww7Cxn2obFshj5cqsQugsv5 95 | B5a6SE2Q8pTIqXOi6wZ7I53eovNNVZ96YUWYGGjHXkBrI/V5eu+MtWuLt29G9Hvx 96 | PUsE2JOAWVrgQSQdso8VYFhH2+9uRv0V9dlfmrPb2LjkQLPNlzmuhbsdjrzch5vR 97 | pu/xO28QOG8= 98 | -----END CERTIFICATE----- 99 | -----BEGIN CERTIFICATE----- 100 | MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU 101 | MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs 102 | IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 103 | MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux 104 | FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h 105 | bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v 106 | dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt 107 | H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 108 | uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX 109 | mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX 110 | a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN 111 | E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 112 | WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD 113 | VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 114 | Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU 115 | cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx 116 | IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN 117 | AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH 118 | YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 119 | 6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC 120 | Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX 121 | c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a 122 | mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= 123 | -----END CERTIFICATE----- 124 | -------------------------------------------------------------------------------- /tst/data/expired-rsa-dv-ssl-com-chain.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFpjCCA46gAwIBAgIIRyCT6kmYDVMwDQYJKoZIhvcNAQELBQAwaTELMAkGA1UE 3 | BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK 4 | DA9TU0wgQ29ycG9yYXRpb24xHjAcBgNVBAMMFVNTTC5jb20gUlNBIFNTTCBzdWJD 5 | QTAeFw0xNjA4MDEyMDQ4MzBaFw0xNjA4MDIyMDQ4MzBaMCExHzAdBgNVBAMMFmV4 6 | cGlyZWQtcnNhLWR2LnNzbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK 7 | AoIBAQCaMDqEemvY/MyKWNa2qLgdvKp0WwyLepukVj5TQpdNCxWoi6oVdzYiveAq 8 | biZUCZLw8zP8aVix86P6CGNmUShWB1T/YovFeX+uatbjoYDEbPd9pLmcEXpV6n/d 9 | /A07H257+oSn9QPB7uWQSy6QTZvqfHDWz8LFw7SVbEL9S09JTm++9VDQZOBxJD/4 10 | yW6LZtIbXNkHd7Ms8uFQpFqSGXGjE0PfLkAKhPKpLyven+pDu4Tb2bktVAkDcO/F 11 | r14utC/yDp4bBIwD7/VHKSIDgBBNyVN2XRAOu2Z8S/YaKhvuhLXhj5qBDe+cb/Dv 12 | gTT6WIarInEepWMaUDEUHzVGSXc5AgMBAAGjggGYMIIBlDAfBgNVHSMEGDAWgBQm 13 | FH7g3Nem9+LUBCffYfHC7OcyyjBxBggrBgEFBQcBAQRlMGMwPwYIKwYBBQUHMAKG 14 | M2h0dHA6Ly93d3cuc3NsLmNvbS9yZXBvc2l0b3J5L1NTTGNvbVJTQVNTTHN1YkNB 15 | LmNlcjAgBggrBgEFBQcwAYYUaHR0cDovL29jc3BzLnNzbC5jb20wIQYDVR0RBBow 16 | GIIWZXhwaXJlZC1yc2EtZHYuc3NsLmNvbTBRBgNVHSAESjBIMDwGDCsGAQQBgqkw 17 | AQEBADAsMCoGCCsGAQUFBwIBFh5odHRwczovL3d3dy5zc2wuY29tL3JlcG9zaXRv 18 | cnkwCAYGZ4EMAQIBMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATA6BgNV 19 | HR8EMzAxMC+gLaArhilodHRwOi8vY3Jscy5zc2wuY29tL1NTTGNvbVJTQVNTTHN1 20 | YkNBLmNybDAdBgNVHQ4EFgQUY+Ay4OqtPYRt4+l7lXrYlqg72DwwDgYDVR0PAQH/ 21 | BAQDAgWgMA0GCSqGSIb3DQEBCwUAA4ICAQBFet1IDrHxXKj0j4EoJ+/Belksj4dp 22 | QADGuwPE2FOxWeTiBUfe3GZ2c6ObZj9HkZOhX8668SWwdTz2rYH4iyeVcikUby3u 23 | zO3vSUzwj5GS9VFnpp4XNJQ6m7lN3teL8N0tV2feTCBrYfJFxzbzo+QXrD7rMiX1 24 | Y9GgMuGxoGwlycVyMI04eDi4qOSb7GOrzHzqjtFpG58OyRccJyjmeIGD2cVvGUVA 25 | 7EiIjW3ZHY1Lr2HsHvrJGhCS+Yepr1vb1LSVNSK6z9irD610NKnDnVVWT8MA4ZmY 26 | 2MiXMvRPahafbo2VXy3sNJOvIq5YCeMWVNQGZhIKUmfWTPOwpzyW/nZMTprnG0q6 27 | DKCfypMMCzlkaLK+i2XCPjJjyLL4KoCs+hZks2hgdQ8qzdiUyHuRm30L8jJ+q8bP 28 | QERe9KKFBaKueGbjiL5aYD3sgMf9wC4LuJ89PQsJ+RKU7VHFpVxcH11JBPnlRAcF 29 | qeA5xnEKpnkHoQFIggzJ8gkNRuqCIW9VAi2jKNE4Beik9G8opr5WDAzapSrLMqIn 30 | Ob1DCPLMhJiQpHFpPtrSp8PKY7fU9nL8/pRfW0vNP+ntdGpm3p19sdvqsvekVZti 31 | 7fWCDUVfIxJzKY0zklMHBKn0/7Dp3LLLK30MiyJCtBhsISpz/ITsY3oIO28p7Zqt 32 | Yt1CKrI0cgiClQ== 33 | -----END CERTIFICATE----- 34 | -----BEGIN CERTIFICATE----- 35 | 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 69 | y702dmPTKEdEfwhgLx0LxJr/Aw== 70 | -----END CERTIFICATE----- 71 | -----BEGIN CERTIFICATE----- 72 | MIIF2DCCBMCgAwIBAgIRAOQnBJX2jJHW0Ox7SU6k3xwwDQYJKoZIhvcNAQELBQAw 73 | fjELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu 74 | QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEiMCAG 75 | A1UEAxMZQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQTAeFw0xODA5MTEwOTI2NDda 76 | Fw0yMzA5MTEwOTI2NDdaMHwxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQ 77 | MA4GA1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTEwLwYD 78 | VQQDDChTU0wuY29tIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBMIIC 79 | IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA+Q/doyt9y9Aq/uxnhabnLhu6 80 | d+Hj9a+k7PpKXZHEV0drGHdrdvL9k+Q9D8IWngtmw1aUnheDhc5W7/IW/QBi9SIJ 81 | VOhlF05BueBPRpeqG8i4bmJeabFf2yoCfvxsyvNB2O3Q6Pw/YUjtsAMUHRAOSxng 82 | u07shmX/NvNeZwILnYZVYf16OO3+4hkAt2+hUGJ1dDyg+sglkrRueiLH+B6h47Ld 83 | kTGrKx0E/6VKBDfphaQzK/3i1lU0fBmkSmjHsqjTt8qhk4jrwZe8jPkd2SKEJHTH 84 | BD1qqSmTzOu4W+H+XyWqNFjIwSNUnRuYEcM4nH49hmylD0CGfAL0XAJPKMuucZ8P 85 | Osgz/hElNer8usVgPdl8GNWyqdN1eANyIso6wx/vLOUuqfqeLLZRRv2vA9bqYGjq 86 | hRY2a4XpHsCz3cQk3IAqgUFtlD7I4MmBQQCeXr9/xQiYohgsQkCz+W84J0tOgPQ9 87 | gUfgiHzqHM61dVxRLhwrfxpyKOcAtdF0xtfkn60Hk7ZTNTX8N+TD9l0WviFz3pIK 88 | +KBjaryWkmo++LxlVZve9Q2JJgT8JRqmJWnLwm3KfOJZX5es6+8uyLzXG1k8K8zy 89 | GciTaydjGc/86Sb4ynGbf5P+NGeETpnr/LN4CTNwumamdu0bc+sapQ3EIhMglFYK 90 | TixsTrH9z5wJuqIz7YcCAwEAAaOCAVEwggFNMBIGA1UdEwEB/wQIMAYBAf8CAQIw 91 | HQYDVR0OBBYEFN0ECQei9Xp9UlMSkpXuOIAlDaZZMB8GA1UdIwQYMBaAFAh2zcsH 92 | /yT2xc3tu5C84oQ3RnX3MA4GA1UdDwEB/wQEAwIBBjA2BgNVHR8ELzAtMCugKaAn 93 | hiVodHRwOi8vc3NsY29tLmNybC5jZXJ0dW0ucGwvY3RuY2EuY3JsMHMGCCsGAQUF 94 | BwEBBGcwZTApBggrBgEFBQcwAYYdaHR0cDovL3NzbGNvbS5vY3NwLWNlcnR1bS5j 95 | b20wOAYIKwYBBQUHMAKGLGh0dHA6Ly9zc2xjb20ucmVwb3NpdG9yeS5jZXJ0dW0u 96 | cGwvY3RuY2EuY2VyMDoGA1UdIAQzMDEwLwYEVR0gADAnMCUGCCsGAQUFBwIBFhlo 97 | dHRwczovL3d3dy5jZXJ0dW0ucGwvQ1BTMA0GCSqGSIb3DQEBCwUAA4IBAQAflZoj 98 | VO6FwvPUb7npBI9Gfyz3MsCnQ6wHAO3gqUUt/Rfh7QBAyK+YrPXAGa0boJcwQGzs 99 | W/ujk06MiWIbfPA6X6dCz1jKdWWcIky/dnuYk5wVgzOxDtxROId8lZwSaZQeAHh0 100 | ftzABne6cC2HLNdoneO6ha1J849ktBUGg5LGl6RAk4ut8WeUtLlaZ1Q8qBvZBc/k 101 | pPmIEgAGiCWF1F7u85NX1oH4LK739VFIq7ZiOnnb7C7yPxRWOsjZy6SiTyWo0Zur 102 | LTAgUAcab/HxlB05g2PoH/1J0OgdRrJGgia9nJ3homhBSFFuevw1lvRU0rwrROVH 103 | 13eCpUqrX5czqyQR 104 | -----END CERTIFICATE----- 105 | -----BEGIN CERTIFICATE----- 106 | MIIEtDCCA5ygAwIBAgIRAJOShUABZXFflH8oj+/JmygwDQYJKoZIhvcNAQELBQAw 107 | PjELMAkGA1UEBhMCUEwxGzAZBgNVBAoTElVuaXpldG8gU3AuIHogby5vLjESMBAG 108 | A1UEAxMJQ2VydHVtIENBMB4XDTA4MTAyMjEyMDczN1oXDTI3MDYxMDEwNDYzOVow 109 | fjELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu 110 | QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEiMCAG 111 | A1UEAxMZQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQTCCASIwDQYJKoZIhvcNAQEB 112 | BQADggEPADCCAQoCggEBAOP7faNyusLwyRSH9WsBTuFuQAe6bSddf/dbLbNax1Ff 113 | q6QypmGHtm4PhtIwApf412lXoRg5XWpkecYBWaw8MUo4fNIE0kso6CBfOweizE1z 114 | 2/OuT8dW1Vqnlon686to1COGWSfPCSe8rG5ygxwwct/gounS4XR1Gb0qnnsVVAQb 115 | 10M5rVUoxeIau/TA5K44STPMdoWfOUXSpJ7yEoxR+HzkLX/1rF/rFp+xLdG6zJFC 116 | d0wlyZA4b9vwzPuOHpdZPtVgTuYFKO1JeRNLukjbL/ly0znK/h/YNHL1tEDPMQHD 117 | 7N4RLRddH7hQ0V4Zp2neBzMoylCV+adUy1SGUEWp+UkCAwEAAaOCAWswggFnMA8G 118 | A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFAh2zcsH/yT2xc3tu5C84oQ3RnX3MFIG 119 | A1UdIwRLMEmhQqRAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNw 120 | LiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQYIDAQAgMA4GA1UdDwEB/wQEAwIB 121 | BjAsBgNVHR8EJTAjMCGgH6AdhhtodHRwOi8vY3JsLmNlcnR1bS5wbC9jYS5jcmww 122 | aAYIKwYBBQUHAQEEXDBaMCgGCCsGAQUFBzABhhxodHRwOi8vc3ViY2Eub2NzcC1j 123 | ZXJ0dW0uY29tMC4GCCsGAQUFBzAChiJodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0u 124 | cGwvY2EuY2VyMDkGA1UdIAQyMDAwLgYEVR0gADAmMCQGCCsGAQUFBwIBFhhodHRw 125 | Oi8vd3d3LmNlcnR1bS5wbC9DUFMwDQYJKoZIhvcNAQELBQADggEBAI3m/UBmo0yc 126 | p6uh2oTdHDAH5tvHLeyDoVbkHTwmoaUJK+h9Yr6ydZTdCPJ/KEHkgGcCToqPwzXQ 127 | 1aknKOrS9KsGhkOujOP5iH3g271CgYACEnWy6BdxqyGVMUZCDYgQOdNv7C9C6kBT 128 | Yr/rynieq6LVLgXqM6vp1peUQl4E7Sztapx6lX0FKgV/CF1mrWHUdqx1lpdzY70a 129 | QVkppV4ig8OLWfqaova9ML9yHRyZhpzyhTwd9yaWLy75ArG1qVDoOPqbCl60BMDO 130 | TjksygtbYvBNWFA0meaaLNKQ1wmB1sCqXs7+0vehukvZ1oaOGR+mBkdCcuBWCgAc 131 | eLmNzJkEN0k= 132 | -----END CERTIFICATE----- 133 | -----BEGIN CERTIFICATE----- 134 | MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM 135 | MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD 136 | QTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBM 137 | MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD 138 | QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6xwS7TT3zNJc4YPk/E 139 | jG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdLkKWo 140 | ePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GI 141 | ULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapu 142 | Ob7kky/ZR6By6/qmW6/KUz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUg 143 | AKpoC6EahQGcxEZjgoi2IrHu/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7 144 | HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEA 145 | uI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQa 146 | TOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTg 147 | xSvgGrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1q 148 | CjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x 149 | O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs 150 | 6GAqm4VKQPNriiTsBhYscw== 151 | -----END CERTIFICATE----- 152 | -------------------------------------------------------------------------------- /src/OpenSSL.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 Remy van Elst 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, version 3. 7 | * 8 | * This program is distributed in the hope that it will be useful, but 9 | * WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | * General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | */ 17 | 18 | #pragma once 19 | 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | struct OpenSSLFree 36 | { 37 | void operator() (BIO* bio) const 38 | { BIO_free(bio); } 39 | 40 | void operator() (X509* x509) const 41 | { X509_free(x509); } 42 | 43 | /** 44 | * This frees the STACK_OF and 45 | * all the items in it. 46 | */ 47 | void operator() (STACK_OF(X509)* st) const 48 | { 49 | for(int i = 0; i < sk_X509_num(st); ++i) 50 | X509_free(sk_X509_value(st, i)); 51 | sk_X509_free(st); 52 | } 53 | 54 | void operator() (X509_STORE* store) const 55 | { X509_STORE_free(store); } 56 | 57 | void operator() (X509_STORE_CTX* ctx) const 58 | { X509_STORE_CTX_free(ctx); } 59 | 60 | void operator() (X509_VERIFY_PARAM* param) const 61 | { X509_VERIFY_PARAM_free(param); } 62 | 63 | void operator() (GENERAL_NAME* gn) const 64 | {GENERAL_NAME_free(gn); } 65 | 66 | /** 67 | * This frees the STACK_OF and 68 | * all the items in it. 69 | */ 70 | void operator() (STACK_OF(GENERAL_NAME)* st) const 71 | { 72 | for(int i = 0; i < sk_GENERAL_NAME_num(st); ++i) 73 | GENERAL_NAME_free(sk_GENERAL_NAME_value(st, i)); 74 | sk_GENERAL_NAME_free(st); 75 | } 76 | 77 | void operator() (EVP_PKEY* evp_pkey) const 78 | { EVP_PKEY_free(evp_pkey); } 79 | 80 | void operator() (EVP_MD_CTX* evp_md_ctx) const 81 | { EVP_MD_CTX_free(evp_md_ctx); } 82 | }; 83 | 84 | using X509_uptr = std::unique_ptr; 85 | using STACK_OF_X509_uptr = std::unique_ptr; 86 | using BIO_MEM_uptr = std::unique_ptr; 87 | using EVP_PKEY_uptr = std::unique_ptr; 88 | using BUF_MEM_uptr = std::unique_ptr; 89 | using X509_STORE_CTX_uptr = std::unique_ptr; 90 | using X509_STORE_uptr = std::unique_ptr; 91 | using X509_VERIFY_PARAM_uptr = std::unique_ptr; 92 | using GENERAL_NAME_uptr = std::unique_ptr; 93 | using STACK_OF_GENERAL_NAME_uptr = std::unique_ptr; 94 | using EVP_MD_CTX_uptr = std::unique_ptr; 95 | 96 | inline static const int maxKeySize = 4096; 97 | 98 | class OpenSSL { 99 | public: 100 | /** 101 | * Convenience wrappers 102 | */ 103 | [[nodiscard]] static int verify_cert_signed_by_chain(const std::string& cert_pem, 104 | const std::string& issuer_pem); 105 | 106 | [[nodiscard]] static int verify_cert_signed_by_chain(const std::string& cert_pem, 107 | const std::string& issuer_pem, 108 | int (*verify_cb)(int, X509_STORE_CTX *)); 109 | 110 | [[nodiscard]] static int verify_cert_signed_by_chain(const std::string& cert_pem, 111 | const std::string& issuer_pem, 112 | const X509_VERIFY_PARAM* x509_verify_param); 113 | 114 | /** 115 | * Verifies if a certificate is signed by a chain. 116 | * @param cert_pem single PEM encoded certificate to check against chain 117 | * @param chain PEM encoded chain (list of certificates) 118 | * IMPORTANT: chain must be complete, ordered and ending in a self signed trusted root. 119 | * @param x509_verify_param optional X509_VERIFY_PARAM to for example disable time checks, X509_V_FLAG_NO_CHECK_TIME 120 | * @param verify_cb optional X509_STORE_CTX_verify_cb function 121 | * @return 1 if OK, 0 if NOT OK, -1 on error 122 | */ 123 | [[nodiscard]] static int verify_cert_signed_by_chain(const std::string& cert_pem, 124 | const std::string& issuer_pem, 125 | const X509_VERIFY_PARAM* x509_verify_param, 126 | int (*verify_cb)(int, X509_STORE_CTX *)); 127 | 128 | /** 129 | * Uses OpenSSL X509_verify to verify a certificates signature 130 | * (eg. if it's signed by the issuer provided). 131 | * @param cert_pem single PEM encoded certificate to check against issuer 132 | * @param issuer_pem single PEM encoded issuer certificate 133 | * @return 1 if OK, 0 if NOT OK, -1 on error 134 | */ 135 | [[nodiscard]] static int verify_cert_signed_by_issuer(const std::string& cert_pem, 136 | const std::string& issuer_pem) ; 137 | 138 | 139 | /** 140 | * Returns a unique_ptr, requiring no manual X509_free 141 | * @param cert_pem PEM encoded certificate 142 | */ 143 | [[nodiscard]] static X509_uptr cert_to_x509(const std::string& cert_pem) ; 144 | 145 | 146 | /** 147 | * @param x509 OpenSSL X509 struct filled with certificate. 148 | * @return Contents of issuer field of certificate, empty on error. 149 | */ 150 | static std::string x509_issuer (const X509* x509) ; 151 | 152 | /** 153 | * @param x509 OpenSSL X509 struct filled with certificate. 154 | * @return Contents of subject field of certificate, empty on error. 155 | */ 156 | static std::string x509_subject (const X509* x509); 157 | 158 | /** 159 | * Parses the X509* and returns the subjectAlternativeNames 160 | * @param x509 OpenSSL X509 struct filled with certificate 161 | * @return vector of strings filled with subjectAlternativeName 162 | * NOTE: only parses DNS:. Not IP: or others. 163 | */ 164 | static std::vector x509_subject_alternative_dns_names(const X509* x509); 165 | 166 | /** 167 | * @param cert_pem PEM encoded certificates 168 | */ 169 | [[nodiscard]] static std::vector certs_to_x509(const std::string& certs_pem); 170 | 171 | /** 172 | * Returns a unique_ptr, requiring no manual X509_free 173 | * @param cert_pem PEM encoded certificates 174 | */ 175 | [[nodiscard]] static STACK_OF_X509_uptr certs_to_stack_of_x509(const std::string& certs_pem) ; 176 | 177 | 178 | /** 179 | * Parses X509* and returns public key (if found), otherwise nullptr 180 | * @param x509 OpenSSL X509 struct filled with certificate. 181 | */ 182 | [[nodiscard]] static EVP_PKEY_uptr x509_to_evp_pubkey(const X509* x509); 183 | 184 | 185 | /** 186 | * Returns the public key in PEM format if found, otherwise empty 187 | * @param x509 OpenSSL X509 struct filled with certificate. 188 | */ 189 | [[nodiscard]] static std::string x509_to_public_key_pem(const X509* x509); 190 | 191 | 192 | /** 193 | * Verifies if a sha256 signed digest signed the provided message. 194 | * cli verify: openssl dgst -sha256 -verify <(openssl x509 -in sign.crt -pubkey -noout) -signature signature.bin message.txt 195 | * cli sign : openssl dgst -sha256 -sign sign.key -out signature.bin message.txt 196 | * @param message original message that was signed 197 | * @param base64_encoded_signature binary signature data encoded as base64 198 | * @param x509_that_has_pubkey_that_signed_the_message certificate with publickey that signed the messag 199 | * @return 1 on verify correct, 0 on verify incorrect, -1 on error, 200 | */ 201 | [[nodiscard]] static int verify_sha256_digest_signature(const std::string& message, const std::string& base64_encoded_signature, const X509* x509_that_has_pubkey_that_signed_the_message); 202 | 203 | /** 204 | * Uses OpenSSL to decode a base64 message string. 205 | */ 206 | [[nodiscard]] static std::string base64_decode(const std::string& message); 207 | 208 | /** 209 | * Uses OpenSSL to encode a string to base64 210 | */ 211 | [[nodiscard]] static std::string base64_encode(const std::string& message); 212 | 213 | private: 214 | 215 | /** 216 | * Used as a base class to convert subject or issuer to std::string, 217 | * handles allocation and conversion. 218 | * @param X509_X_NAME_FUNC Lambda that calls for example X509_get_subject_name. 219 | * @return 220 | */ 221 | static std::string x509_name_base(const X509 *x509, 222 | const std::function &X509_X_NAME_FUNC); 224 | 225 | 226 | static std::vector read_binary_file(const std::string& filename); 227 | 228 | inline static const std::string allowed_base64{ 229 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 230 | 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 231 | 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 232 | 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 233 | 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', 234 | '3', '4', '5', '6', '7', '8', '9', '+', '/', '='}; 235 | 236 | static std::string stripNonBase64FromString(const std::string &message); 237 | }; 238 | 239 | 240 | 241 | -------------------------------------------------------------------------------- /src/OpenSSL.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 Remy van Elst 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, version 3. 7 | * 8 | * This program is distributed in the hope that it will be useful, but 9 | * WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | * General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | */ 17 | 18 | 19 | #include 20 | #include 21 | #include "OpenSSL.h" 22 | 23 | int OpenSSL::verify_cert_signed_by_issuer(const std::string& cert_pem, const std::string& issuer_pem) 24 | { 25 | if(cert_pem.empty() || issuer_pem.empty()) 26 | return -1; 27 | 28 | BIO_MEM_uptr bio_issuer(BIO_new(BIO_s_mem())); 29 | if(BIO_puts(bio_issuer.get(), issuer_pem.c_str()) <= 0) 30 | return -1; 31 | 32 | X509_uptr issuer(PEM_read_bio_X509(bio_issuer.get(), nullptr, 33 | nullptr, nullptr)); 34 | if(issuer == nullptr) 35 | return -1; 36 | 37 | EVP_PKEY_uptr signing_key(X509_get_pubkey(issuer.get())); 38 | 39 | BIO_MEM_uptr bio_cert(BIO_new(BIO_s_mem())); 40 | if(BIO_puts(bio_cert.get(), cert_pem.c_str()) <= 0) 41 | return -1; 42 | 43 | X509_uptr cert(PEM_read_bio_X509(bio_cert.get(), nullptr, 44 | nullptr, nullptr)); 45 | 46 | if(cert == nullptr) 47 | return -1; 48 | 49 | int result = X509_verify(cert.get(), signing_key.get()); 50 | 51 | return result; 52 | } 53 | 54 | X509_uptr OpenSSL::cert_to_x509(const std::string& cert_pem) 55 | { 56 | if(cert_pem.empty()) 57 | return X509_uptr{nullptr}; 58 | 59 | auto certs_x509 = certs_to_x509(cert_pem); 60 | if(certs_x509.empty()) 61 | return X509_uptr{nullptr}; 62 | 63 | return std::move(certs_x509.front()); 64 | } 65 | 66 | 67 | std::string OpenSSL::x509_name_base(const X509 *const x509, 68 | const std::function &X509_X_NAME_FUNC) 69 | { 70 | std::string result; 71 | if(x509 == nullptr) 72 | return result; 73 | 74 | std::vector subject_buffer(maxKeySize, 0); 75 | BIO_MEM_uptr bio(BIO_new(BIO_s_mem())); 76 | 77 | // X509_get_subject_name() or 78 | // X509_get_issuer_name() returns the subject name of certificate x. 79 | // The returned value is an internal pointer which MUST NOT be freed. 80 | X509_X_NAME_FUNC(x509, bio); 81 | 82 | if(BIO_read(bio.get(), subject_buffer.data(), maxKeySize) <= 0) 83 | return result; 84 | 85 | result.assign(subject_buffer.begin(), subject_buffer.end()); 86 | result.erase(std::find(result.begin(), result.end(), '\0'), result.end()); 87 | return result; 88 | } 89 | 90 | std::string OpenSSL::x509_subject (const X509* const x509) 91 | { 92 | return x509_name_base(x509, [](const X509 *x509p, const BIO_MEM_uptr &bio) { 93 | const X509_NAME *subject_name = X509_get_subject_name(x509p); 94 | X509_NAME_print_ex(bio.get(), subject_name, 95 | 0, XN_FLAG_SEP_COMMA_PLUS); 96 | }); 97 | 98 | 99 | } 100 | 101 | std::string OpenSSL::x509_issuer (const X509* const x509) 102 | { 103 | return x509_name_base(x509, [](const X509 *x509p, const BIO_MEM_uptr &bio) { 104 | const X509_NAME *issuer_name = X509_get_issuer_name(x509p); 105 | X509_NAME_print_ex(bio.get(), issuer_name, 106 | 0, XN_FLAG_SEP_COMMA_PLUS); 107 | }); 108 | } 109 | 110 | 111 | std::vector OpenSSL::certs_to_x509(const std::string& certs_pem) 112 | { 113 | if(certs_pem.empty()) 114 | return {}; 115 | 116 | std::vector result; 117 | 118 | X509_uptr x509(X509_new()); 119 | BIO_MEM_uptr bio(BIO_new(BIO_s_mem())); 120 | if(BIO_puts(bio.get(), certs_pem.c_str()) <= 0) 121 | return {}; 122 | 123 | while (X509_uptr cert {PEM_read_bio_X509(bio.get(), nullptr, 124 | nullptr, nullptr)}) { 125 | result.push_back(std::move(cert)); 126 | } 127 | 128 | return result; 129 | } 130 | 131 | 132 | int OpenSSL::verify_cert_signed_by_chain(const std::string &cert_pem, 133 | const std::string &chain_pem) { 134 | 135 | return verify_cert_signed_by_chain(cert_pem, chain_pem, 136 | nullptr, nullptr); 137 | } 138 | 139 | int OpenSSL::verify_cert_signed_by_chain(const std::string &cert_pem, 140 | const std::string &chain_pem, 141 | const X509_VERIFY_PARAM* x509_verify_param) { 142 | return verify_cert_signed_by_chain(cert_pem, chain_pem, 143 | x509_verify_param, nullptr); 144 | } 145 | 146 | int OpenSSL::verify_cert_signed_by_chain(const std::string &cert_pem, 147 | const std::string &chain_pem, 148 | int (*verify_cb)(int, X509_STORE_CTX *)) { 149 | return verify_cert_signed_by_chain(cert_pem, chain_pem, 150 | nullptr, verify_cb); 151 | } 152 | 153 | 154 | std::vector OpenSSL::x509_subject_alternative_dns_names(const X509 *x509) { 155 | std::vector result; 156 | STACK_OF_GENERAL_NAME_uptr names((STACK_OF(GENERAL_NAME)*)X509_get_ext_d2i(x509, 157 | NID_subject_alt_name, nullptr, nullptr)); 158 | int count = sk_GENERAL_NAME_num(names.get()); 159 | for (int i = 0; i < count; ++i) 160 | { 161 | GENERAL_NAME_uptr entry(GENERAL_NAME_dup(sk_GENERAL_NAME_value(names.get(), i))); 162 | if (!entry) continue; 163 | 164 | result.emplace_back(reinterpret_cast(ASN1_STRING_get0_data(entry->d.dNSName)), 165 | ASN1_STRING_length(entry->d.dNSName)); 166 | } 167 | 168 | return result; 169 | } 170 | 171 | STACK_OF_X509_uptr OpenSSL::certs_to_stack_of_x509(const std::string &certs_pem) 172 | { 173 | if(certs_pem.empty()) 174 | return {}; 175 | 176 | STACK_OF_X509_uptr result(sk_X509_new(nullptr)); 177 | 178 | BIO_MEM_uptr bio(BIO_new(BIO_s_mem())); 179 | if(BIO_puts(bio.get(), certs_pem.c_str()) <= 0) 180 | return {}; 181 | 182 | while (X509_uptr cert {PEM_read_bio_X509(bio.get(), nullptr, 183 | nullptr, nullptr)}) 184 | { 185 | sk_X509_push(result.get(), X509_dup(cert.get())); 186 | } 187 | 188 | return result; 189 | } 190 | 191 | 192 | 193 | int OpenSSL::verify_cert_signed_by_chain(const std::string &cert_pem, 194 | const std::string &chain_pem, 195 | const X509_VERIFY_PARAM* x509_verify_param, 196 | int (*verify_cb)(int, X509_STORE_CTX *)) { 197 | 198 | if(cert_pem.empty() || chain_pem.empty()) 199 | return -1; 200 | 201 | X509_STORE_uptr store(X509_STORE_new()); 202 | 203 | if(store == nullptr) 204 | return -1; 205 | 206 | if(x509_verify_param != nullptr) { 207 | if(X509_STORE_set1_param(store.get(), x509_verify_param) <= 0) 208 | return -1; 209 | } 210 | 211 | if(verify_cb != nullptr) { 212 | X509_STORE_set_verify_cb(store.get(), verify_cb); 213 | } 214 | 215 | auto stack_of_x509_certs = certs_to_stack_of_x509(chain_pem); 216 | 217 | X509_uptr cert_x509 = cert_to_x509(cert_pem); 218 | 219 | // store == nullptr otherwise chain would have to be anchors to trusted 220 | // root in store. with_self_signed = 1 because this method validates up 221 | // to a user provided trusted root. 222 | STACK_OF_X509_uptr chain((STACK_OF(X509)*)X509_build_chain(cert_x509.get(), stack_of_x509_certs.get(), 223 | nullptr, 1, nullptr, nullptr)); 224 | 225 | int chainSize = sk_X509_num(chain.get()); 226 | for (int i = 0; i < chainSize; i++) { 227 | X509* chainCert = sk_X509_value(chain.get(), i); 228 | // add the last chain as trusted root anchor 229 | if(i == (chainSize - 1)) 230 | if(X509_STORE_add_cert(store.get(), chainCert) <= 0) 231 | return -1; 232 | } 233 | 234 | X509_STORE_CTX_uptr store_ctx(X509_STORE_CTX_new()); 235 | if(store_ctx == nullptr) 236 | return -1; 237 | 238 | if(X509_STORE_CTX_init(store_ctx.get(), store.get(), cert_x509.get(), chain.get()) != 1) 239 | return -1; 240 | 241 | int result = X509_verify_cert(store_ctx.get()); 242 | if(result != 1) { 243 | int error = X509_STORE_CTX_get_error(store_ctx.get()); 244 | auto errorMessage = std::string(X509_verify_cert_error_string(error)); 245 | std::cerr << errorMessage << "; "; 246 | } 247 | return result; 248 | } 249 | 250 | EVP_PKEY_uptr OpenSSL::x509_to_evp_pubkey(const X509 *x509) { 251 | if(!x509) 252 | return {}; 253 | 254 | X509_uptr non_const_x509(X509_dup(x509)); 255 | return EVP_PKEY_uptr(X509_get_pubkey(non_const_x509.get())); 256 | } 257 | 258 | std::string OpenSSL::x509_to_public_key_pem(const X509 *x509) { 259 | std::string result; 260 | std::vector pem_buffer(maxKeySize, 0); 261 | if(!x509) 262 | return result; 263 | 264 | EVP_PKEY_uptr evp_pubkey_uptr = x509_to_evp_pubkey(x509); 265 | 266 | BIO_MEM_uptr bio(BIO_new(BIO_s_mem())); 267 | if(PEM_write_bio_PUBKEY_ex(bio.get(), evp_pubkey_uptr.get(), nullptr, nullptr) <= 0) 268 | return result; 269 | 270 | if(BIO_read(bio.get(), pem_buffer.data(), maxKeySize) <= 0) 271 | return result; 272 | 273 | result.assign(pem_buffer.begin(), pem_buffer.end()); 274 | result.erase(std::find(result.begin(), result.end(), '\0'), result.end()); 275 | return result; 276 | } 277 | 278 | int OpenSSL::verify_sha256_digest_signature(const std::string &message, 279 | const std::string &base64_encoded_signature, 280 | const X509 *x509_that_has_pubkey_that_signed_the_message) { 281 | if(message.empty() || 282 | base64_encoded_signature.empty() || 283 | x509_that_has_pubkey_that_signed_the_message == nullptr) 284 | return -1; 285 | 286 | std::string decoded_signature = base64_decode(base64_encoded_signature); 287 | if(decoded_signature.empty()) 288 | return -1; 289 | 290 | EVP_PKEY_uptr evp_pubkey_uptr = x509_to_evp_pubkey(x509_that_has_pubkey_that_signed_the_message); 291 | if(evp_pubkey_uptr == nullptr) 292 | return -1; 293 | 294 | EVP_MD_CTX_uptr evp_md_ctx(EVP_MD_CTX_new()); 295 | if(evp_md_ctx == nullptr) // Could not create hash contex 296 | return -1; 297 | 298 | if(!EVP_DigestVerifyInit(evp_md_ctx.get(), nullptr, EVP_sha256(), nullptr, evp_pubkey_uptr.get())) 299 | return -1; // Could not initialize hash context 300 | 301 | 302 | if(EVP_DigestVerifyUpdate(evp_md_ctx.get(), message.c_str(), message.length()) != 1) 303 | return -1; 304 | 305 | int result = EVP_DigestVerifyFinal(evp_md_ctx.get(), 306 | reinterpret_cast(decoded_signature.c_str()), 307 | decoded_signature.length()); 308 | 309 | return result; 310 | } 311 | 312 | std::string OpenSSL::base64_decode(const std::string &message) { 313 | 314 | if(message.size() > std::numeric_limits::max()) 315 | return ""; 316 | 317 | if(message.empty()) 318 | return ""; 319 | 320 | std::string strippedMessage = stripNonBase64FromString(message); 321 | 322 | if(strippedMessage.empty() || message.size() > std::numeric_limits::max()) 323 | return ""; 324 | 325 | size_t decoded_size = (((strippedMessage.length() + 1) * 3) / 4); 326 | std::vector message_buffer(decoded_size); 327 | 328 | int length_decoded = EVP_DecodeBlock(reinterpret_cast(message_buffer.data()), 329 | reinterpret_cast(strippedMessage.c_str()), 330 | strippedMessage.length()); 331 | 332 | if(length_decoded <= 0) 333 | return ""; 334 | 335 | std::string result(message_buffer.data(), message_buffer.size()); 336 | result.erase(result.find_last_not_of('\0') + 1, std::string::npos); 337 | return result; 338 | } 339 | 340 | std::string OpenSSL::stripNonBase64FromString(const std::string &message) { 341 | std::string strippedMessage(message); 342 | strippedMessage.erase(std::remove_if(strippedMessage.begin(), strippedMessage.end(), 343 | [](const char c) { 344 | return allowed_base64.find(c) == std::string::npos; 345 | }), strippedMessage.cend()); 346 | return strippedMessage; 347 | } 348 | 349 | std::string OpenSSL::base64_encode(const std::string &message) { 350 | 351 | if(message.size() > std::numeric_limits::max()) 352 | return ""; 353 | 354 | if(message.empty()) 355 | return ""; 356 | 357 | size_t encoded_size = (1 + ((message.length() + 2) / 3 * 4)); 358 | std::vector message_buffer(encoded_size); 359 | 360 | int length_encoded = EVP_EncodeBlock(reinterpret_cast(message_buffer.data()), 361 | reinterpret_cast(message.c_str()), 362 | message.length()); 363 | 364 | if(length_encoded <= 0) 365 | return ""; 366 | 367 | std::string result(message_buffer.data(), message_buffer.size()); 368 | result.erase(result.find_last_not_of('\0') + 1, std::string::npos); 369 | return result; 370 | } 371 | 372 | 373 | std::vector OpenSSL::read_binary_file(const std::string &filename) { 374 | std::ifstream infile(filename, std::ios::binary); 375 | if(!infile) 376 | return {}; 377 | 378 | std::vector result(std::istreambuf_iterator(infile), {}); 379 | return result; 380 | } 381 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /tst/OpenSSL-test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023 Remy van Elst 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, version 3. 7 | * 8 | * This program is distributed in the hope that it will be useful, but 9 | * WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | * General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | */ 17 | 18 | 19 | #include "gtest/gtest.h" 20 | #include 21 | 22 | #define private public 23 | #include "OpenSSL.h" 24 | #undef private 25 | 26 | namespace fs = std::filesystem; 27 | 28 | struct OpenSSLTestSuite : public ::testing::Test 29 | { 30 | fs::path dataPath = fs::path(__FILE__).parent_path() / "data/"; 31 | OpenSSLTestSuite() = default; 32 | ~OpenSSLTestSuite() override = default; 33 | 34 | static std::string readFile(const fs::path& filename) { 35 | if(!fs::exists(filename)) 36 | return ""; 37 | 38 | std::ifstream in(filename); 39 | std::string out((std::istreambuf_iterator(in)), 40 | std::istreambuf_iterator()); 41 | return out; 42 | } 43 | }; 44 | 45 | 46 | struct OpenSSLWrappersTestSuite : public OpenSSLTestSuite 47 | { 48 | /* Tests related to the modern C++ wrappers, 49 | * unique_ptrs, TYPE_dup(), STACK_OF(), etc. */ 50 | }; 51 | 52 | struct OpenSSLChainTestSuite : public OpenSSLTestSuite 53 | { 54 | /* Tests related to methods that validate a single 55 | * certificate against a chain containing multiple 56 | * intermediate certificates. */ 57 | }; 58 | 59 | struct CustomVerifyCallBacksTestSuite : public OpenSSLChainTestSuite 60 | { 61 | /* Tests related to custom verify callbacks */ 62 | }; 63 | 64 | struct CustomParametersTestSuite : public OpenSSLChainTestSuite 65 | { 66 | /* Tests related to validation with custom parameters */ 67 | }; 68 | 69 | struct OpenSSLOneIntermediateTestSuite : public OpenSSLTestSuite 70 | { 71 | /* Tests related to the methods that validate a single 72 | * certificate against a single issuer */ 73 | }; 74 | 75 | struct OpenSSLDGSTSuite : public OpenSSLTestSuite 76 | { 77 | /* Tests related to methods that sign / verify */ 78 | }; 79 | 80 | 81 | struct OpenSSLDataGatheringTestSuite : public OpenSSLTestSuite 82 | { 83 | /* Tests related to certificate data parsing, like subject, 84 | * issuer, subjectAlternativeNames. */ 85 | }; 86 | 87 | TEST_F(OpenSSLDataGatheringTestSuite, certSubjectMatches) { 88 | //arrange 89 | auto cert_pem = readFile(dataPath / "raymii.org.2023.pem"); 90 | auto cert_x509 = OpenSSL::cert_to_x509(cert_pem); 91 | 92 | //act 93 | std::string result = OpenSSL::x509_subject(cert_x509.get()); 94 | 95 | //assert 96 | EXPECT_EQ(result, "CN=raymii.org"); 97 | } 98 | 99 | TEST_F(OpenSSLDataGatheringTestSuite, certSubjectEmptyOnNonExistingFile) { 100 | //arrange 101 | auto cert_pem = readFile(dataPath / "notexist.pem"); 102 | auto cert_x509 = OpenSSL::cert_to_x509(cert_pem); 103 | 104 | //act 105 | std::string result = OpenSSL::x509_subject(cert_x509.get()); 106 | 107 | //assert 108 | EXPECT_EQ(result, ""); 109 | } 110 | 111 | TEST_F(OpenSSLDataGatheringTestSuite, certSubjectEmptyOnGarbageFile) { 112 | //arrange 113 | auto cert_pem = readFile(dataPath / "gibberish.pem"); 114 | auto cert_x509 = OpenSSL::cert_to_x509(cert_pem); 115 | 116 | //act 117 | std::string result = OpenSSL::x509_subject(cert_x509.get()); 118 | 119 | //assert 120 | EXPECT_EQ(result, ""); 121 | } 122 | 123 | TEST_F(OpenSSLWrappersTestSuite, pointerEmptyOnNotExistingFile) { 124 | //arrange 125 | auto cert_pem = readFile(dataPath / "notexist.pem"); 126 | X509_uptr empty{nullptr}; 127 | 128 | //act 129 | auto cert_x509 = OpenSSL::cert_to_x509(cert_pem); 130 | 131 | //assert 132 | EXPECT_EQ(cert_x509, empty); 133 | } 134 | 135 | 136 | TEST_F(OpenSSLWrappersTestSuite, stackOfX509CorrectCountAndData) { 137 | //arrange 138 | auto cert_pem = readFile(dataPath / "Chain-Sectigo_UserTRUST_RSA.pem"); 139 | int expectedSize = 2; 140 | testing::internal::CaptureStderr(); 141 | 142 | //act 143 | auto stack_of_x509_certs = OpenSSL::certs_to_stack_of_x509(cert_pem); 144 | 145 | int actualSize = sk_X509_num(stack_of_x509_certs.get()); 146 | for (int i = 0; i < actualSize; i++) { 147 | X509* si = sk_X509_value(stack_of_x509_certs.get(), i); 148 | std::cerr << "i: " << i << "; subject: " << OpenSSL::x509_subject(si) << std::endl; 149 | std::cerr << "i: " << i << "; issuer : " << OpenSSL::x509_issuer(si)<< std::endl; 150 | } 151 | 152 | //assert 153 | EXPECT_EQ(actualSize, expectedSize); 154 | EXPECT_EQ(testing::internal::GetCapturedStderr(), "i: 0; subject: C=GB,ST=Greater Manchester,L=Salford,O=Sectigo Limited,CN=Sectigo RSA Domain Validation Secure Server CA\ni: 0; issuer : C=US,ST=New Jersey,L=Jersey City,O=The USERTRUST Network,CN=USERTrust RSA Certification Authority\ni: 1; subject: C=US,ST=New Jersey,L=Jersey City,O=The USERTRUST Network,CN=USERTrust RSA Certification Authority\ni: 1; issuer : C=US,ST=New Jersey,L=Jersey City,O=The USERTRUST Network,CN=USERTrust RSA Certification Authority\n"); 155 | } 156 | 157 | TEST_F(OpenSSLWrappersTestSuite, ErrorIfEmpty) { 158 | //arrange 159 | auto cert_pem = readFile(dataPath / "notexist.pem"); 160 | int expectedSize = -1; 161 | 162 | //act 163 | auto stack_of_x509_certs = OpenSSL::certs_to_stack_of_x509(cert_pem); 164 | int actualSize = sk_X509_num(stack_of_x509_certs.get()); 165 | 166 | //assert 167 | EXPECT_EQ(actualSize, expectedSize); 168 | } 169 | 170 | TEST_F(OpenSSLWrappersTestSuite, pointerEmptyOnGarbageFile) { 171 | //arrange 172 | auto cert_pem = readFile(dataPath / "gibberish.pem"); 173 | X509_uptr empty{nullptr}; 174 | 175 | //act 176 | auto cert_x509 = OpenSSL::cert_to_x509(cert_pem); 177 | 178 | //assert 179 | EXPECT_EQ(cert_x509, empty); 180 | } 181 | 182 | TEST_F(OpenSSLDataGatheringTestSuite, certIssuerMatches) { 183 | //arrange 184 | auto cert_pem = readFile(dataPath / "raymii.org.2023.pem"); 185 | auto cert_x509 = OpenSSL::cert_to_x509(cert_pem); 186 | 187 | //act 188 | std::string result = OpenSSL::x509_issuer(cert_x509.get()); 189 | 190 | //assert 191 | EXPECT_EQ(result, "C=GB,ST=Greater Manchester,L=Salford,O=Sectigo Limited,CN=Sectigo RSA Domain Validation Secure Server CA"); 192 | } 193 | 194 | 195 | TEST_F(OpenSSLDataGatheringTestSuite, certIssuerEmptyOnNonExistingFile) { 196 | //arrange 197 | auto cert_pem = readFile(dataPath / "notexist.pem"); 198 | auto cert_x509 = OpenSSL::cert_to_x509(cert_pem); 199 | 200 | //act 201 | std::string result = OpenSSL::x509_issuer(cert_x509.get()); 202 | 203 | //assert 204 | EXPECT_EQ(result, ""); 205 | } 206 | 207 | TEST_F(OpenSSLDataGatheringTestSuite, certIssuerEmptyOnGarbageFile) { 208 | //arrange 209 | auto cert_pem = readFile(dataPath / "gibberish.pem"); 210 | auto cert_x509 = OpenSSL::cert_to_x509(cert_pem); 211 | 212 | //act 213 | std::string result = OpenSSL::x509_issuer(cert_x509.get()); 214 | 215 | //assert 216 | EXPECT_EQ(result, ""); 217 | } 218 | 219 | 220 | TEST_F(OpenSSLOneIntermediateTestSuite, certSignedByIssuer) { 221 | //arrange 222 | auto cert_pem = readFile(dataPath / "raymii.org.2023.pem"); 223 | auto issuer_pem = readFile(dataPath / "Sectigo_RSA_Domain_Validation_Secure_Server_CA.pem"); 224 | 225 | //act 226 | int result = OpenSSL::verify_cert_signed_by_issuer(cert_pem, issuer_pem); 227 | 228 | //assert 229 | EXPECT_EQ(result, 1); 230 | } 231 | 232 | TEST_F(OpenSSLOneIntermediateTestSuite, issuerSignedByRoot) { 233 | //arrange 234 | auto issuer_pem = readFile(dataPath / "Sectigo_RSA_Domain_Validation_Secure_Server_CA.pem"); 235 | auto root_pem = readFile(dataPath / "USERTrust_RSA_Certification_Authority.pem"); 236 | 237 | //act 238 | int result = OpenSSL::verify_cert_signed_by_issuer(issuer_pem, root_pem); 239 | 240 | //assert 241 | EXPECT_EQ(result, 1); 242 | } 243 | 244 | TEST_F(OpenSSLOneIntermediateTestSuite, nonExistingClientResultsInError) { 245 | //arrange 246 | auto client_pem = readFile(dataPath / "notexist.pem"); 247 | auto issuer_pem = readFile(dataPath / "Sectigo_RSA_Domain_Validation_Secure_Server_CA.pem"); 248 | 249 | //act 250 | int result = OpenSSL::verify_cert_signed_by_issuer(client_pem, issuer_pem); 251 | 252 | //assert 253 | EXPECT_EQ(result, -1); 254 | } 255 | 256 | TEST_F(OpenSSLOneIntermediateTestSuite, garbageFileResultsInError) { 257 | //arrange 258 | auto client_pem = readFile(dataPath / "gibberish.pem"); 259 | auto issuer_pem = readFile(dataPath / "Sectigo_RSA_Domain_Validation_Secure_Server_CA.pem"); 260 | 261 | //act 262 | int result = OpenSSL::verify_cert_signed_by_issuer(client_pem, issuer_pem); 263 | 264 | //assert 265 | EXPECT_EQ(result, -1); 266 | } 267 | 268 | TEST_F(OpenSSLOneIntermediateTestSuite, garbageIssuerFileResultsInError) { 269 | //arrange 270 | auto client_pem = readFile(dataPath / "raymii.org.2023.pem"); 271 | auto issuer_pem = readFile(dataPath / "garbage.pem"); 272 | 273 | //act 274 | int result = OpenSSL::verify_cert_signed_by_issuer(client_pem, issuer_pem); 275 | 276 | //assert 277 | EXPECT_EQ(result, -1); 278 | } 279 | 280 | TEST_F(OpenSSLOneIntermediateTestSuite, nonExistingIssuerResultsInError) { 281 | //arrange 282 | auto client_pem = readFile(dataPath / "Sectigo_RSA_Domain_Validation_Secure_Server_CA.pem"); 283 | auto issuer_pem = readFile(dataPath / "notexist.pem"); 284 | 285 | //act 286 | int result = OpenSSL::verify_cert_signed_by_issuer(client_pem, issuer_pem); 287 | 288 | //assert 289 | EXPECT_EQ(result, -1); 290 | } 291 | 292 | 293 | TEST_F(OpenSSLOneIntermediateTestSuite, issuerNotSignedByFakeRootWithSameSubject) { 294 | //arrange 295 | auto issuer_pem = readFile(dataPath / "Sectigo_RSA_Domain_Validation_Secure_Server_CA.pem"); 296 | auto root_pem = readFile(dataPath / "FAKE_USERTrust_RSA_Certification_Authority.pem"); 297 | 298 | //act 299 | int result = OpenSSL::verify_cert_signed_by_issuer(issuer_pem, root_pem); 300 | 301 | //assert 302 | EXPECT_EQ(result, 0); 303 | } 304 | 305 | 306 | TEST_F(OpenSSLOneIntermediateTestSuite, clientNotSignedByRoot) { 307 | //arrange 308 | auto cert_pem = readFile(dataPath / "raymii.org.2023.pem"); 309 | auto root_pem = readFile(dataPath / "USERTrust_RSA_Certification_Authority.pem"); 310 | 311 | //act 312 | int result = OpenSSL::verify_cert_signed_by_issuer(cert_pem, root_pem); 313 | 314 | //assert 315 | EXPECT_EQ(result, 0); 316 | } 317 | 318 | TEST_F(OpenSSLChainTestSuite, certSignedByChain) { 319 | //arrange 320 | auto cert_pem = readFile(dataPath / "raymii.org.2023.pem"); 321 | auto chain_pem = readFile(dataPath / "Chain-Sectigo_UserTRUST_RSA.pem"); 322 | 323 | //act 324 | int result = OpenSSL::verify_cert_signed_by_chain(cert_pem, chain_pem); 325 | 326 | //assert 327 | EXPECT_EQ(result, 1); 328 | } 329 | 330 | 331 | TEST_F(OpenSSLChainTestSuite, emptyCertResultsInError) { 332 | //arrange 333 | auto cert_pem = readFile(dataPath / "notexist.pem"); 334 | auto chain_pem = readFile(dataPath / "Chain-Sectigo_UserTRUST_RSA.pem"); 335 | 336 | //act 337 | int result = OpenSSL::verify_cert_signed_by_chain(cert_pem, chain_pem); 338 | 339 | //assert 340 | EXPECT_EQ(result, -1); 341 | } 342 | 343 | TEST_F(OpenSSLWrappersTestSuite, certChainHasMultipleSubjects) { 344 | //arrange 345 | auto chain_pem = readFile(dataPath / "Chain-Sectigo_UserTRUST_RSA.pem"); 346 | auto chain = OpenSSL::certs_to_x509(chain_pem); 347 | 348 | //act & assert 349 | ASSERT_EQ(chain.size(), 2u); 350 | EXPECT_EQ(OpenSSL::x509_subject(chain[0].get()), "C=GB,ST=Greater Manchester,L=Salford,O=Sectigo Limited,CN=Sectigo RSA Domain Validation Secure Server CA"); 351 | EXPECT_EQ(OpenSSL::x509_subject(chain[1].get()), "C=US,ST=New Jersey,L=Jersey City,O=The USERTRUST Network,CN=USERTrust RSA Certification Authority"); 352 | } 353 | 354 | TEST_F(OpenSSLWrappersTestSuite, invalidIntermidiateInChainFails) { 355 | //arrange 356 | auto chain_pem = readFile(dataPath / "chain-with-gibberish-intermidiate.pem"); 357 | auto chain = OpenSSL::certs_to_x509(chain_pem); 358 | 359 | //act & assert 360 | ASSERT_EQ(chain.size(), 0u); 361 | } 362 | 363 | 364 | TEST_F(OpenSSLWrappersTestSuite, invalidRootInChainSkipsInvalidCertificate) { 365 | //arrange 366 | auto chain_pem = readFile(dataPath / "chain-with-gibberish-root.pem"); 367 | auto chain = OpenSSL::certs_to_x509(chain_pem); 368 | 369 | //act & assert 370 | ASSERT_EQ(chain.size(), 1u); 371 | EXPECT_EQ(OpenSSL::x509_subject(chain[0].get()), "C=GB,ST=Greater Manchester,L=Salford,O=Sectigo Limited,CN=Sectigo RSA Domain Validation Secure Server CA"); 372 | } 373 | 374 | 375 | TEST_F(OpenSSLWrappersTestSuite, emptyPEMResultsInEmptyString) { 376 | //arrange 377 | auto chain = OpenSSL::certs_to_x509(""); 378 | 379 | //act & assert 380 | ASSERT_TRUE(chain.empty()); 381 | } 382 | 383 | TEST_F(OpenSSLChainTestSuite, certNotSignedByWrongChain) { 384 | //arrange 385 | auto cert_pem = readFile(dataPath / "raymii.org.2023.pem"); 386 | auto chain_pem = readFile(dataPath / "Chain-Staat_der_Nederlanden_Organisatie.pem"); 387 | testing::internal::CaptureStderr(); 388 | 389 | 390 | //act 391 | int result = OpenSSL::verify_cert_signed_by_chain(cert_pem, chain_pem); 392 | 393 | //assert 394 | EXPECT_EQ(result, 0); 395 | EXPECT_EQ(testing::internal::GetCapturedStderr(), "unable to get local issuer certificate; "); 396 | } 397 | 398 | TEST_F(OpenSSLChainTestSuite, certNotSignedByEmptyChain) { 399 | //arrange 400 | auto cert_pem = readFile(dataPath / "raymii.org.2023.pem"); 401 | auto chain_pem = ""; 402 | 403 | //act 404 | int result = OpenSSL::verify_cert_signed_by_chain(cert_pem, chain_pem); 405 | 406 | //assert 407 | EXPECT_EQ(result, -1); 408 | } 409 | 410 | TEST_F(OpenSSLChainTestSuite, certNotSignedByChainWithGibberishIntermidiate) { 411 | //arrange 412 | auto cert_pem = readFile(dataPath / "raymii.org.2023.pem"); 413 | auto chain_pem = readFile(dataPath / "chain-with-gibberish-intermidiate.pem"); 414 | testing::internal::CaptureStderr(); 415 | 416 | //act 417 | int result = OpenSSL::verify_cert_signed_by_chain(cert_pem, chain_pem); 418 | 419 | //assert 420 | EXPECT_EQ(result, 0); 421 | EXPECT_EQ(testing::internal::GetCapturedStderr(), "unable to get local issuer certificate; "); 422 | } 423 | 424 | TEST_F(OpenSSLChainTestSuite, certSignedCheckFailsWhenChainWithGibberishRootProvided) { 425 | //arrange 426 | auto cert_pem = readFile(dataPath / "raymii.org.2023.pem"); 427 | auto chain_pem = readFile(dataPath / "chain-with-gibberish-root.pem"); 428 | 429 | //act 430 | int result = OpenSSL::verify_cert_signed_by_chain(cert_pem, chain_pem); 431 | 432 | //assert 433 | EXPECT_EQ(result, 0); 434 | } 435 | 436 | TEST_F(OpenSSLChainTestSuite, otherCertSignedOtherChain) { 437 | //arrange 438 | auto cert_pem = readFile(dataPath / "Digidentity_BV_PKIoverheid_Organisatie_Persoon_CA_G3.pem"); 439 | auto chain_pem = readFile(dataPath / "Chain-Staat_der_Nederlanden_Organisatie.pem"); 440 | testing::internal::CaptureStderr(); 441 | //act 442 | int result = OpenSSL::verify_cert_signed_by_chain(cert_pem, chain_pem); 443 | 444 | //assert 445 | EXPECT_EQ(result, 1); 446 | EXPECT_EQ(testing::internal::GetCapturedStderr(), ""); 447 | } 448 | 449 | 450 | TEST_F(CustomParametersTestSuite, expiredCertValidDueToParams) { 451 | //arrange 452 | auto cert_pem = readFile(dataPath / "expired-rsa-dv-ssl-com.pem"); 453 | auto chain_pem = readFile(dataPath / "expired-rsa-dv-ssl-com-chain.pem"); 454 | 455 | X509_VERIFY_PARAM_uptr param(X509_VERIFY_PARAM_new()); 456 | X509_VERIFY_PARAM_set_flags(param.get(), X509_V_FLAG_NO_CHECK_TIME); 457 | 458 | //act 459 | int result = OpenSSL::verify_cert_signed_by_chain(cert_pem, 460 | chain_pem, 461 | param.get()); 462 | 463 | //assert 464 | EXPECT_EQ(result, 1); 465 | }; 466 | 467 | TEST_F(OpenSSLChainTestSuite, expiredBadSSLCertInvalid) { 468 | //arrange 469 | auto cert_pem = readFile(dataPath / "expired.baddssl.com.cert.pem"); 470 | auto chain_pem = readFile(dataPath / "expired.baddssl.com.chain.pem"); 471 | testing::internal::CaptureStderr(); 472 | 473 | //act 474 | int result = OpenSSL::verify_cert_signed_by_chain(cert_pem, 475 | chain_pem); 476 | 477 | //assert 478 | EXPECT_EQ(result, 0); 479 | EXPECT_EQ(testing::internal::GetCapturedStderr(), "certificate has expired; "); 480 | } 481 | 482 | TEST_F(CustomParametersTestSuite, expiredBadSSLWithExpiredChainCertValidDueToParams) { 483 | //arrange 484 | auto cert_pem = readFile(dataPath / "expired.baddssl.com.cert.pem"); 485 | auto chain_pem = readFile(dataPath / "expired.baddssl.com.chain.pem"); 486 | 487 | X509_VERIFY_PARAM_uptr param(X509_VERIFY_PARAM_new()); 488 | X509_VERIFY_PARAM_set_flags(param.get(), X509_V_FLAG_NO_CHECK_TIME); 489 | 490 | //act 491 | int result = OpenSSL::verify_cert_signed_by_chain(cert_pem, chain_pem, 492 | param.get()); 493 | 494 | //assert 495 | EXPECT_EQ(result, 1); 496 | } 497 | 498 | 499 | TEST_F(CustomParametersTestSuite, signedByPartialChainAllowed) { 500 | //arrange 501 | auto cert_pem = readFile(dataPath / "raymii.org.2023.pem"); 502 | auto chain_pem = readFile(dataPath / "Incomplete-Chain-Sectigo_UserTRUST_RSA.pem"); 503 | 504 | // https://github.com/openssl/openssl/issues/7871 505 | // https://github.com/curl/curl/pull/4655 506 | X509_VERIFY_PARAM_uptr param(X509_VERIFY_PARAM_new()); 507 | X509_VERIFY_PARAM_set_flags(param.get(), X509_V_FLAG_PARTIAL_CHAIN); 508 | 509 | //act 510 | int result = OpenSSL::verify_cert_signed_by_chain(cert_pem, chain_pem, 511 | param.get()); 512 | 513 | //assert 514 | EXPECT_EQ(result, 1); 515 | } 516 | 517 | TEST_F(OpenSSLChainTestSuite, expiredCertInvalid) { 518 | //arrange 519 | auto cert_pem = readFile(dataPath / "expired-rsa-dv-ssl-com.pem"); 520 | auto chain_pem = readFile(dataPath / "expired-rsa-dv-ssl-com-chain.pem"); 521 | testing::internal::CaptureStderr(); 522 | 523 | //act 524 | int result = OpenSSL::verify_cert_signed_by_chain(cert_pem,chain_pem); 525 | 526 | //assert 527 | EXPECT_EQ(result, 0); 528 | EXPECT_EQ(testing::internal::GetCapturedStderr(), "certificate has expired; "); 529 | } 530 | 531 | TEST_F(CustomVerifyCallBacksTestSuite, expiredCertValidDueToCustomVerifyCallback) { 532 | //arrange 533 | auto cert_pem = readFile(dataPath / "expired-rsa-dv-ssl-com.pem"); 534 | auto chain_pem = readFile(dataPath / "expired-rsa-dv-ssl-com-chain.pem"); 535 | testing::internal::CaptureStderr(); 536 | 537 | auto verify_callback_accept_exipred = [](int ok, X509_STORE_CTX *ctx) { 538 | /* Tolerate certificate expiration */ 539 | if (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_CERT_HAS_EXPIRED) 540 | return 1; 541 | /* Otherwise don't override */ 542 | return ok; 543 | }; 544 | 545 | 546 | //act 547 | int result = OpenSSL::verify_cert_signed_by_chain(cert_pem, 548 | chain_pem, 549 | verify_callback_accept_exipred); 550 | 551 | //assert 552 | EXPECT_EQ(result, 1); 553 | EXPECT_EQ(testing::internal::GetCapturedStderr(), ""); 554 | } 555 | 556 | 557 | 558 | TEST_F(CustomVerifyCallBacksTestSuite, expiredCertPartialChainINVALIDEvenThoughExpiredIsAllowedInCallBack) { 559 | //arrange 560 | auto cert_pem = readFile(dataPath / "expired-rsa-dv-ssl-com.pem"); 561 | auto chain_pem = readFile(dataPath / "INCOMPLETE-expired-rsa-dv-ssl-com-chain.pem"); 562 | testing::internal::CaptureStderr(); 563 | 564 | auto verify_callback_accept_exipred = [](int ok, X509_STORE_CTX *ctx) { 565 | /* Tolerate certificate expiration */ 566 | if (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_CERT_HAS_EXPIRED) 567 | return 1; 568 | /* Otherwise don't override */ 569 | return ok; 570 | }; 571 | 572 | //act 573 | int result = OpenSSL::verify_cert_signed_by_chain(cert_pem, 574 | chain_pem, 575 | verify_callback_accept_exipred); 576 | 577 | //assert 578 | EXPECT_EQ(result, 0); 579 | EXPECT_EQ(testing::internal::GetCapturedStderr(), "unable to get issuer certificate; "); 580 | } 581 | 582 | TEST_F(CustomVerifyCallBacksTestSuite, expiredCertPartialChainValidDueToCustomVerifyCallbackAndParameter) { 583 | //arrange 584 | auto cert_pem = readFile(dataPath / "expired-rsa-dv-ssl-com.pem"); 585 | auto chain_pem = readFile(dataPath / "expired-rsa-dv-ssl-com-chain.pem"); 586 | testing::internal::CaptureStderr(); 587 | 588 | auto verify_callback_accept_exipred = [](int ok, X509_STORE_CTX *ctx) { 589 | /* Tolerate certificate expiration */ 590 | if (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_CERT_HAS_EXPIRED) 591 | return 1; 592 | /* Otherwise don't override */ 593 | return ok; 594 | }; 595 | 596 | X509_VERIFY_PARAM_uptr param(X509_VERIFY_PARAM_new()); 597 | X509_VERIFY_PARAM_set_flags(param.get(), X509_V_FLAG_PARTIAL_CHAIN); 598 | 599 | //act 600 | int result = OpenSSL::verify_cert_signed_by_chain(cert_pem, 601 | chain_pem, 602 | param.get(), 603 | verify_callback_accept_exipred); 604 | 605 | //assert 606 | EXPECT_EQ(result, 1); 607 | EXPECT_EQ(testing::internal::GetCapturedStderr(), ""); 608 | } 609 | 610 | TEST_F(OpenSSLDataGatheringTestSuite, certSANMatches) { 611 | //arrange 612 | auto cert_pem = readFile(dataPath / "raymii.org.2023.pem"); 613 | auto cert_x509 = OpenSSL::cert_to_x509(cert_pem); 614 | 615 | //act 616 | auto result = OpenSSL::x509_subject_alternative_dns_names(cert_x509.get()); 617 | 618 | //assert 619 | ASSERT_EQ(result.size(), 2); 620 | EXPECT_EQ(result[0], "raymii.org"); 621 | EXPECT_EQ(result[1], "www.raymii.org"); 622 | } 623 | 624 | TEST_F(OpenSSLDataGatheringTestSuite, FourSansMatches) { 625 | //arrange 626 | auto cert_pem = readFile(dataPath / "example.org.crt"); 627 | auto cert_x509 = OpenSSL::cert_to_x509(cert_pem); 628 | 629 | //act 630 | auto result = OpenSSL::x509_subject_alternative_dns_names(cert_x509.get()); 631 | 632 | //assert 633 | ASSERT_EQ(result.size(), 5); 634 | EXPECT_EQ(result[0], "example.org"); 635 | EXPECT_EQ(result[1], "www.example.org"); 636 | EXPECT_EQ(result[2], "ex.example.org"); 637 | EXPECT_EQ(result[3], "www.ex.example.org"); 638 | } 639 | 640 | TEST_F(OpenSSLDataGatheringTestSuite, noSANS) { 641 | //arrange 642 | auto cert_pem = readFile(dataPath / "Staat_der_Nederlanden_Organisatie_Persoon_CA_G3.pem"); 643 | auto cert_x509 = OpenSSL::cert_to_x509(cert_pem); 644 | 645 | //act 646 | auto result = OpenSSL::x509_subject_alternative_dns_names(cert_x509.get()); 647 | 648 | //assert 649 | ASSERT_EQ(result.size(), 0); 650 | } 651 | 652 | 653 | 654 | TEST_F(OpenSSLTestSuite, certNotSignedByFakeChain) { 655 | //arrange 656 | auto cert_pem = readFile(dataPath / "raymii.org.2023.pem"); 657 | auto chain_pem = readFile(dataPath / "FAKE-Chain-Sectigo_UserTRUST_RSA.pem"); 658 | 659 | //act 660 | int result = OpenSSL::verify_cert_signed_by_chain(cert_pem, chain_pem); 661 | 662 | //assert 663 | EXPECT_EQ(result, -1); 664 | } 665 | 666 | 667 | 668 | TEST_F(OpenSSLDGSTSuite, getPubKeyFromCert) { 669 | //arrange 670 | // openssl x509 -in raymii.org.2023.pem -pubkey -noout 671 | auto expected_pubkey_pem = 672 | "-----BEGIN PUBLIC KEY-----\n" 673 | "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvz5LrA5t1Bv4qzJX++bQ\n" 674 | "myR0eYPpBe/rgzEh5EhGDPoT6Jd1gtA59VaIPHrkag0eOY3xclko3TPSo5CftGMg\n" 675 | "aQWa8/ho8fChS5sjClucanMSz74+J0O9GE0Gw0WmchXwnUDaPr0U18VA5Mj5mw+x\n" 676 | "3cJ9YHZpZZkh3q7XP1X52MRF735eFVXAaRcuxrXUYf9+CcEZ9ahdU/rtP192uFsR\n" 677 | "phYYDWFk5Z5BscyykCLgiaQlwqs5pDQNEBt2I4WKzmUy8bXRRHQC4IKu8X1rbDQb\n" 678 | "8O7V64Vd0qimLDMKi+CA+jtvinC7mhkVOC8FG6oZgsR0xrIR4FY78yADXDHl53Qj\n" 679 | "iUmLeWO0hfNTANf+GGuNo1qcVXpbJVRFvJ1HpTScp8c92+GVmSgqz4EICHH92yFw\n" 680 | "m+lOyHdbj77RtqPDThSPFvhgKQhwSbzhvai3Jnsg0Jf0ZsUm/KJGrMQNFWD4cGSw\n" 681 | "xPn/MWsLGGFGQgLSuw6RoylKHTWUETlPFKd/ALXETstWZ/CEOjD6+Qj1Bvy9Gphr\n" 682 | "FryZrCMK7fvdsBjnDP5OMcdeNgewGF89aqW55bjTkOfMISBb1rRdYKfW8N0aA7hS\n" 683 | "3hW3gYwMRFo4xyZL4+oRg9/oM0JcKGwuKaZqjaFDucNipD2GFDsdkm7ZYj8CIxJ7\n" 684 | "yvTL4A1x2xHNrg7fmnt1GHUCAwEAAQ==\n" 685 | "-----END PUBLIC KEY-----\n"; 686 | 687 | auto cert_pem = readFile(dataPath / "raymii.org.2023.pem"); 688 | auto cert = OpenSSL::cert_to_x509(cert_pem); 689 | 690 | //act 691 | auto result = OpenSSL::x509_to_evp_pubkey(cert.get()); 692 | auto resultString = OpenSSL::x509_to_public_key_pem(cert.get()); 693 | 694 | 695 | //assert 696 | ASSERT_NE(result, nullptr); 697 | EXPECT_EQ(resultString, expected_pubkey_pem); 698 | } 699 | 700 | 701 | TEST_F(OpenSSLDGSTSuite, gibberishResultsInEmptyPubkey) { 702 | //arrange 703 | auto cert_pem = readFile(dataPath / "gibberish.pem"); 704 | auto cert = OpenSSL::cert_to_x509(cert_pem); 705 | 706 | //act 707 | auto result = OpenSSL::x509_to_evp_pubkey(cert.get()); 708 | auto resultString = OpenSSL::x509_to_public_key_pem(cert.get()); 709 | 710 | 711 | //assert 712 | ASSERT_EQ(result, nullptr); 713 | EXPECT_EQ(resultString, ""); 714 | } 715 | 716 | 717 | TEST_F(OpenSSLDGSTSuite, base64Decode) { 718 | //arrange 719 | auto encoded_input = "UmVteSBpcyBkZSBiZXN0ZQ=="; 720 | auto expected_decoded_output = "Remy is de beste"; 721 | 722 | //act 723 | auto result = OpenSSL::base64_decode(encoded_input); 724 | 725 | //assert 726 | EXPECT_EQ(result, expected_decoded_output); 727 | } 728 | 729 | 730 | TEST_F(OpenSSLDGSTSuite, base64Encode) { 731 | //arrange 732 | std::string decoded_input = "Remy is de beste!!!"; 733 | std::string expected_encoded_output = "UmVteSBpcyBkZSBiZXN0ZSEhIQ=="; 734 | 735 | //act 736 | std::string result = OpenSSL::base64_encode(decoded_input); 737 | 738 | //assert 739 | EXPECT_EQ(result, expected_encoded_output); 740 | } 741 | 742 | 743 | 744 | TEST_F(OpenSSLDGSTSuite, multiLineBase64Decode) { 745 | //arrange 746 | auto encoded_input = "UmVteSBpcy\n" 747 | "BkZSBiZXN0ZQ=="; 748 | auto expected_decoded_output = "Remy is de beste"; 749 | 750 | //act 751 | auto result = OpenSSL::base64_decode(encoded_input); 752 | 753 | //assert 754 | EXPECT_EQ(result, expected_decoded_output); 755 | } 756 | 757 | TEST_F(OpenSSLDGSTSuite, base64BinaryEncode) { 758 | //arrange 759 | auto decoded_input = OpenSSL::read_binary_file(dataPath / "raymii.org.2023.der"); 760 | std::string decoded_string(decoded_input.data(), decoded_input.size()); 761 | // coreutils base64 -w 0 raymii.org.2023.der: 762 | auto expected_encoded_output = "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"; 763 | 764 | //act 765 | auto result = OpenSSL::base64_encode(decoded_string); 766 | 767 | //assert 768 | EXPECT_EQ(result, expected_encoded_output); 769 | } 770 | 771 | 772 | TEST_F(OpenSSLDGSTSuite, base64BinaryDecode) { 773 | //arrange 774 | std::string encoded_input ("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"); 775 | auto binfile = OpenSSL::read_binary_file(dataPath / "raymii.org.2023.der"); 776 | std::string expected_decoded_output(binfile.data(), binfile.size()); 777 | 778 | //act 779 | auto result = OpenSSL::base64_decode(encoded_input); 780 | 781 | //assert 782 | EXPECT_EQ(result, expected_decoded_output); 783 | } 784 | 785 | 786 | TEST_F(OpenSSLDGSTSuite, base64DecodeEmpty) { 787 | EXPECT_EQ(OpenSSL::base64_decode(""), ""); 788 | } 789 | 790 | 791 | TEST_F(OpenSSLDGSTSuite, base64EncodeEmpty) { 792 | EXPECT_EQ(OpenSSL::base64_encode(""), "");; 793 | } 794 | 795 | 796 | 797 | TEST_F(OpenSSLDGSTSuite, verifyHashCorrect) { 798 | // arrange 799 | //openssl dgst -sha256 -sign tst_sign.key -out sign.txt.sha256 sign.txt 800 | //openssl dgst -sha256 -verify <(openssl x509 -in tst_sign.crt -pubkey -noout) -signature sign.txt.sha256 sign.txt 801 | //Verified OK 802 | //base64 sign.txt.sha256 > sign.txt.sha256.txt 803 | 804 | std::string message = readFile(dataPath / "sign.txt"); 805 | std::string base64_encoded_signature = readFile(dataPath / "sign.txt.sha256.txt"); 806 | X509_uptr cert_with_pubkey_that_signed_message = OpenSSL::cert_to_x509(readFile(dataPath / "tst_sign.crt")); 807 | 808 | // act 809 | int result = OpenSSL::verify_sha256_digest_signature(message, base64_encoded_signature, cert_with_pubkey_that_signed_message.get()); 810 | 811 | // assert 812 | EXPECT_EQ(result, 1); 813 | } 814 | 815 | 816 | TEST_F(OpenSSLDGSTSuite, verifyTamperedDataFails) { 817 | // arrange 818 | std::string message = readFile(dataPath / "sign-tampered.txt"); 819 | std::string base64_encoded_signature = readFile(dataPath / "sign.txt.sha256.txt"); 820 | X509_uptr cert_with_pubkey_that_signed_message = OpenSSL::cert_to_x509(readFile(dataPath / "tst_sign.crt")); 821 | 822 | // act 823 | int result = OpenSSL::verify_sha256_digest_signature(message, base64_encoded_signature, cert_with_pubkey_that_signed_message.get()); 824 | 825 | // assert 826 | EXPECT_EQ(result, 0); 827 | } 828 | 829 | 830 | TEST_F(OpenSSLDGSTSuite, verifyOtherCertificateFails) { 831 | // arrange 832 | std::string message = readFile(dataPath / "sign.txt"); 833 | std::string base64_encoded_signature = readFile(dataPath / "sign.txt.sha256.txt"); 834 | X509_uptr cert_with_pubkey_that_signed_message = OpenSSL::cert_to_x509(readFile(dataPath / "raymii.org.2023.pem")); 835 | 836 | // act 837 | int result = OpenSSL::verify_sha256_digest_signature(message, base64_encoded_signature, cert_with_pubkey_that_signed_message.get()); 838 | 839 | // assert 840 | EXPECT_EQ(result, 0); 841 | } 842 | 843 | TEST_F(OpenSSLDGSTSuite, verifyTamperedSignatureFails) { 844 | // arrange 845 | std::string message = readFile(dataPath / "sign-tampered.txt"); 846 | std::string base64_encoded_signature = readFile(dataPath / "sign.tampered.sha256.txt"); 847 | X509_uptr cert_with_pubkey_that_signed_message = OpenSSL::cert_to_x509(readFile(dataPath / "tst_sign.crt")); 848 | 849 | // act 850 | int result = OpenSSL::verify_sha256_digest_signature(message, base64_encoded_signature, cert_with_pubkey_that_signed_message.get()); 851 | 852 | // assert 853 | EXPECT_EQ(result, 0); 854 | } 855 | 856 | TEST_F(OpenSSLDGSTSuite, emptyMessageResultsInError) { 857 | // arrange 858 | std::string message; 859 | std::string base64_encoded_signature = readFile(dataPath / "sign.txt.sha256.txt"); 860 | X509_uptr cert_with_pubkey_that_signed_message = OpenSSL::cert_to_x509(readFile(dataPath / "tst_sign.crt")); 861 | 862 | // act 863 | int result = OpenSSL::verify_sha256_digest_signature(message, base64_encoded_signature, cert_with_pubkey_that_signed_message.get()); 864 | 865 | // assert 866 | EXPECT_EQ(result, -1); 867 | } 868 | 869 | 870 | TEST_F(OpenSSLDGSTSuite, emptySignatureResultsInError) { 871 | // arrange 872 | std::string message = readFile(dataPath / "sign.txt"); 873 | std::string base64_encoded_signature; 874 | X509_uptr cert_with_pubkey_that_signed_message = OpenSSL::cert_to_x509(readFile(dataPath / "tst_sign.crt")); 875 | 876 | // act 877 | int result = OpenSSL::verify_sha256_digest_signature(message, base64_encoded_signature, cert_with_pubkey_that_signed_message.get()); 878 | 879 | // assert 880 | EXPECT_EQ(result, -1); 881 | } 882 | 883 | 884 | TEST_F(OpenSSLDGSTSuite, emptyCertResultsInError) { 885 | // arrange 886 | std::string message = readFile(dataPath / "sign.txt"); 887 | std::string base64_encoded_signature = readFile(dataPath / "sign.txt.sha256.txt"); 888 | X509_uptr cert_with_pubkey_that_signed_message = nullptr; 889 | 890 | // act 891 | int result = OpenSSL::verify_sha256_digest_signature(message, base64_encoded_signature, cert_with_pubkey_that_signed_message.get()); 892 | 893 | // assert 894 | EXPECT_EQ(result, -1); 895 | } 896 | --------------------------------------------------------------------------------