VirtualBox

Changeset 100528 in vbox for trunk/src/VBox/Runtime


Ignore:
Timestamp:
Jul 11, 2023 10:52:34 PM (17 months ago)
Author:
vboxsync
Message:

IPRT/PKCS8: Added the ability to load PKCS\#8 EncryptedPrivateKey format. bugref:10299

Location:
trunk/src/VBox/Runtime
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/crypto/key-file.cpp

    r100494 r100528  
    3939*   Header Files                                                                                                                 *
    4040*********************************************************************************************************************************/
     41#define LOG_GROUP RTLOGGROUP_CRYPTO
    4142#include "internal/iprt.h"
    4243#include <iprt/crypto/key.h>
     
    4748#include <iprt/ctype.h>
    4849#include <iprt/err.h>
     50#include <iprt/log.h>
    4951#include <iprt/mem.h>
    5052#include <iprt/memsafer.h>
     
    6264# include "internal/iprt-openssl.h"
    6365# include "internal/openssl-pre.h"
     66# include <openssl/err.h>
    6467# include <openssl/evp.h>
     68# include <openssl/pkcs12.h>
    6569# include "internal/openssl-post.h"
    6670# ifndef OPENSSL_VERSION_NUMBER
     
    114118RT_DECL_DATA_CONST(RTCRPEMMARKER const) g_aRTCrKeyAllMarkers[] =
    115119{
    116     { g_aWords_RsaPublicKey,  RT_ELEMENTS(g_aWords_RsaPublicKey) },
    117     { g_aWords_PublicKey,     RT_ELEMENTS(g_aWords_PublicKey) },
    118     { g_aWords_RsaPrivateKey, RT_ELEMENTS(g_aWords_RsaPrivateKey) },
    119     { g_aWords_PrivateKey,    RT_ELEMENTS(g_aWords_PrivateKey) },
     120    { g_aWords_RsaPublicKey,        RT_ELEMENTS(g_aWords_RsaPublicKey) },
     121    { g_aWords_PublicKey,           RT_ELEMENTS(g_aWords_PublicKey) },
     122    { g_aWords_RsaPrivateKey,       RT_ELEMENTS(g_aWords_RsaPrivateKey) },
     123    { g_aWords_EncryptedPrivateKey, RT_ELEMENTS(g_aWords_EncryptedPrivateKey) },
     124    { g_aWords_PrivateKey,          RT_ELEMENTS(g_aWords_PrivateKey) },
    120125};
    121126/** Number of entries in g_aRTCrKeyAllMarkers. */
    122127RT_DECL_DATA_CONST(uint32_t const) g_cRTCrKeyAllMarkers = RT_ELEMENTS(g_aRTCrKeyAllMarkers);
     128
     129
     130/**
     131 * Creates a key from a raw PKCS\#8 PrivateKeyInfo structure.
     132 *
     133 * This is common code to both kKeyFormat_PrivateKeyInfo and
     134 * kKeyFormat_EncryptedPrivateKeyInfo.
     135 *
     136 * @returns IPRT status code.
     137 * @param   phKey           Where to return the key handle on success.
     138 * @param   pPrimaryCursor  Cursor structure to use.
     139 * @param   pbRaw           The raw PrivateKeyInfo bytes.
     140 * @param   cbRaw           Size of the raw PrivateKeyInfo structure.
     141 * @param   pErrInfo        Where to return additional error information.
     142 * @param   pszErrorTag     What to tag the decoding with.
     143 */
     144static int rtCrKeyCreateFromPrivateKeyInfo(PRTCRKEY phKey, PRTASN1CURSORPRIMARY pPrimaryCursor,
     145                                           uint8_t const *pbRaw, size_t cbRaw, PRTERRINFO pErrInfo, const char *pszErrorTag)
     146
     147{
     148    RTCRPKCS8PRIVATEKEYINFO PrivateKeyInfo;
     149    RT_ZERO(PrivateKeyInfo);
     150    RTAsn1CursorInitPrimary(pPrimaryCursor, pbRaw, (uint32_t)cbRaw, pErrInfo, &g_RTAsn1DefaultAllocator,
     151                            RTASN1CURSOR_FLAGS_DER, pszErrorTag);
     152    int rc = RTCrPkcs8PrivateKeyInfo_DecodeAsn1(&pPrimaryCursor->Cursor, 0, &PrivateKeyInfo,
     153                                                pszErrorTag ? pszErrorTag : "PrivateKeyInfo");
     154    if (RT_SUCCESS(rc))
     155    {
     156        /*
     157         * Load the private key according to it's algorithm.
     158         * We currently only support RSA (pkcs1-RsaEncryption).
     159         */
     160        if (RTAsn1ObjId_CompareWithString(&PrivateKeyInfo.PrivateKeyAlgorithm.Algorithm, RTCRX509ALGORITHMIDENTIFIERID_RSA) == 0)
     161            rc = rtCrKeyCreateRsaPrivate(phKey, PrivateKeyInfo.PrivateKey.Asn1Core.uData.pv,
     162                                         PrivateKeyInfo.PrivateKey.Asn1Core.cb, pErrInfo, pszErrorTag);
     163        else
     164            rc = RTERRINFO_LOG_SET(pErrInfo, VERR_CR_KEY_FORMAT_NOT_SUPPORTED,
     165                                   "Support for PKCS#8 PrivateKeyInfo for non-RSA keys is not yet implemented");
     166        RTCrPkcs8PrivateKeyInfo_Delete(&PrivateKeyInfo);
     167    }
     168    return rc;
     169}
     170
     171
     172/**
     173 * Decrypts a PEM message.
     174 *
     175 * @returns IPRT status code
     176 * @param   pEncryptedKey       The encrypted private key information.
     177 * @param   pszPassword         The password to use to decrypt the key text.
     178 * @param   ppbDecrypted        Where to return the decrypted message. Free using RTMemSaferFree.
     179 * @param   pcbDecrypted        Where to return the length of the decrypted message.
     180 * @param   pcbDecryptedAlloced Where to return the allocation size.
     181 * @param   pErrInfo            Where to return additional error information.
     182 */
     183static int rtCrKeyDecryptPkcs8Info(PRTCRPKCS8ENCRYPTEDPRIVATEKEYINFO pEncryptedKey, const char *pszPassword,
     184                                   uint8_t **ppbDecrypted, size_t *pcbDecrypted, size_t *pcbDecryptedAlloced, PRTERRINFO pErrInfo)
     185{
     186    /*
     187     * Initialize return values.
     188     */
     189    *ppbDecrypted        = NULL;
     190    *pcbDecrypted        = 0;
     191    *pcbDecryptedAlloced = 0;
     192
     193    /*
     194     * This operation requires a password.
     195     */
     196    if (!pszPassword)
     197        return VERR_CR_KEY_ENCRYPTED;
     198
     199#ifdef IPRT_WITH_OPENSSL /** @todo abstract encryption & decryption. */
     200
     201    /*
     202     * Query the EncryptionAlgorithm bytes so we can construction a X509_ALGOR
     203     * for use in PKCS12_pbe_crypt.
     204     */
     205    void          *pvAlgoFree = NULL;
     206    const uint8_t *pbAlgoRaw  = NULL;
     207    uint32_t       cbAlgoRaw  = 0;
     208    int rc = RTAsn1EncodeQueryRawBits(&pEncryptedKey->EncryptionAlgorithm.SeqCore.Asn1Core,
     209                                      &pbAlgoRaw, &cbAlgoRaw, &pvAlgoFree, pErrInfo);
     210    AssertRCReturn(rc, rc);
     211
     212    const unsigned char *puchAlgo     = pbAlgoRaw;
     213    X509_ALGOR          *pOsslAlgoRet = NULL;
     214    pOsslAlgoRet = d2i_X509_ALGOR(&pOsslAlgoRet, &puchAlgo, cbAlgoRaw);
     215
     216    RTMemTmpFree(pvAlgoFree);
     217    if (pOsslAlgoRet)
     218    {
     219        /*
     220         * Do the decryption (en_de = 0).
     221         */
     222        int            cbDecrypted   = 0;
     223        unsigned char *puchDecrypted = NULL;
     224        puchDecrypted = PKCS12_pbe_crypt(pOsslAlgoRet, pszPassword, (int)strlen(pszPassword),
     225                                         pEncryptedKey->EncryptedData.Asn1Core.uData.puch,
     226                                         (int)pEncryptedKey->EncryptedData.Asn1Core.cb,
     227                                         &puchDecrypted, &cbDecrypted, 0 /*en_de*/);
     228        if (puchDecrypted)
     229        {
     230            /*
     231             * Transfer to a safer buffer and carefully wipe the OpenSSL buffer.
     232             */
     233            uint8_t *pbFinal = (uint8_t *)RTMemSaferAllocZ(cbDecrypted);
     234            if (pbFinal)
     235            {
     236                memcpy(pbFinal, puchDecrypted, cbDecrypted);
     237                *ppbDecrypted        = pbFinal;
     238                *pcbDecrypted        = cbDecrypted;
     239                *pcbDecryptedAlloced = cbDecrypted;
     240                rc = VINF_SUCCESS;
     241            }
     242            else
     243                rc = VERR_NO_MEMORY;
     244            RTMemWipeThoroughly(puchDecrypted, cbDecrypted, 3);
     245            OPENSSL_free(puchDecrypted);
     246        }
     247        else
     248            rc = RTERRINFO_LOG_SET_F(pErrInfo, VERR_CR_KEY_DECRYPTION_FAILED,
     249                                     "Incorrect password? d2i_X509_ALGOR failed (%u)", ERR_get_error());
     250        X509_ALGOR_free(pOsslAlgoRet);
     251    }
     252    else
     253        rc = RTERRINFO_LOG_SET_F(pErrInfo, VERR_CR_PKIX_OSSL_D2I_PRIVATE_KEY_FAILED /* close enough */,
     254                                 "d2i_X509_ALGOR failed (%u)", ERR_get_error());
     255    return rc;
     256
     257#else
     258    RT_NOREF(pEncryptedKey, pszPassword, pErrInfo);
     259    return VERR_CR_KEY_DECRYPTION_NOT_SUPPORTED;
     260#endif
     261}
    123262
    124263
     
    173312
    174313    /*
    175      * Do we support the cihper?
     314     * Do we support the cipher?
    176315     */
    177316#ifdef IPRT_WITH_OPENSSL /** @todo abstract encryption & decryption. */
     
    471610
    472611        case kKeyFormat_PrivateKeyInfo:
     612            rc = rtCrKeyCreateFromPrivateKeyInfo(phKey, &PrimaryCursor, pSection->pbData, pSection->cbData, pErrInfo, pszErrorTag);
     613            break;
     614
     615        case kKeyFormat_EncryptedPrivateKeyInfo:
    473616        {
    474617            RTAsn1CursorInitPrimary(&PrimaryCursor, pSection->pbData, (uint32_t)pSection->cbData,
    475618                                    pErrInfo, &g_RTAsn1DefaultAllocator, RTASN1CURSOR_FLAGS_DER, pszErrorTag);
    476             RTCRPKCS8PRIVATEKEYINFO PrivateKeyInfo;
    477             RT_ZERO(PrivateKeyInfo);
    478             rc = RTCrPkcs8PrivateKeyInfo_DecodeAsn1(&PrimaryCursor.Cursor, 0, &PrivateKeyInfo,
    479                                                     pszErrorTag ? pszErrorTag : "PrivateKeyInfo");
     619            RTCRPKCS8ENCRYPTEDPRIVATEKEYINFO EncryptedPrivateKeyInfo;
     620            RT_ZERO(EncryptedPrivateKeyInfo);
     621            rc = RTCrPkcs8EncryptedPrivateKeyInfo_DecodeAsn1(&PrimaryCursor.Cursor, 0, &EncryptedPrivateKeyInfo,
     622                                                             pszErrorTag ? pszErrorTag : "EncryptedPrivateKeyInfo");
    480623            if (RT_SUCCESS(rc))
    481624            {
    482                 /*
    483                  * Load the private key according to it's algorithm.
    484                  * We currently only support RSA (pkcs1-RsaEncryption).
    485                  */
    486                 if (RTAsn1ObjId_CompareWithString(&PrivateKeyInfo.PrivateKeyAlgorithm.Algorithm,
    487                                                   RTCRX509ALGORITHMIDENTIFIERID_RSA) == 0)
    488                     rc = rtCrKeyCreateRsaPrivate(phKey, PrivateKeyInfo.PrivateKey.Asn1Core.uData.pv,
    489                                                  PrivateKeyInfo.PrivateKey.Asn1Core.cb, pErrInfo, pszErrorTag);
    490                 else
    491                     rc = RTErrInfoSet(pErrInfo, VERR_CR_KEY_FORMAT_NOT_SUPPORTED,
    492                                       "Support for PKCS#8 PrivateKeyInfo for non-RSA keys is not yet implemented");
     625                uint8_t *pbDecrypted = NULL;
     626                size_t   cbDecrypted = 0;
     627                size_t   cbDecryptedAlloced = 0;
     628                rc = rtCrKeyDecryptPkcs8Info(&EncryptedPrivateKeyInfo, pszPassword,
     629                                             &pbDecrypted, &cbDecrypted, &cbDecryptedAlloced, pErrInfo);
     630                if (RT_SUCCESS(rc))
     631                {
     632                    rc = rtCrKeyCreateFromPrivateKeyInfo(phKey, &PrimaryCursor, pbDecrypted, cbDecrypted, pErrInfo, pszErrorTag);
     633
     634                    RTMemSaferFree(pbDecrypted, cbDecryptedAlloced);
     635                }
     636                RTCrPkcs8EncryptedPrivateKeyInfo_Delete(&EncryptedPrivateKeyInfo);
    493637            }
    494638            break;
    495639        }
    496 
    497         case kKeyFormat_EncryptedPrivateKeyInfo:
    498             rc = RTErrInfoSet(pErrInfo, VERR_CR_KEY_FORMAT_NOT_SUPPORTED,
    499                               "Support for encrypted PKCS#8 PrivateKeyInfo is not yet implemented");
    500             break;
    501640
    502641        default:
  • trunk/src/VBox/Runtime/common/crypto/pkcs8-template.h

    r100493 r100528  
    5353#undef RTASN1TMPL_INT_NAME
    5454
    55 #if 0
    5655
    5756/*
    5857 * Encrypted private key info
    5958 */
    60 #define RTASN1TMPL_TYPE         RTCRENCRYPTEDPRIVATEKEY
    61 #define RTASN1TMPL_EXT_NAME     RTCrEncryptedPrivateKey
    62 #define RTASN1TMPL_INT_NAME     rtCrEncryptedPrivateKey
     59#define RTASN1TMPL_TYPE         RTCRPKCS8ENCRYPTEDPRIVATEKEYINFO
     60#define RTASN1TMPL_EXT_NAME     RTCrPkcs8EncryptedPrivateKeyInfo
     61#define RTASN1TMPL_INT_NAME     rtCrPkcs8EncryptedPrivateKeyInfo
    6362RTASN1TMPL_BEGIN_SEQCORE();
    6463RTASN1TMPL_MEMBER(              EncryptionAlgorithm,    RTCRX509ALGORITHMIDENTIFIER,    RTCrX509AlgorithmIdentifier);
     
    6968#undef RTASN1TMPL_INT_NAME
    7069
    71 #endif
  • trunk/src/VBox/Runtime/testcase/tstRTCrPkix-1.cpp

    r100421 r100528  
    5858static const struct { unsigned cBits; const char *pszPrivateKey, *pszPublicKey, *pszPassword; } g_aKeyPairs[] =
    5959{
     60#if 0
    6061    {
    6162        4096,
     
    256257        "password"
    257258    },
    258 
     259#endif
    259260    /*
    260261     * PKCS8 Test Keys
     
    285286        "-----END PUBLIC KEY-----\n",
    286287        NULL
    287     }
     288    },
     289    {
     290        2048,
     291        "-----BEGIN ENCRYPTED PRIVATE KEY-----\n"
     292        "MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIRFetWFFFIb4CAggA\n"
     293        "MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBAZMr0Lq1s+olU2jUY8MuQJBIIE\n"
     294        "0ICOZE6GhPCQbUSudbBYTG4zBRGhJOTeGF43c3pqi6UNS4qWK9IQ3B5hm618Iof0\n"
     295        "YUnCDKy9G7TPMwP+8pcybFXuvWo1yeJcVGNalBq/LmUG2RBJ3hh/IikDnzj2jq1u\n"
     296        "QKFTgl5yZ41bC75d81fdg0CpYqIGOjLdQcUJmVk+lKggWcN7KuqPj+9FhCoRyjIp\n"
     297        "UyLYQQ8E0sb7tk0gJoi6VHddTYpLEDiFzGqXP/XWykCFHx977sbRuOymrTF3C3OZ\n"
     298        "X5PSkszydSBzomPl1MnmiMjAmgc3j6EABUpzjaUZ2l2xxeM9r/c076zSpHdcBFus\n"
     299        "Y3pA9Hm9HvV2q+1FHHNk90vZlXWtyTh8tSJvT3WF63kYMyIXXztovldjxX76fxB0\n"
     300        "c5K0E9FH5sjv0R4AfMf4CMsP5InGfy2zICRwi+xvp97lq6nEXjIqiePyNTUA3QAy\n"
     301        "brZtzM67KxFL/TuV6Y20DILAPlWZe3C8KFpFeHEi5yddi0VikzQVl1X/hieCt4SP\n"
     302        "aTdd+MCn3XIu+58RK6UYCVCxbH9j9iZCznOfWLRMpthvoa9SO8M8DTFlx/bptClt\n"
     303        "IKUnsQgBpvT3+xzpJk4sQyD4aZDcDMQeNfDr/1KyYMEjaqvGMqKfLed2HLDHdD9f\n"
     304        "rsg41wTCqp/draUh2qxa7pXkK0KcNbH4hLH//pduaLubHmOPofLvprVIISyOtspN\n"
     305        "tsPtXs43Ta4dOQWLg2Q/lwlo0psi1im/fHKyr7rpMdUa+dRGX8H4tYsFJufHzVjr\n"
     306        "rQrKDHPsNfhy+JuCfQu/8SdZCXwcBxxeSlam5EgtlfsTDC+zIP8dDHaOWsDRm+k3\n"
     307        "ryKTSn84LBQLWzc3RhZteAlzDHcmrS/MmF4yfpgSkFI+aUF5+XPLqoYVsoVKQ5bL\n"
     308        "NnA6xJBkXVtzNZUYH3cHoiAOATlhHRFtoWrKoEQXlCNvvTCiBGoMPfjpnTy3u/kS\n"
     309        "8JaUsJLvDFQBFPSxdYA+w/zb3zy0Nh5s3R9D6IkrH0X2mk8JhABYNzDIDYlS2Ioz\n"
     310        "ARpmwuZwPUG1iSzamYZCt2OVd1acPexiwTATihfPVT2RFbHET9+e7NX/5TFnGP++\n"
     311        "4o6mckiD5c9QmwE29FLTeiqwKvLweLrrF6/1/S45/okibqXHgh7O567y+PSMmjk5\n"
     312        "L0azEmv6UIs5z4FNvDxS5++b3oqUMu+oazQP1aDk0H/8xJaDFrnOKWL9h8waeBn7\n"
     313        "JBuuIFKqRb6S9H0ZPb1R7Z9BVuUil76nc4zr0kLNdJ8dq2l/kcqIIFrtVJX/INaf\n"
     314        "gYvlsIYXpb/IhBZit1GJxwi8kk29b2QSyDW6CNNi3dC8Y1p9jiLejqFM4LQL/HNr\n"
     315        "atc1pUBPePK1ZHJ0OLyVthJYXmn8v+M9eHfptQzBZpILTZZK719uOtHloPrI64LY\n"
     316        "iO00glzBju2W1yDF6cTgmWQEigWno65Is5pjN5ByMf3ouHM8qJFIhTEqCpAY7cQQ\n"
     317        "2k6o7dqAcQm7Q+BvhfsWcPWq/GH/OOkuUDqQaK1YDA+lUj9uyrxm9AlrDtUjezLE\n"
     318        "k3IT6ZiBVrPlKWCMbT6ajm9ti0RuCRnZfrrLn2gu16weRtaNeVyza6D5wn+eKXmE\n"
     319        "5dnugDd6T+QBX/3+WLaXTL3l/tj7i9WwNJU4uqW7y6+P\n"
     320        "-----END ENCRYPTED PRIVATE KEY-----\n",
     321        "-----BEGIN PUBLIC KEY-----\n"
     322        "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp6CMrt0Z/k5+c/7C3oWz\n"
     323        "bLBmE4fttE84EZsrwB/ZDhMBQDsVF/GMePj1e5zrxnVq6GZhcNbcJTqHp0mWb+K5\n"
     324        "HMlAihPKYlswJQtkVgp/czbdXwt3MI+D4ifUiq4v8AMrJHW+AYd0GYKzYma6LGVj\n"
     325        "75Bue450bsLocMKwB03iyFE8SBwzGSj9jwJ9UYBvVUnNsutq6nCPTj1bM6naFIHO\n"
     326        "Y+cozHIrKyvHGHoWBVUqKARlNT3TtbTyGxaT4QyZj8Pm9jB5Np6CrF7nmV936Q3A\n"
     327        "3CHji8BbhfcdZ/9s53wkSwztfpe8NYh1/RiLZtZdky9E6Q67dt3h4bKHsKRFi0xW\n"
     328        "jQIDAQAB\n"
     329        "-----END PUBLIC KEY-----\n",
     330        "password"
     331    },
    288332};
    289333
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette