diff --git a/CMakeLists.txt b/CMakeLists.txt index d7d812933d9..9e161950379 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -320,6 +320,11 @@ IF(WITH_CORE) FIND_QCAOSSL_PLUGIN_CPP(ENABLE_TESTS) ENDIF(NOT MSVC) + IF (APPLE) + # Libtasn1 is for DER-encoded PKI ASN.1 parsing/extracting workarounds + FIND_PACKAGE(Libtasn1 REQUIRED) + ENDIF (APPLE) + IF (SUPPRESS_QT_WARNINGS) # Newer versions of UseQt4.cmake include Qt with -isystem automatically # This can be used to force this behavior on older systems diff --git a/cmake/FindLibtasn1.cmake b/cmake/FindLibtasn1.cmake new file mode 100644 index 00000000000..c416e874760 --- /dev/null +++ b/cmake/FindLibtasn1.cmake @@ -0,0 +1,45 @@ +# Find Libtasn1 +# ~~~~~~~~~~~~~~~ +# CMake module to search for Libtasn1 ASN.1 library and header(s) from: +# https://www.gnu.org/software/libtasn1/ +# +# If it's found it sets LIBTASN1_FOUND to TRUE +# and following variables are set: +# LIBTASN1_INCLUDE_DIR +# LIBTASN1_LIBRARY +# +# Copyright (c) 2017, Boundless Spatial +# Author: Larry Shaffer +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + + +find_path(LIBTASN1_INCLUDE_DIR + NAMES libtasn1.h + PATHS + ${LIB_DIR}/include + "$ENV{LIB_DIR}/include" + $ENV{INCLUDE} + /usr/local/include + /usr/include +) + +find_library(LIBTASN1_LIBRARY + NAMES tasn1 + PATHS + ${LIB_DIR} + "$ENV{LIB_DIR}" + $ENV{LIB} + /usr/local/lib + /usr/lib +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + Libtasn1 + REQUIRED_VARS LIBTASN1_INCLUDE_DIR LIBTASN1_LIBRARY + FOUND_VAR LIBTASN1_FOUND +) + +mark_as_advanced(LIBTASN1_INCLUDE_DIR LIBTASN1_LIBRARY) diff --git a/resources/CMakeLists.txt b/resources/CMakeLists.txt index b2ed42bb823..fe9bbc4d1f9 100644 --- a/resources/CMakeLists.txt +++ b/resources/CMakeLists.txt @@ -9,3 +9,9 @@ INSTALL(DIRECTORY data DESTINATION ${QGIS_DATA_DIR}/resources) IF (WITH_SERVER) INSTALL(DIRECTORY server DESTINATION ${QGIS_DATA_DIR}/resources) ENDIF (WITH_SERVER) + +IF (APPLE) + # ASN.1 definition files of PKIX elements + INSTALL(FILES pkcs8.asn + DESTINATION ${QGIS_DATA_DIR}/resources) +ENDIF (APPLE) diff --git a/resources/pkcs8.asn b/resources/pkcs8.asn new file mode 100644 index 00000000000..2aee10089c8 --- /dev/null +++ b/resources/pkcs8.asn @@ -0,0 +1,63 @@ +PKCS-8 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-8(8) + modules(1) pkcs-8(1)} + +-- $Revision: 1.5 $ + +-- This module has been checked for conformance with the ASN.1 +-- standard by the OSS ASN.1 Tools + +DEFINITIONS EXPLICIT TAGS ::= + +BEGIN + +-- EXPORTS All -- +-- All types and values defined in this module is exported for use in +-- other ASN.1 modules. + +-- attribute data types -- + +Attribute ::= SEQUENCE { + type AttributeType, + values SET OF AttributeValue + -- at least one value is required -- +} + +AttributeType ::= OBJECT IDENTIFIER + +AttributeValue ::= ANY DEFINED BY type + +AttributeTypeAndValue ::= SEQUENCE { + type AttributeType, + value AttributeValue } + +AlgorithmIdentifier ::= SEQUENCE { + algorithm OBJECT IDENTIFIER, + parameters ANY DEFINED BY algorithm OPTIONAL } + -- contains a value of the type + -- registered for use with the + -- algorithm object identifier value + +-- Private-key information syntax + +PrivateKeyInfo ::= SEQUENCE { + version Version, + privateKeyAlgorithm AlgorithmIdentifier, + privateKey PrivateKey, + attributes [0] Attributes OPTIONAL } + +Version ::= INTEGER {v1(0)} + +PrivateKey ::= OCTET STRING + +Attributes ::= SET OF Attribute + +-- Encrypted private-key information syntax + +EncryptedPrivateKeyInfo ::= SEQUENCE { + encryptionAlgorithm AlgorithmIdentifier, + encryptedData EncryptedData +} + +EncryptedData ::= OCTET STRING + +END diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 6dcce0d9ea6..d898a12a6e7 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1179,6 +1179,13 @@ INCLUDE_DIRECTORIES(SYSTEM ${QTKEYCHAIN_INCLUDE_DIR} ) +IF (APPLE) + # Libtasn1 is for DER-encoded PKI ASN.1 parsing/extracting workarounds + INCLUDE_DIRECTORIES(SYSTEM + ${LIBTASN1_INCLUDE_DIR} + ) +ENDIF (APPLE) + #for PAL classes IF (WIN32) @@ -1249,7 +1256,7 @@ IF (WIN32) ENDIF (WIN32) IF (APPLE) - TARGET_LINK_LIBRARIES(qgis_core qgis_native) + TARGET_LINK_LIBRARIES(qgis_core qgis_native ${LIBTASN1_LIBRARY}) ENDIF (APPLE) IF (NOT WITH_INTERNAL_QEXTSERIALPORT) diff --git a/src/core/auth/qgsauthcertutils.cpp b/src/core/auth/qgsauthcertutils.cpp index 38b9dc5fd1d..e6bc1fd1137 100644 --- a/src/core/auth/qgsauthcertutils.cpp +++ b/src/core/auth/qgsauthcertutils.cpp @@ -23,9 +23,16 @@ #include #include +#include "qgsapplication.h" #include "qgsauthmanager.h" #include "qgslogger.h" +#ifdef Q_OS_MAC +#include +#include "libtasn1.h" +#endif + + QString QgsAuthCertUtils::getSslProtocolName( QSsl::SslProtocol protocol ) { switch ( protocol ) @@ -273,37 +280,242 @@ bool QgsAuthCertUtils::pemIsPkcs8( const QString &keyPemTxt ) return keyPemTxt.contains( pkcs8Header ) && keyPemTxt.contains( pkcs8Footer ); } +#ifdef Q_OS_MAC +QByteArray QgsAuthCertUtils::pkcs8PrivateKey( QByteArray &pkcs8Der ) +{ + QByteArray pkcs1; + + if ( pkcs8Der.isEmpty() ) + { + QgsDebugMsg( QStringLiteral( "ERROR, passed DER is empty" ) ); + return pkcs1; + } + // Dump as unarmored PEM format, e.g. missing '-----BEGIN|END...' wrapper + //QgsDebugMsg ( QStringLiteral( "pkcs8Der: %1" ).arg( QString( pkcs8Der.toBase64() ) ) ); + + QFileInfo asnDefsRsrc( QgsApplication::pkgDataPath() + QStringLiteral( "/resources/pkcs8.asn" ) ); + if ( ! asnDefsRsrc.exists() ) + { + QgsDebugMsg( QStringLiteral( "ERROR, pkcs.asn resource file not found: %1" ).arg( asnDefsRsrc.filePath() ) ); + return pkcs1; + } + const char *asnDefsFile = asnDefsRsrc.absoluteFilePath().toLocal8Bit().constData(); + + int asn1_result = ASN1_SUCCESS, der_len = 0, oct_len = 0; + asn1_node definitions = NULL, structure = NULL; + char errorDescription[ASN1_MAX_ERROR_DESCRIPTION_SIZE], oct_data[1024]; + unsigned char *der = NULL; + unsigned int flags = 0; //TODO: see if any or all ASN1_DECODE_FLAG_* flags can be set + unsigned oct_etype; + + // Base PKCS#8 element to decode + QString typeName( QStringLiteral( "PKCS-8.PrivateKeyInfo" ) ); + + asn1_result = asn1_parser2tree( asnDefsFile, &definitions, errorDescription ); + + switch ( asn1_result ) + { + case ASN1_SUCCESS: + QgsDebugMsgLevel( QStringLiteral( "Parse: done.\n" ), 4 ); + break; + case ASN1_FILE_NOT_FOUND: + QgsDebugMsg( QStringLiteral( "ERROR, file not found: %1" ).arg( asnDefsFile ) ); + return pkcs1; + case ASN1_SYNTAX_ERROR: + case ASN1_IDENTIFIER_NOT_FOUND: + case ASN1_NAME_TOO_LONG: + QgsDebugMsg( QStringLiteral( "ERROR, asn1 parsing: %1" ).arg( errorDescription ) ); + return pkcs1; + default: + QgsDebugMsg( QStringLiteral( "ERROR, libtasn1: %1" ).arg( asn1_strerror( asn1_result ) ) ); + return pkcs1; + } + + // Generate the ASN.1 structure + asn1_result = asn1_create_element( definitions, typeName.toLatin1().constData(), &structure ); + + //asn1_print_structure( stdout, structure, "", ASN1_PRINT_ALL); + + if ( asn1_result != ASN1_SUCCESS ) + { + QgsDebugMsg( QStringLiteral( "ERROR, structure creation: %1" ).arg( asn1_strerror( asn1_result ) ) ); + goto PKCS1DONE; + } + + // Populate the ASN.1 structure with decoded DER data + der = reinterpret_cast( pkcs8Der.data() ); + der_len = pkcs8Der.size(); + + if ( flags != 0 ) + { + asn1_result = asn1_der_decoding2( &structure, der, &der_len, flags, errorDescription ); + } + else + { + asn1_result = asn1_der_decoding( &structure, der, der_len, errorDescription ); + } + + if ( asn1_result != ASN1_SUCCESS ) + { + QgsDebugMsg( QStringLiteral( "ERROR, decoding: %1" ).arg( errorDescription ) ); + goto PKCS1DONE; + } + else + { + QgsDebugMsgLevel( QStringLiteral( "Decoding: %1" ).arg( asn1_strerror( asn1_result ) ), 4 ); + } + + if ( QgsLogger::debugLevel() >= 4 ) + { + QgsDebugMsg( QStringLiteral( "DECODING RESULT:" ) ); + asn1_print_structure( stdout, structure, "", ASN1_PRINT_NAME_TYPE_VALUE ); + } + + // Validate and extract privateKey value + QgsDebugMsgLevel( QStringLiteral( "Validating privateKey type..." ), 4 ); + typeName.append( QStringLiteral( ".privateKey" ) ); + QgsDebugMsgLevel( QStringLiteral( "privateKey element name: %1" ).arg( typeName ), 4 ); + + asn1_result = asn1_read_value_type( structure, "privateKey", NULL, &oct_len, &oct_etype ); + + if ( asn1_result != ASN1_MEM_ERROR ) // not sure why ASN1_MEM_ERROR = success, but it does + { + QgsDebugMsg( QStringLiteral( "ERROR, asn1 read privateKey value type: %1" ).arg( asn1_strerror( asn1_result ) ) ); + goto PKCS1DONE; + } + + if ( oct_etype != ASN1_ETYPE_OCTET_STRING ) + { + QgsDebugMsg( QStringLiteral( "ERROR, asn1 privateKey value not octet string, but type: %1" ).arg( static_cast( oct_etype ) ) ); + goto PKCS1DONE; + } + + if ( oct_len == 0 ) + { + QgsDebugMsg( QStringLiteral( "ERROR, asn1 privateKey octet string empty" ) ); + goto PKCS1DONE; + } + + QgsDebugMsgLevel( QStringLiteral( "Reading privateKey value..." ), 4 ); + asn1_result = asn1_read_value( structure, "privateKey", oct_data, &oct_len ); + + if ( asn1_result != ASN1_SUCCESS ) + { + QgsDebugMsg( QStringLiteral( "ERROR, asn1 read privateKey value: %1" ).arg( asn1_strerror( asn1_result ) ) ); + goto PKCS1DONE; + } + + if ( oct_len == 0 ) + { + QgsDebugMsg( QStringLiteral( "ERROR, asn1 privateKey value octet string empty" ) ); + goto PKCS1DONE; + } + + pkcs1 = QByteArray( oct_data, oct_len ); + + // !!! SENSITIVE DATA !!! + QgsDebugMsgLevel( QStringLiteral( "privateKey octet data as PEM: %1" ).arg( QString( pkcs1.toBase64() ) ), 9 ); + +PKCS1DONE: + + asn1_delete_structure( &structure ); + return pkcs1; +} +#endif + QStringList QgsAuthCertUtils::pkcs12BundleToPem( const QString &bundlepath, const QString &bundlepass, bool reencrypt ) { QStringList empty; if ( !QCA::isSupported( "pkcs12" ) ) + { + QgsDebugMsg( QString( "QCA does not support PKCS#12" ) ); return empty; + } QCA::KeyBundle bundle( QgsAuthCertUtils::qcaKeyBundle( bundlepath, bundlepass ) ); if ( bundle.isNull() ) + { + QgsDebugMsg( QString( "FAILED to convert PKCS#12 file to QCA key bundle: %1" ).arg( bundlepath ) ); return empty; + } QCA::SecureArray passarray; if ( reencrypt && !bundlepass.isEmpty() ) + { passarray = QCA::SecureArray( bundlepass.toUtf8() ); + } QString algtype; + QSsl::KeyAlgorithm keyalg = QSsl::Opaque; if ( bundle.privateKey().isRSA() ) { algtype = QStringLiteral( "rsa" ); + keyalg = QSsl::Rsa; } else if ( bundle.privateKey().isDSA() ) { algtype = QStringLiteral( "dsa" ); + keyalg = QSsl::Dsa; } else if ( bundle.privateKey().isDH() ) { algtype = QStringLiteral( "dh" ); } + // TODO: add support for EC keys, once QCA supports them - return QStringList() << bundle.certificateChain().primary().toPEM() << bundle.privateKey().toPEM( passarray ) << algtype; + // can currently only support RSA and DSA between QCA and Qt + if ( keyalg == QSsl::Opaque ) + { + QgsDebugMsg( QString( "FAILED to read PKCS#12 key (only RSA and DSA algorithms supported): %1" ).arg( bundlepath ) ); + return empty; + } + + QString keyPem; +#ifdef Q_OS_MAC + if ( keyalg == QSsl::Rsa && QgsAuthCertUtils::pemIsPkcs8( bundle.privateKey().toPEM() ) ) + { + QgsDebugMsgLevel( QString( "Private key is PKCS#8: attempting conversion to PKCS#1..." ), 4 ); + // if RSA, convert from PKCS#8 key to 'traditional' OpenSSL RSA format, which Qt prefers + // note: QCA uses OpenSSL, regardless of the Qt SSL backend, and 1.0.2+ OpenSSL versions return + // RSA private keys as PKCS#8, which choke Qt upon QSslKey creation + + QByteArray pkcs8Der = bundle.privateKey().toDER().toByteArray(); + if ( pkcs8Der.isEmpty() ) + { + QgsDebugMsg( QString( "FAILED to convert PKCS#12 key to DER-encoded format: %1" ).arg( bundlepath ) ); + return empty; + } + + QByteArray pkcs1Der = QgsAuthCertUtils::pkcs8PrivateKey( pkcs8Der ); + if ( pkcs1Der.isEmpty() ) + { + QgsDebugMsg( QString( "FAILED to convert PKCS#12 key from PKCS#8 to PKCS#1: %1" ).arg( bundlepath ) ); + return empty; + } + + QSslKey pkcs1Key( pkcs1Der, QSsl::Rsa, QSsl::Der, QSsl::PrivateKey ); + if ( pkcs1Key.isNull() ) + { + QgsDebugMsg( QString( "FAILED to convert PKCS#12 key from PKCS#8 to PKCS#1 QSslKey: %1" ).arg( bundlepath ) ); + return empty; + } + keyPem = QString( pkcs1Key.toPem( passarray.toByteArray() ) ); + } + else + { + keyPem = bundle.privateKey().toPEM( passarray ); + } +#else + keyPem = bundle.privateKey().toPEM( passarray ); +#endif + + QgsDebugMsgLevel( QString( "PKCS#12 cert as PEM:\n%1" ).arg( QString( bundle.certificateChain().primary().toPEM() ) ), 4 ); + // !!! SENSITIVE DATA !!! + QgsDebugMsgLevel( QString( "PKCS#12 key as PEM:\n%1" ).arg( QString( keyPem ) ), 9 ); + + return QStringList() << bundle.certificateChain().primary().toPEM() << keyPem << algtype; } QList QgsAuthCertUtils::pkcs12BundleCas( const QString &bundlepath, const QString &bundlepass ) diff --git a/src/core/auth/qgsauthcertutils.h b/src/core/auth/qgsauthcertutils.h index 064366de3ca..14f1abcd41f 100644 --- a/src/core/auth/qgsauthcertutils.h +++ b/src/core/auth/qgsauthcertutils.h @@ -171,6 +171,25 @@ class CORE_EXPORT QgsAuthCertUtils */ static bool pemIsPkcs8( const QString &keyPemTxt ); +#ifdef Q_OS_MAC + + /** + * Extract the PrivateKey ASN.1 element of a DER-encoded PKCS#8 private key + * \param pkcs8Der PKCS#8 DER-encoded private key data + * \returns DER-encoded private key on success or an empty QByteArray upon failure + * \note On some platforms, e.g. macOS, where the default SSL backend is not OpenSSL, a QSslKey + * can not be created using PKCS#8-formatted data. However, PKCS#8 private key ASN.1 structures + * contain the key data inside a wrapper describing the algorithm used, e.g. RSA, DSA, ECC etc. + * Extracted PrivateKey ASN.1 data can be used to create a compatible QSslKey, + * e.g. 'traditional' SSLeay RSA-specific PKCS#1. + * By default OpenSSL 1.0.0+ returns private keys as PKCS#8, previously it was PKCS#1. + * \note This function requires 'libtasn1' development files and library, which is used + * to parse and extract the PrivateKey element from an ASN.1 PKCS#8 structure. + */ + static QByteArray pkcs8PrivateKey( QByteArray &pkcs8Der ) SIP_SKIP; +#endif + + /** * Return list of certificate, private key and algorithm (as PEM text) for a PKCS#12 bundle * \param bundlepath File path to the PKCS bundle * \param bundlepass Passphrase for bundle diff --git a/tests/src/core/testqgsauthcertutils.cpp b/tests/src/core/testqgsauthcertutils.cpp index 28953180e0a..68ef765fb46 100644 --- a/tests/src/core/testqgsauthcertutils.cpp +++ b/tests/src/core/testqgsauthcertutils.cpp @@ -72,6 +72,63 @@ void TestQgsAuthCertUtils::testPkcsUtils() pkcs = QgsAuthCertUtils::fileData( sPkiData + "/gerardus_key-pkcs8-rsa.pem", false ); QVERIFY( !pkcs.isEmpty() ); QVERIFY( QgsAuthCertUtils::pemIsPkcs8( QString( pkcs ) ) ); + + +#ifdef Q_OS_MAC + QByteArray pkcs1; + pkcs.clear(); + + // Nothing should return nothing + pkcs1 = QgsAuthCertUtils::pkcs8PrivateKey( pkcs ); + QVERIFY( pkcs1.isEmpty() ); + + pkcs.clear(); + pkcs1.clear(); + // Is actually a PKCS#1 key, not #8 + pkcs = QgsAuthCertUtils::fileData( sPkiData + "/gerardus_key.der", false ); + QVERIFY( !pkcs.isEmpty() ); + pkcs1 = QgsAuthCertUtils::pkcs8PrivateKey( pkcs ); + QVERIFY( pkcs1.isEmpty() ); + + pkcs.clear(); + pkcs1.clear(); + // Is PKCS#1 PEM text, not DER + pkcs = QgsAuthCertUtils::fileData( sPkiData + "/gerardus_key.pem", false ); + QVERIFY( !pkcs.isEmpty() ); + pkcs1 = QgsAuthCertUtils::pkcs8PrivateKey( pkcs ); + QVERIFY( pkcs1.isEmpty() ); + + pkcs.clear(); + pkcs1.clear(); + // Is PKCS#8 PEM text, not DER + pkcs = QgsAuthCertUtils::fileData( sPkiData + "/gerardus_key-pkcs8-rsa.pem", false ); + QVERIFY( !pkcs.isEmpty() ); + pkcs1 = QgsAuthCertUtils::pkcs8PrivateKey( pkcs ); + QVERIFY( pkcs1.isEmpty() ); + + pkcs.clear(); + pkcs1.clear(); + // Correct PKCS#8 DER input + pkcs = QgsAuthCertUtils::fileData( sPkiData + "/gerardus_key-pkcs8-rsa.der", false ); + QVERIFY( !pkcs.isEmpty() ); + pkcs1 = QgsAuthCertUtils::pkcs8PrivateKey( pkcs ); + QVERIFY( !pkcs1.isEmpty() ); + + // PKCS#8 DER format should fail, and the reason for QgsAuthCertUtils::pkcs8PrivateKey + // (as of Qt5.9.0, and where macOS Qt5 SSL backend is not OpenSSL, and + // where PKCS#8 is *still* unsupported for macOS) + QSslKey pkcs8Key( pkcs, QSsl::Rsa, QSsl::Der, QSsl::PrivateKey ); + QVERIFY( pkcs8Key.isNull() ); + + // PKCS#1 DER format should work + QSslKey pkcs1Key( pkcs1, QSsl::Rsa, QSsl::Der, QSsl::PrivateKey ); + QVERIFY( !pkcs1Key.isNull() ); + + // Converted PKCS#8 DER should match PKCS#1 PEM + QByteArray pkcs1PemRef = QgsAuthCertUtils::fileData( sPkiData + "/gerardus_key.pem", true ); + QVERIFY( !pkcs1PemRef.isEmpty() ); + QCOMPARE( pkcs1Key.toPem(), pkcs1PemRef ); +#endif } QGSTEST_MAIN( TestQgsAuthCertUtils ) diff --git a/tests/testdata/auth_system/certs_keys/fra_key-pkcs8-rsa.der b/tests/testdata/auth_system/certs_keys/fra_key-pkcs8-rsa.der new file mode 100644 index 00000000000..cd0638a71ec Binary files /dev/null and b/tests/testdata/auth_system/certs_keys/fra_key-pkcs8-rsa.der differ diff --git a/tests/testdata/auth_system/certs_keys/fra_key-pkcs8-rsa.pem b/tests/testdata/auth_system/certs_keys/fra_key-pkcs8-rsa.pem new file mode 100644 index 00000000000..84185ddf38f --- /dev/null +++ b/tests/testdata/auth_system/certs_keys/fra_key-pkcs8-rsa.pem @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAOOA/yLAj0TOL6Z3 +OGY+2JxaSmStwl5veQjp+VoAOoxDVjQDOxuBNihZ1gGUVPc2cQm8HS+nMizw9SiC +l0ZiP23QqkL9Xgd1+scE1Hhxf8cvTp2Ek3QKbKlfol3wGZgGElwkrVed77+l7PjX +VxLd2UbnZEF8TURntOyMKeYwi53vAgMBAAECgYA9/tIH41dnVZSQlV5uJmQav1QU +eXFFELV342KKzxMlU9gy1kqOJTjf6BM0XPqGX3SQRY3ihXpb2tHD10pn6LAFtiOR +ymfPJ+fs3TiPUn+Ut7TkedKkTxu5IT5C5Nu0FllcTo9mpi5ytfu6D+gkrB8fX/fZ +5+jGdevrd9WWU+v5wQJBAP8AerrTiFLCJRocP/jIdwg+gmEdcPYg5cmeNVpAUuAN +CSa5QYIQ9xB3ERUVo4ODCEGQFdYDZaPPvGp5wICo9U8CQQDkZPaaj4UegQZp/Vkf +7fQBmRzVhccxewV/HlEqJR1iQydjN3SfTU3cI0QmZL805emSN0f2sgT4lV4tdLbJ +ueVhAkEAk2C+jf21u0bz1IxhOLL7gKtIBULTx5yp0gX7BedJPq6qDFRjlP2jHUQD +fnEcKOTxP5s7043xD2T/m3Y0mOeNpwJAaFDI5Y05otYRhOVnCJNZSEWTit7APRRQ +TWAeeB5djlzXp5RTmtLnBe3BmbuYLWP5S4QeRUnHxXYLfr15IyfZ4QJBAMxGWwet +yoR03gyOwSagP53hcV5wGWu1ThKlmzrLl6ulJYb/3lwbYeNCaI5ZzGaSiycWC/8K +9zIREiwz1u/iupk= +-----END PRIVATE KEY----- diff --git a/tests/testdata/auth_system/certs_keys/gerardus_key-pkcs8-rsa.der b/tests/testdata/auth_system/certs_keys/gerardus_key-pkcs8-rsa.der new file mode 100644 index 00000000000..41ce8280105 Binary files /dev/null and b/tests/testdata/auth_system/certs_keys/gerardus_key-pkcs8-rsa.der differ diff --git a/tests/testdata/auth_system/certs_keys/gerardus_key-pkcs8-rsa.pem b/tests/testdata/auth_system/certs_keys/gerardus_key-pkcs8-rsa.pem new file mode 100644 index 00000000000..27313ab3b80 --- /dev/null +++ b/tests/testdata/auth_system/certs_keys/gerardus_key-pkcs8-rsa.pem @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBALrXW9BbnHSp96kA +naNMFr7Wu4xUd0HwPiLmkSpriRqSMI9EQF6+Bib50BIHYGpmAXdsH44FoD8k2r9q +C5sjiJpQY7pba3IB/n0pGufQJe4rw2lKWBKvl3ADjVoqPfCBT5mnpyEppDmXxOJr +ANH+ojsnjZh44fkq6emgEfganGcrAgMBAAECgYEAuO2jQG0MRCRernWfkRskgCrF +YrXPfAIvXhfboqLhBt2fFo41MBDgwf8MRGvssCLaXLs12DoVS6pMoJxzdFANSQyl +Oqf2wLtiTMzjPslv7x8R2ho/0uLxeccP5xHpLSxypbcXF3PzCxp4gNpnZWDvwx9V +Ofgrsjx//toTiMcSYiECQQDurSJmr+wDoBblptvFbO8KrfnkvMlTlQqeYQXmceGg +Mdxcygm3nqAw/Tiqd5LUGLgQP3R/Sot8ZjSPtLme6ilTAkEAyGcSiFhx/eIYwWmp +L1AJ4DSp9MQI3nVxxwrKWwyq48zxrDcSZcUJYFMphgfgzTwupTMoDNwxPiNdkUxN +SdaXyQJAIUSyydt1q1+yMVqbwZ4Yh8WOUoraCTN6Im9lsiRnjbvFeo2S4yxSKeHx +9xjpt3Smm2Us6N1MKg/Y/br0MKl1DwJBAIIGrnWcvUl3G4zSm51BF0dLpEJVt1Nv +bEUy8RymWXK4lM2iZeN2NqEzFCwMjIVdWP6C9KdzbtfcZmdR1IvmGlECQQDDzyIT +6g6z5IxBF1zQJAct34UZyLR+gjcTnT4CAjensHbpEbUvBuKT4D8S+No643rCwRQz +mgvgSjp6glQuamby +-----END PRIVATE KEY----- diff --git a/tests/testdata/auth_system/certs_keys/nicholas_key-pkcs8-rsa.der b/tests/testdata/auth_system/certs_keys/nicholas_key-pkcs8-rsa.der new file mode 100644 index 00000000000..55cc41591c4 Binary files /dev/null and b/tests/testdata/auth_system/certs_keys/nicholas_key-pkcs8-rsa.der differ diff --git a/tests/testdata/auth_system/certs_keys/nicholas_key-pkcs8-rsa.pem b/tests/testdata/auth_system/certs_keys/nicholas_key-pkcs8-rsa.pem new file mode 100644 index 00000000000..b31733e44ad --- /dev/null +++ b/tests/testdata/auth_system/certs_keys/nicholas_key-pkcs8-rsa.pem @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMuZd8GDiWvpMU7W +LJBSeDL/bXzdbnmL35RmF+gDOQOS5zZFFz6Nn2PD6xPJxPTSzG46BLjeXdvZVsNN +nx8JvLZ4XdehXGdue9C8iHTeNS5di/E9rwBYRaHK9D8NUN54xQLs7SL4v5Y//x3/ +1p2pRWzhMsJm4o4xi2A0pi4qQmthAgMBAAECgYBIMrvM26A3rBHYKwrSguws6Xch ++EPcxkUakrmXhM0K/2UOUaHUhNQoxKjv83TsfHQSAnD6PaB6/a9Owo/SqdlJGXv3 +f+lvsHx283/PCD/fO/P0NE6L/9S0yYKbYd5r1PvbWBM66+AKS/1u6GevIp9UCpOJ +f7P3xwTOcNSIPgP2AQJBAO9vyckXBNcmtASzOUikQk+K4qyQEqzysS1HpuLt7y/w +r75BB2sM8h7cXimYIlSPTbPrcMXzoA0rB6iHrhq1sIkCQQDZrwjd/SC9y/9fi+LB +MxNnai/f9h+nQzP2VWLNIakDIHXcHaqWp2GjvQW+M6XH/pMJ8g7iFbXi2YtVL2iA +6z4ZAkAvXfkYXAJsIc75Iw+RDFXF8J7ZLoNTTYu5fnRIbnOkE0RhKfIyvlPjwQqr +xdn8yoC/uDMOJh0incGdGIJb7FepAkB18c2XIdB8paw/Y7a/wWHRFYrNCTkLUnE0 +Ff2LcaJ2jD7vva8xI43WvtL+xFMdsoSOzfVccDD1sbM5u48e0tb5AkA24I2q6BE8 +dkW3irynMHLu2y19C6k/QeZRExix8dEpLJh0MRPwtIqeijMav+YSzHLO2h7sHhB3 +LDQWscGKrSRu +-----END PRIVATE KEY----- diff --git a/tests/testdata/auth_system/certs_keys/ptolemy_key-pkcs8-rsa.der b/tests/testdata/auth_system/certs_keys/ptolemy_key-pkcs8-rsa.der new file mode 100644 index 00000000000..4f170ec062d Binary files /dev/null and b/tests/testdata/auth_system/certs_keys/ptolemy_key-pkcs8-rsa.der differ diff --git a/tests/testdata/auth_system/certs_keys/ptolemy_key-pkcs8-rsa.pem b/tests/testdata/auth_system/certs_keys/ptolemy_key-pkcs8-rsa.pem new file mode 100644 index 00000000000..9ca8ca3c421 --- /dev/null +++ b/tests/testdata/auth_system/certs_keys/ptolemy_key-pkcs8-rsa.pem @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAK7KI7uoxRgWQ4AI +dAqsGao/M1Mg0C8poMQuv4k2ORplioPLlna5fTlhBFZBiB9f86QLoonwS0iEwhs3 +5VdJtlvEorjud7HmQesU6SWk7bNBQTdWbJPJgM48ivIjZSjVvBj3zEDJL5u948uJ +67zP1gQ5qqOrXDCV5KpXGOkRDDubAgMBAAECgYAgNQcYkSSgJ5oQgX5AaS3hfPvM +GYPC7Py+qY6JjgA/qO45Es6K2esFI6dU7YZToa6XT72HhUuZ9Tx/H3GW//Il8MJh +WEmiy6hB+yX3yEgq+CuUCgxnZd6BhX6H3O4dRBFxHaTEUjQJpZWrIS0vAzbdgJuM +vDbNDYuYgF/ZAMwGYQJBANbxDJzrYQxIelamwiEO9uPGvOoHRopLoIaFZPneSnpp +kIyLoCqikAjQuqeqVEOFXlYFfR8wVT9aq/RXqaw0A00CQQDQLZnGwhiaptBn8BL+ +6RjJM1Rmc1jmjiSNkp+ow573ttJhdgHnC0+CjOcwQu5Db2nzDkT+kkOLm5aCzOuZ +/XaHAkEAgAUOWCAxq1k31Ih6M6pwDnZ+an1u3EvzDmxBGjn17jcV6z/2Y65zT2zS +364phhXXfDDEt2DYRWXB6USVQIWyOQJAdEkEnQHOvJRx1Z1E/x81uS3y90d3YVIF +GQ/OH3cmVTjKS6afaW/n+gS7HzpD3Wdex2YxJAKPuGwwpt/QuzPaAQJAGP8nj5g9 +oYxzD+x018fxSf/BsTjXU2S6SrbIg5D4B5s5kYFXOvLUS4rfjGWxssyHdtZuFf7T +VMmSp5bTS7YAfQ== +-----END PRIVATE KEY-----