VirtualBox

Changeset 73749 in vbox for trunk/src


Ignore:
Timestamp:
Aug 18, 2018 12:25:57 AM (6 years ago)
Author:
vboxsync
Message:

IPRT/crypto: Implemented reading of PEM encrypted RSA keys. bugref:9152

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

Legend:

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

    r73665 r73749  
    3232#include <iprt/crypto/key.h>
    3333
     34#include <iprt/alloca.h>
    3435#include <iprt/asm.h>
    3536#include <iprt/assert.h>
     37#include <iprt/ctype.h>
    3638#include <iprt/err.h>
    3739#include <iprt/mem.h>
     
    4547#include "internal/magics.h"
    4648#include "key-internal.h"
     49
     50#ifdef IPRT_WITH_OPENSSL
     51# include "internal/iprt-openssl.h"
     52# include "openssl/evp.h"
     53# ifndef OPENSSL_VERSION_NUMBER
     54#  error "Missing OPENSSL_VERSION_NUMBER!"
     55# endif
     56#endif
    4757
    4858
     
    6979/** RSA private key marker words. */
    7080static RTCRPEMMARKERWORD const g_aWords_RsaPrivateKey[] =
    71 { { RT_STR_TUPLE("RSA") }, { RT_STR_TUPLE("PRIVATE") }, { RT_STR_TUPLE("KEY") } };
     81{ { RT_STR_TUPLE("RSA") },       { RT_STR_TUPLE("PRIVATE") }, { RT_STR_TUPLE("KEY") } };
     82/** Generic encrypted private key marker words. */
     83static RTCRPEMMARKERWORD const g_aWords_EncryptedPrivateKey[] =
     84{ { RT_STR_TUPLE("ENCRYPTED") }, { RT_STR_TUPLE("PRIVATE") }, { RT_STR_TUPLE("KEY") } };
    7285/** Generic private key marker words. */
    7386static RTCRPEMMARKERWORD const g_aWords_PrivateKey[] =
    74 {                          { RT_STR_TUPLE("PRIVATE") }, { RT_STR_TUPLE("KEY") } };
     87{                                { RT_STR_TUPLE("PRIVATE") }, { RT_STR_TUPLE("KEY") } };
    7588
    7689/** Private key markers. */
    7790RT_DECL_DATA_CONST(RTCRPEMMARKER const) g_aRTCrKeyPrivateMarkers[] =
    7891{
    79     { g_aWords_RsaPrivateKey, RT_ELEMENTS(g_aWords_RsaPrivateKey) },
    80     { g_aWords_PrivateKey,    RT_ELEMENTS(g_aWords_PrivateKey) },
     92    { g_aWords_RsaPrivateKey,       RT_ELEMENTS(g_aWords_RsaPrivateKey) },
     93    { g_aWords_EncryptedPrivateKey, RT_ELEMENTS(g_aWords_EncryptedPrivateKey) },
     94    { g_aWords_PrivateKey,          RT_ELEMENTS(g_aWords_PrivateKey) },
    8195};
    8296/** Number of entries in g_aRTCrKeyPrivateMarkers. */
     
    96110
    97111
    98 
    99 RTDECL(int) RTCrKeyCreateFromPemSection(PRTCRKEY phKey, PCRTCRPEMSECTION pSection, uint32_t fFlags,
     112/**
     113 * Decrypts a PEM message.
     114 *
     115 * @returns IPRT status code
     116 * @param   pszDekInfo          The decryption info.  See RFC-1421 section 4.6.1.3
     117 *                              as well as RFC-1423).
     118 * @param   pszPassword         The password to use to decrypt the key text.
     119 * @param   pbEncrypted         The encrypted key text.
     120 * @param   cbEncrypted         The size of the encrypted text.
     121 * @param   ppbDecrypted        Where to return the decrypted message. Free using RTMemSaferFree.
     122 * @param   pcbDecrypted        Where to return the length of the decrypted message.
     123 * @param   pcbDecryptedAlloced Where to return the allocation size.
     124 * @param   pErrInfo            Where to return additional error information.
     125 */
     126static int rtCrKeyDecryptPemMessage(const char *pszDekInfo, const char *pszPassword, uint8_t *pbEncrypted, size_t cbEncrypted,
     127                                    uint8_t **ppbDecrypted, size_t *pcbDecrypted, size_t *pcbDecryptedAlloced, PRTERRINFO pErrInfo)
     128{
     129    /*
     130     * Initialize return values.
     131     */
     132    *ppbDecrypted        = NULL;
     133    *pcbDecrypted        = 0;
     134    *pcbDecryptedAlloced = 0;
     135
     136    /*
     137     * Parse the DEK-Info.
     138     */
     139    if (!pszDekInfo)
     140        return VERR_CR_KEY_NO_DEK_INFO;
     141
     142    /* Find the end of the algorithm */
     143    const char *pszParams = strchr(pszDekInfo, ',');
     144    if (!pszParams)
     145        pszParams = strchr(pszDekInfo, '\0');
     146    size_t cchAlgo = pszParams - pszDekInfo;
     147    while (cchAlgo > 0 && RT_C_IS_SPACE(pszDekInfo[cchAlgo - 1]))
     148        cchAlgo--;
     149
     150    /* Copy it out and zero terminating it. */
     151    char szAlgo[256];
     152    if (cchAlgo >= sizeof(szAlgo))
     153        return RTErrInfoSetF(pErrInfo, VERR_CR_KEY_DEK_INFO_TOO_LONG, "Algorithms list is too long (%s)", pszDekInfo);
     154    memcpy(szAlgo, pszDekInfo, cchAlgo);
     155    szAlgo[cchAlgo] = '\0';
     156
     157    /* Parameters. */
     158    pszParams = RTStrStripL(*pszParams == ',' ? pszParams + 1 : pszParams);
     159    size_t const cchParams = strlen(pszParams);
     160
     161    /*
     162     * Do we support the cihper?
     163     */
     164#ifdef IPRT_WITH_OPENSSL /** @todo abstract encryption & decryption. */
     165    const EVP_CIPHER *pCipher = EVP_get_cipherbyname(szAlgo);
     166    if (!pCipher)
     167        return RTErrInfoSetF(pErrInfo, VERR_CR_KEY_UNSUPPORTED_CIPHER, "Unknown key cipher: %s (params: %s)", szAlgo, pszParams);
     168
     169    /* Decode the initialization vector if one is required. */
     170    uint8_t *pbInitVector = NULL;
     171    int const cbInitVector = EVP_CIPHER_iv_length(pCipher);
     172    if (cbInitVector > 0)
     173    {
     174        if (*pszParams == '\0')
     175            return RTErrInfoSetF(pErrInfo, VERR_CR_KEY_MISSING_CIPHER_PARAMS,
     176                                 "Cipher '%s' expected %u bytes initialization vector, none found", cbInitVector, szAlgo);
     177        if ((size_t)cbInitVector > cchParams / 2)
     178            return RTErrInfoSetF(pErrInfo, VERR_CR_KEY_TOO_SHORT_CIPHER_IV,
     179                                 "Too short initialization vector for '%s', expected %u chars found only %u: %s",
     180                                 szAlgo, cbInitVector * 2, cchParams, pszParams);
     181        pbInitVector = (uint8_t *)alloca(cbInitVector);
     182        int rc = RTStrConvertHexBytes(pszParams, pbInitVector, cbInitVector, 0 /*fFlags*/);
     183        if (   RT_FAILURE(rc)
     184            && rc != VERR_BUFFER_OVERFLOW /* openssl ignores this condition */)
     185            return RTErrInfoSetF(pErrInfo, VERR_CR_KEY_MALFORMED_CIPHER_IV,
     186                                 "Malformed initialization vector for '%s': %s (rc=%Rrc)", szAlgo, pszParams, rc);
     187    }
     188    else if (*pszParams != '\0')
     189        return RTErrInfoSetF(pErrInfo, VERR_CR_KEY_UNEXPECTED_CIPHER_PARAMS,
     190                             "Cipher '%s' expected no parameters, found: %s", szAlgo, pszParams);
     191
     192    /*
     193     * Do we have a password?  If so try decrypt the key.
     194     */
     195    if (!pszPassword)
     196        return VERR_CR_KEY_ENCRYPTED;
     197
     198    unsigned char abKey[EVP_MAX_KEY_LENGTH * 2];
     199    int cbKey = EVP_BytesToKey(pCipher, EVP_md5(), pbInitVector, (unsigned char const *)pszPassword, (int)strlen(pszPassword),
     200                               1, abKey, NULL);
     201    if (!cbKey)
     202        return RTErrInfoSetF(pErrInfo, VERR_CR_KEY_PASSWORD_ENCODING, "EVP_BytesToKey failed to encode password");
     203
     204    EVP_CIPHER_CTX *pCipherCtx = EVP_CIPHER_CTX_new();
     205    if (!pCipherCtx)
     206        return VERR_NO_MEMORY;
     207
     208    int rc;
     209    if (EVP_DecryptInit_ex(pCipherCtx, pCipher, NULL /*pEngine*/, abKey, pbInitVector))
     210    {
     211        size_t   cbDecryptedAlloced = cbEncrypted;
     212        int      cbDecrypted = (int)cbDecryptedAlloced;
     213        uint8_t *pbDecrypted = (uint8_t *)RTMemSaferAllocZ(cbDecryptedAlloced);
     214        if (pbDecrypted)
     215        {
     216            if (EVP_DecryptUpdate(pCipherCtx, pbDecrypted, &cbDecrypted, pbEncrypted, (int)cbEncrypted))
     217            {
     218                int cbFinal = (int)cbDecryptedAlloced - cbDecrypted;
     219                if (EVP_DecryptFinal_ex(pCipherCtx, &pbDecrypted[cbDecrypted], &cbFinal))
     220                {
     221                    cbDecrypted += cbFinal;
     222                    Assert((size_t)cbDecrypted <= cbDecryptedAlloced);
     223
     224                    /*
     225                     * Done! Just set the return values.
     226                     */
     227                    *pcbDecrypted        = cbDecrypted;
     228                    *pcbDecryptedAlloced = cbDecryptedAlloced;
     229                    *ppbDecrypted        = pbDecrypted;
     230                    pbDecrypted = NULL;
     231                    rc = VINF_CR_KEY_WAS_DECRYPTED;
     232                }
     233                else
     234                    rc = RTErrInfoSetF(pErrInfo, VERR_CR_KEY_DECRYPTION_FAILED,
     235                                       "Incorrect password? EVP_DecryptFinal_ex failed for %s", pszDekInfo);
     236            }
     237            else
     238                rc = RTErrInfoSetF(pErrInfo, VERR_CR_KEY_DECRYPTION_FAILED,
     239                                   "Incorrect password? EVP_DecryptUpdate failed for %s", pszDekInfo);
     240            if (pbDecrypted)
     241                RTMemSaferFree(pbDecrypted, cbDecryptedAlloced);
     242        }
     243        else
     244            rc = VERR_NO_MEMORY;
     245    }
     246    else
     247        rc = RTErrInfoSetF(pErrInfo, VERR_CR_KEY_OSSL_DECRYPT_INIT_ERROR, "EVP_DecryptInit_ex failed for %s", pszDekInfo);
     248    EVP_CIPHER_CTX_free(pCipherCtx);
     249    return rc;
     250#else
     251    RT_NOREF(pbEncrypted, cbEncrypted, pszPassword, pErrInfo, cchParams);
     252    return VERR_CR_KEY_DECRYPTION_NOT_SUPPORTED;
     253#endif
     254}
     255
     256
     257RTDECL(int) RTCrKeyCreateFromPemSection(PRTCRKEY phKey, PCRTCRPEMSECTION pSection, uint32_t fFlags, const char *pszPassword,
    100258                                        PRTERRINFO pErrInfo, const char *pszErrorTag)
    101259{
     
    105263    *phKey = NIL_RTCRKEY;
    106264    AssertPtrReturn(pSection, VERR_INVALID_POINTER);
     265    NOREF(pszPassword);
    107266
    108267    /*
     
    113272        kKeyFormat_Unknown = 0,
    114273        kKeyFormat_RsaPrivateKey,
     274        kKeyFormat_RsaEncryptedPrivateKey,
    115275        kKeyFormat_RsaPublicKey,
     276        kKeyFormat_SubjectPublicKeyInfo,
    116277        kKeyFormat_PrivateKeyInfo,
    117         kKeyFormat_SubjectPublicKeyInfo
     278        kKeyFormat_EncryptedPrivateKeyInfo
    118279    }               enmFormat     = kKeyFormat_Unknown;
     280    const char     *pszDekInfo    = NULL;
    119281    PCRTCRPEMMARKER pMarker       = pSection->pMarker;
    120282    if (pMarker)
     
    127289                enmFormat  = kKeyFormat_RsaPublicKey;
    128290            else if (strcmp(pMarker->paWords[1].pszWord, "PRIVATE") == 0)
    129                 enmFormat  = kKeyFormat_RsaPrivateKey;
     291            {
     292                enmFormat = kKeyFormat_RsaPrivateKey;
     293
     294                /* RSA PRIVATE KEY encryption is advertised thru PEM header fields.
     295                   We need the DEK field to decrypt the message (see RFC-1421 4.6.1.3). */
     296                for (PCRTCRPEMFIELD pField = pSection->pFieldHead; pField; pField = pField->pNext)
     297                {
     298                    if (   pField->cchName == sizeof("Proc-Type") - 1
     299                        && pField->cchValue >= sizeof("4,ENCRYPTED") - 1
     300                        && memcmp(pField->szName, RT_STR_TUPLE("Proc-Type")) == 0)
     301                    {
     302                        const char *pszValue = pField->pszValue;
     303                        if (*pszValue == '4')
     304                        {
     305                            do
     306                                pszValue++;
     307                            while (RT_C_IS_SPACE(*pszValue) || RT_C_IS_PUNCT(*pszValue));
     308                            if (strcmp(pszValue, "ENCRYPTED") == 0)
     309                                enmFormat  = kKeyFormat_RsaEncryptedPrivateKey;
     310                        }
     311                    }
     312                    else if (   pField->cchName == sizeof("DEK-Info") - 1
     313                             && pField->cchValue > 0
     314                             && !pszDekInfo)
     315                        pszDekInfo = pField->pszValue;
     316                }
     317            }
    130318            else
    131319                AssertFailed();
     
    141329                AssertFailed();
    142330        }
     331        else if (   pMarker->cWords == 3
     332                 && strcmp(pMarker->paWords[0].pszWord, "ENCRYPTED") == 0
     333                 && strcmp(pMarker->paWords[1].pszWord, "PRIVATE") == 0
     334                 && strcmp(pMarker->paWords[2].pszWord, "KEY") == 0)
     335            enmFormat = kKeyFormat_EncryptedPrivateKeyInfo;
    143336        else
    144337            AssertFailed();
     
    224417    switch (enmFormat)
    225418    {
     419        case kKeyFormat_RsaPublicKey:
     420            rc = rtCrKeyCreateRsaPublic(phKey, pSection->pbData, (uint32_t)pSection->cbData, pErrInfo, pszErrorTag);
     421            break;
     422
    226423        case kKeyFormat_RsaPrivateKey:
    227424            rc = rtCrKeyCreateRsaPrivate(phKey, pSection->pbData, (uint32_t)pSection->cbData, pErrInfo, pszErrorTag);
    228425            break;
    229426
    230         case kKeyFormat_RsaPublicKey:
    231             rc = rtCrKeyCreateRsaPrivate(phKey, pSection->pbData, (uint32_t)pSection->cbData, pErrInfo, pszErrorTag);
     427        case kKeyFormat_RsaEncryptedPrivateKey:
     428        {
     429            uint8_t *pbDecrypted = NULL;
     430            size_t   cbDecrypted = 0;
     431            size_t   cbDecryptedAlloced = 0;
     432            rc = rtCrKeyDecryptPemMessage(pszDekInfo, pszPassword, pSection->pbData, pSection->cbData,
     433                                          &pbDecrypted, &cbDecrypted, &cbDecryptedAlloced, pErrInfo);
     434            if (RT_SUCCESS(rc))
     435            {
     436                int rc2 = rtCrKeyCreateRsaPrivate(phKey, pbDecrypted, (uint32_t)cbDecrypted, pErrInfo, pszErrorTag);
     437                if (rc2 != VINF_SUCCESS)
     438                    rc = rc2;
     439                RTMemSaferFree(pbDecrypted, cbDecryptedAlloced);
     440            }
    232441            break;
     442        }
    233443
    234444        case kKeyFormat_SubjectPublicKeyInfo:
     
    252462            break;
    253463
     464        case kKeyFormat_EncryptedPrivateKeyInfo:
     465            rc = RTErrInfoSet(pErrInfo, VERR_CR_KEY_FORMAT_NOT_SUPPORTED,
     466                              "Support for encrypted PKCS#8 PrivateKeyInfo is not yet implemented");
     467            break;
     468
    254469        default:
    255470            AssertFailedStmt(rc = VERR_INTERNAL_ERROR_4);
     
    259474
    260475
    261 RTDECL(int) RTCrKeyCreateFromBuffer(PRTCRKEY phKey, uint32_t fFlags, void const *pvSrc, size_t cbSrc,
     476RTDECL(int) RTCrKeyCreateFromBuffer(PRTCRKEY phKey, uint32_t fFlags, void const *pvSrc, size_t cbSrc, const char *pszPassword,
    262477                                    PRTERRINFO pErrInfo, const char *pszErrorTag)
    263478{
     
    269484        if (pSectionHead)
    270485        {
    271             rc = RTCrKeyCreateFromPemSection(phKey, pSectionHead, fFlags  & ~RTCRKEYFROM_F_ONLY_PEM, pErrInfo, pszErrorTag);
     486            rc = RTCrKeyCreateFromPemSection(phKey, pSectionHead, fFlags  & ~RTCRKEYFROM_F_ONLY_PEM, pszPassword,
     487                                             pErrInfo, pszErrorTag);
    272488            RTCrPemFreeSections(pSectionHead);
    273489        }
     
    279495
    280496
    281 RTDECL(int) RTCrKeyCreateFromFile(PRTCRKEY phKey, uint32_t fFlags, const char *pszFilename, PRTERRINFO pErrInfo)
     497RTDECL(int) RTCrKeyCreateFromFile(PRTCRKEY phKey, uint32_t fFlags, const char *pszFilename,
     498                                  const char *pszPassword, PRTERRINFO pErrInfo)
    282499{
    283500    AssertReturn(!(fFlags & ~RTCRKEYFROM_F_VALID_MASK), VERR_INVALID_FLAGS);
     
    288505        if (pSectionHead)
    289506        {
    290             rc = RTCrKeyCreateFromPemSection(phKey, pSectionHead, fFlags & ~RTCRKEYFROM_F_ONLY_PEM,
     507            rc = RTCrKeyCreateFromPemSection(phKey, pSectionHead, fFlags & ~RTCRKEYFROM_F_ONLY_PEM, pszPassword,
    291508                                             pErrInfo, RTPathFilename(pszFilename));
    292509            RTCrPemFreeSections(pSectionHead);
  • trunk/src/VBox/Runtime/common/crypto/pemfile.cpp

    r73644 r73749  
    22/** @file
    33 * IPRT - Crypto - PEM file reader / writer.
     4 *
     5 * See RFC-1341 for the original ideas for the format, but keep in mind
     6 * that the format was hijacked and put to different uses.  We're aiming at
     7 * dealing with the different uses rather than anything email related here.
    48 */
    59
     
    3236#include <iprt/crypto/pem.h>
    3337
     38#include <iprt/asm.h>
    3439#include <iprt/base64.h>
    3540#include <iprt/ctype.h>
    3641#include <iprt/err.h>
    3742#include <iprt/mem.h>
     43#include <iprt/memsafer.h>
    3844#include <iprt/file.h>
    3945#include <iprt/string.h>
     
    4450 * Looks for a PEM-like marker.
    4551 *
    46  * @returns true if found, fasle if not.
     52 * @returns true if found, false if not.
    4753 * @param   pbContent           Start of the content to search thru.
    4854 * @param   cbContent           The size of the content to search.
     
    220226
    221227
     228/**
     229 * Parses any fields the message may contain.
     230 *
     231 * @retval  VINF_SUCCESS
     232 * @retval  VERR_NO_MEMORY
     233 * @retval  VERR_CR_MALFORMED_PEM_HEADER
     234 *
     235 * @param   pSection        The current section, where we will attach a list of
     236 *                          fields to the pFieldHead member.
     237 * @param   pbContent       The content of the PEM message being parsed.
     238 * @param   cbContent       The length of the PEM message.
     239 * @param   pcbFields       Where to return the length of the header fields we found.
     240 */
     241static int rtCrPemProcessFields(PRTCRPEMSECTION pSection, uint8_t const *pbContent, size_t cbContent, size_t *pcbFields)
     242{
     243    uint8_t const * const pbContentStart = pbContent;
     244
     245    /*
     246     * Work the encapulated header protion field by field.
     247     *
     248     * This is optional, so currently we don't throw errors here but leave that
     249     * to when we work the text portion with the base64 decoder.  Also, as a reader
     250     * we don't go all pedanic on confirming to specification (RFC-1421), especially
     251     * given that it's used for crypto certificates, keys and the like not email. :-)
     252     */
     253    PCRTCRPEMFIELD *ppNext = &pSection->pFieldHead;
     254    while (cbContent > 0)
     255    {
     256        /* Just look for a colon first. */
     257        const uint8_t *pbColon = (const uint8_t *)memchr(pbContent, ':', cbContent);
     258        if (!pbColon)
     259            break;
     260        size_t offColon = pbColon - pbContent;
     261
     262        /* Check that the colon is within the first line. */
     263        if (!memchr(pbContent, '\n', cbContent - offColon))
     264            return VERR_CR_MALFORMED_PEM_HEADER;
     265
     266        /* Skip leading spaces (there shouldn't be any, but just in case). */
     267        while (RT_C_IS_BLANK(*pbContent) && /*paranoia:*/ offColon > 0)
     268        {
     269            offColon--;
     270            cbContent--;
     271            pbContent++;
     272        }
     273
     274        /* There shouldn't be any spaces before the colon, but just in case */
     275        size_t cchName = offColon;
     276        while (cchName > 0 && RT_C_IS_BLANK(pbContent[cchName - 1]))
     277            cchName--;
     278
     279        /* Skip leading value spaces (there typically is at least one). */
     280        size_t offValue = offColon + 1;
     281        while (offValue < cbContent && RT_C_IS_BLANK(pbContent[offValue]))
     282            offValue++;
     283
     284        /* Find the newline the field value ends with and where the next iteration should start later on. */
     285        size_t         cbLeft;
     286        uint8_t const *pbNext = (uint8_t const *)memchr(&pbContent[offValue], '\n', cbContent - offValue);
     287        while (   pbNext
     288               && (cbLeft = pbNext - pbContent) < cbContent
     289               && RT_C_IS_BLANK(pbNext[1]) /* next line must start with a space or tab */)
     290            pbNext = (uint8_t const *)memchr(&pbNext[1], '\n', cbLeft - 1);
     291
     292        size_t cchValue;
     293        if (pbNext)
     294        {
     295            cchValue = pbNext - &pbContent[offValue];
     296            if (cchValue > 0 && pbNext[-1] == '\r')
     297                cchValue--;
     298            pbNext++;
     299        }
     300        else
     301        {
     302            cchValue = cbContent - offValue;
     303            pbNext = &pbContent[cbContent];
     304        }
     305
     306        /* Strip trailing spaces. */
     307        while (cchValue > 0 && RT_C_IS_BLANK(pbContent[offValue + cchValue - 1]))
     308            cchValue--;
     309
     310        /*
     311         * Allocate a field instance.
     312         *
     313         * Note! We don't consider field data sensitive at the moment.  This
     314         *       mainly because the fields are chiefly used to indicate the
     315         *       encryption parameters to the body.
     316         */
     317        PRTCRPEMFIELD pNewField = (PRTCRPEMFIELD)RTMemAllocZVar(sizeof(*pNewField) + cchName + 1 + cchValue + 1);
     318        if (!pNewField)
     319            return VERR_NO_MEMORY;
     320        pNewField->cchName         = cchName;
     321        pNewField->cchValue        = cchValue;
     322        memcpy(pNewField->szName, pbContent, cchName);
     323        pNewField->szName[cchName] = '\0';
     324        char *pszDst = (char *)memcpy(&pNewField->szName[cchName + 1], &pbContent[offValue], cchValue);
     325        pNewField->pszValue        = pszDst;
     326        pszDst[cchValue]           = '\0';
     327        pNewField->pNext           = NULL;
     328
     329        *ppNext = pNewField;
     330        ppNext = &pNewField->pNext;
     331
     332        /*
     333         * Advance past the field.
     334         */
     335        cbContent -= pbNext - pbContent;
     336        pbContent  = pbNext;
     337    }
     338
     339    /*
     340     * Skip blank line(s) before the body.
     341     */
     342    while (cbContent >= 1)
     343    {
     344        size_t cbSkip;
     345        if (pbContent[0] == '\n')
     346            cbSkip = 1;
     347        else if (   pbContent[0] == '\r'
     348                 && cbContent >= 2
     349                 && pbContent[1] == '\n')
     350            cbSkip = 2;
     351        else
     352            break;
     353        pbContent += cbSkip;
     354        cbContent -= cbSkip;
     355    }
     356
     357    *pcbFields = pbContent - pbContentStart;
     358    return VINF_SUCCESS;
     359}
     360
    222361
    223362/**
     
    227366 * @param   pbContent           The start of the PEM-like content (text).
    228367 * @param   cbContent           The max size of the PEM-like content.
     368 * @param   fSensitive          Set if the safer allocator should be used.
    229369 * @param   ppvDecoded          Where to return a heap block containing the
    230370 *                              decoded content.
    231371 * @param   pcbDecoded          Where to return the size of the decoded content.
    232372 */
    233 static int rtCrPemDecodeBase64(uint8_t const *pbContent, size_t cbContent, void **ppvDecoded, size_t *pcbDecoded)
     373static int rtCrPemDecodeBase64(uint8_t const *pbContent, size_t cbContent, bool fSensitive,
     374                               void **ppvDecoded, size_t *pcbDecoded)
    234375{
    235376    ssize_t cbDecoded = RTBase64DecodedSizeEx((const char *)pbContent, cbContent, NULL);
     
    238379
    239380    *pcbDecoded = cbDecoded;
    240     void *pvDecoded = RTMemAlloc(cbDecoded);
     381    void *pvDecoded = !fSensitive ? RTMemAlloc(cbDecoded) : RTMemSaferAllocZ(cbDecoded);
    241382    if (!pvDecoded)
    242383        return VERR_NO_MEMORY;
     
    251392            return VINF_SUCCESS;
    252393        }
     394
    253395        rc = VERR_INTERNAL_ERROR_3;
    254396    }
    255     RTMemFree(pvDecoded);
     397    if (!fSensitive)
     398        RTMemFree(pvDecoded);
     399    else
     400        RTMemSaferFree(pvDecoded, cbDecoded);
    256401    return rc;
    257402}
     
    310455        PRTCRPEMSECTION pFree = (PRTCRPEMSECTION)pSectionHead;
    311456        pSectionHead = pSectionHead->pNext;
    312 
    313         Assert(pFree->pMarker || !pFree->pszPreamble);
     457        ASMCompilerBarrier(); /* paranoia */
    314458
    315459        if (pFree->pbData)
    316460        {
    317             RTMemFree(pFree->pbData);
     461            if (!pFree->fSensitive)
     462                RTMemFree(pFree->pbData);
     463            else
     464                RTMemSaferFree(pFree->pbData, pFree->cbData);
    318465            pFree->pbData = NULL;
    319466            pFree->cbData = 0;
    320467        }
    321468
    322         if (pFree->pszPreamble)
    323         {
    324             RTMemFree(pFree->pszPreamble);
    325             pFree->pszPreamble = NULL;
    326             pFree->cchPreamble = 0;
    327         }
     469        PRTCRPEMFIELD pField = (PRTCRPEMFIELD)pFree->pFieldHead;
     470        if (pField)
     471        {
     472            pFree->pFieldHead = NULL;
     473            do
     474            {
     475                PRTCRPEMFIELD pFreeField = pField;
     476                pField = (PRTCRPEMFIELD)pField->pNext;
     477                ASMCompilerBarrier(); /* paranoia */
     478
     479                pFreeField->pszValue = NULL;
     480                RTMemFree(pFreeField);
     481            } while (pField);
     482        }
     483
    328484        RTMemFree(pFree);
    329485    }
     
    355511    if (pSection)
    356512    {
     513        bool const fSensitive = RT_BOOL(fFlags & RTCRPEMREADFILE_F_SENSITIVE);
     514
    357515        /*
    358516         * Try locate the first section.
     
    372530                //pSection->pbData      = NULL;
    373531                //pSection->cbData      = 0;
    374                 //pSection->pszPreamble = NULL;
    375                 //pSection->cchPreamble = 0;
     532                //pSection->pFieldHead = NULL;
     533                pSection->fSensitive    = fSensitive;
    376534
    377535                *ppNext = pSection;
    378536                ppNext = &pSection->pNext;
    379537
    380                 /* Decode the section. */
    381                 /** @todo copy the preamble as well. */
    382                 int rc2 = rtCrPemDecodeBase64(pbContent + offBegin, offEnd - offBegin,
     538                /*
     539                 * Decode the section.
     540                 */
     541                size_t cbFields = 0;
     542                int rc2 = rtCrPemProcessFields(pSection, pbContent + offBegin, offEnd - offBegin, &cbFields);
     543                offBegin += cbFields;
     544                if (RT_SUCCESS(rc2))
     545                    rc2 = rtCrPemDecodeBase64(pbContent + offBegin, offEnd - offBegin, fSensitive,
    383546                                              (void **)&pSection->pbData, &pSection->cbData);
    384547                if (RT_FAILURE(rc2))
     
    396559                }
    397560
    398                 /* More sections? */
     561                /*
     562                 * More sections?
     563                 */
    399564                if (   offResume + 12 >= cbContent
    400565                    || offResume      >= cbContent
     
    425590                //pSection->pNext       = NULL;
    426591                //pSection->pMarker     = NULL;
    427                 pSection->pbData        = (uint8_t *)RTMemDup(pbContent, cbContent);
     592                //pSection->pFieldHead  = NULL;
    428593                pSection->cbData        = cbContent;
    429                 //pSection->pszPreamble = NULL;
    430                 //pSection->cchPreamble = 0;
     594                pSection->fSensitive    = fSensitive;
     595                if (!fSensitive)
     596                    pSection->pbData    = (uint8_t *)RTMemDup(pbContent, cbContent);
     597                else
     598                {
     599                    pSection->pbData    = (uint8_t *)RTMemSaferAllocZ(cbContent);
     600                    if (pSection->pbData)
     601                        memcpy(pSection->pbData, pbContent, cbContent);
     602                }
    431603                if (pSection->pbData)
    432604                {
     
    461633    {
    462634        rc = RTCrPemParseContent(pvContent, cbContent, fFlags, paMarkers, cMarkers, ppSectionHead, pErrInfo);
     635        if (fFlags & RTCRPEMREADFILE_F_SENSITIVE)
     636            RTMemWipeThoroughly(pvContent, cbContent, 3);
    463637        RTFileReadAllFree(pvContent, cbContent);
    464638    }
  • trunk/src/VBox/Runtime/testcase/tstRTCrPkix-1.cpp

    r73679 r73749  
    4545 * Key pairs to use when testing.
    4646 */
    47 static const struct { unsigned cBits; const char *pszPrivateKey, *pszPublicKey; } g_aKeyPairs[] =
     47static const struct { unsigned cBits; const char *pszPrivateKey, *pszPublicKey, *pszPassword; } g_aKeyPairs[] =
    4848{
    4949    {
     
    113113        "l93DTgQaXwX/ZjXmwjXvQ0W4OxxexqyW6YvDBYeNKxstuM5qfgzYf7FD/8lZYkyM\n"
    114114        "AXELgpCqC92xlTbWpRVNpXcCAwEAAQ==\n"
    115         "-----END PUBLIC KEY-----\n"
     115        "-----END PUBLIC KEY-----\n",
     116        NULL
    116117    },
    117118    {
     
    152153        "RNsEv/qoK+g/h+b2C0sVO7eUyM6nx9VT8w+ODunnYWs1HiAGAhzj7NhsnJp0gm88\n"
    153154        "KwIDAQAB\n"
    154         "-----END PUBLIC KEY-----\n"
     155        "-----END PUBLIC KEY-----\n",
     156        NULL
    155157    },
    156158    {
     
    176178        "jljAj3vfF9HpyyKOBgLwY1Plfwj3bNPUomGZ+sgigNYWJ4+lXlSxJ7UlTQuQd7Pi\n"
    177179        "RsgCEIRny+5thH/rSwIDAQAB\n"
    178         "-----END PUBLIC KEY-----\n"
     180        "-----END PUBLIC KEY-----\n",
     181        NULL
    179182    },
    180183    {
     
    192195        "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMgbhgcN8LxMNpEZgOC3hgI61pAwSxn4\n"
    193196        "X8rSBHyTt7pfqbU0g2TkPsNT7J6YS2xN+MwKiYNDeCTjRRbt67o1ZscCAwEAAQ==\n"
    194         "-----END PUBLIC KEY-----\n"
     197        "-----END PUBLIC KEY-----\n",
     198        NULL
     199    },
     200
     201    /*
     202     * Keys with passwords.
     203     */
     204    {
     205        2048,
     206        "-----BEGIN RSA PRIVATE KEY-----\n"
     207        "Proc-Type: 4,ENCRYPTED\n"
     208        "DEK-Info: AES-128-CBC,86B32E02F476832DE26291AEF884BFB2\n"
     209        "\n"
     210        "3vqVAOubNaajTSUj/t0ueXRG11kVOCbQkj6AoB4bO+xYUabtcisM4I34It6GN1ZJ\n"
     211        "yXv2DcCE3At31LvvqS8bYGvRhY+oPpCUkC4DX+RX9Tkw5ivl1F9pv/rL3nv2F3LX\n"
     212        "KxMUcygwJOG2ItPu+vLI0HDYGn9reR+6boriwQfU6S8An4C6LrIZK0hUN0Bpr6W+\n"
     213        "JyTX9B3Tgy/BldW6yziRzYUZHnnKEKKacvHP5l0n/6nn6iFSJSFmnzvsedwOvUI0\n"
     214        "eHQ1LvbfQnd5yIalQ5S8UkgpKb5S4s2U0AthAC67m+Nc0E8NcbCMY1JT4FlsWVLD\n"
     215        "GqWmjKhwEBgoPRROEiq39KgPnoxnCEIOiQ6l8kZ0uvqlCHhWM4b1UVqb6hyrmY32\n"
     216        "SEBiwRqFewVYzPFI1+vT3CH/BJcXCBISNj2c4OZDqhmgncGWpLwqU1GIlLp82o3l\n"
     217        "t58WfNuqUM7bc/T6cIKAI2JoR2R96Zo0cgL+419msVUdZXhM/10K3W+wbHUVuSqh\n"
     218        "iDOCJhXWIhu47kjbCOh7OvpOtOPayWBLQiGh1Q4+WQU6t6Vdr/i71dKP0/P/QHwk\n"
     219        "ELNaWv/RLbE6PqKuXcjtoIqzynTvS/6C7PLEKEX3PB6kZNV+m7C0Dxu4BFj04vtx\n"
     220        "5CL71sGaB1ETYUdMRSvCa+f/1zwUXngmozUL+D4PkCz/vT5FYKElWt7RBMt8N+rC\n"
     221        "Iga+YqqvnuSPrxGXLCGZBuI2V+0BwG1pUHwk/C3uo/ggacj9+E/Oiei725cEI7H5\n"
     222        "FnJdFrubYsoGtyII4H1MJzp768s+bD5Bs9m/6a1m+HtzwjxNt329MyAW4DixNGEp\n"
     223        "T1e1e6DMnYU8XlxHkRu3IkgWjY3GPw+mfnxT5ThM16w3XC5bvRPMbIukJxFE3yDL\n"
     224        "jsUeVhA9NHBZbrFIjLwBWoxqlmgZjJrMFE8pcdFbNl2nKvOK0DHw6Tc93Qz0pg4q\n"
     225        "tvt51k9FR4WNmUY8uElmkhepAAAyzcGAHqxvrzkBmXOh76i5+j32swmmaTdx35I2\n"
     226        "GdRPAl75JEKZVKgHZOW6f/eCWdY7z0GAOnn+fkEzxAufU+DQAOuNkgVKySTyov5J\n"
     227        "v3aaMBuyrxyhgqt+k7PahlRE00S84+QvEgeiTmP/Beyd2GHwKiQ0G/9mwkVjSB1Y\n"
     228        "rFw0pzzud1JcYy3uFKZB+YHrV4YbfUHmJR0CKCqHUD2R95rNBIcS5ZpMm1Ak0d5E\n"
     229        "jAQsYlGIbWGx6aNmmf7NWacRpwVPnViU30cumeQxbCLQ2Mfb9N2zuwgplOSNp/2m\n"
     230        "KRU7jRs3ZLD21iplVBbmmvpC8HyJ7605bDWBw+eVaS92sEmA5lnD3uRil+7/tM8C\n"
     231        "rXrnU8h7vFBSWxcVM1kEiocE8eetSMczI7uA36KWbAWcMlG6hCyQSLuGkxGSZpaM\n"
     232        "Ro+IJx/vHNvnVj2ObqHCmSIE0+VkeyV3SlF2MqrdHNss/iOUBYFsE9zVN/oQcibt\n"
     233        "dXMXRN81KyHg8keNiwdd18ZWVW2+lix1mbPPgwd5iptnT4Qyder5HJroV52LdRZc\n"
     234        "nf3XjVzVp7tTGjGi9T/FvkpQR4tkU+Sl17qDrw9H/Y7k1j90zWFn8kykpwSRt0bV\n"
     235        "-----END RSA PRIVATE KEY-----\n",
     236        "-----BEGIN PUBLIC KEY-----\n"
     237        "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvvqfSDO1HN3Els04TSGE\n"
     238        "sJ0Himl934+ryfNXYIRWkq91i5+rENyZ475XBMjg8fblhvHy7vy4GfUo0PKVXxWS\n"
     239        "nPqOPSLEP3r2vsCX5l+KRBnGi4TeGWDTB8R6oA6HKY5ybtzUr1MHKwa7K7YJu7M9\n"
     240        "DW7n2JPLRajUMioO9wbYK70qlbxjeOu0V62D68fWoa3alSWMlMBv9KZW9g2oJHQy\n"
     241        "mUO2OdJFdyaah3z6vTKtzxmZ+NB4iwIjD6Go1CMj+FOjjjJb3EgUOIZAsRz/+9MF\n"
     242        "S3cRfh/8u9cZQ20Woh5vmw1anXxbwk6Z8uIFYrdgcY5G7ak0/3VukbP7VzvG+voY\n"
     243        "AwIDAQAB\n"
     244        "-----END PUBLIC KEY-----\n",
     245        "password"
    195246    }
    196247};
     
    217268         */
    218269        rc = RTCrKeyCreateFromBuffer(&hPublicKey, 0, g_aKeyPairs[i].pszPublicKey, strlen(g_aKeyPairs[i].pszPublicKey),
    219                                      NULL /*pErrInfo*/, NULL /*pszErrorTag*/);
     270                                     NULL /*pszPassword*/, NULL /*pErrInfo*/, NULL /*pszErrorTag*/);
    220271        if (RT_FAILURE(rc))
    221272            RTTestIFailed("Error %Rrc decoding public key #%u (%u bits)", rc, i, g_aKeyPairs[i].cBits);
    222273
    223274        rc = RTCrKeyCreateFromBuffer(&hPrivateKey, 0, g_aKeyPairs[i].pszPrivateKey, strlen(g_aKeyPairs[i].pszPrivateKey),
    224                                      NULL /*pErrInfo*/, NULL /*pszErrorTag*/);
     275                                     g_aKeyPairs[i].pszPassword, NULL /*pErrInfo*/, NULL /*pszErrorTag*/);
    225276        if (RT_FAILURE(rc))
    226277            RTTestIFailed("Error %Rrc decoding private key #%u (%u bits)", rc, i, g_aKeyPairs[i].cBits);
     
    228279        if (hPrivateKey == NIL_RTCRKEY || hPublicKey == NIL_RTCRKEY)
    229280            continue;
     281
     282        /*
     283         * If we've got a password encrypted key, try some incorrect password.
     284         */
     285        if (g_aKeyPairs[i].pszPassword)
     286        {
     287            static const char * const s_apszBadPassword[] =
     288            {
     289                "bad-password", "", "<>", "really really long long long bad bad bad bad bad password password password password",
     290                "a", "ab", "abc", "abcd", "abcde", "fdcba"
     291            };
     292            for (unsigned iPasswd = 0; iPasswd < RT_ELEMENTS(s_apszBadPassword); iPasswd++)
     293            {
     294                RTCRKEY hKey = NIL_RTCRKEY;
     295                rc = RTCrKeyCreateFromBuffer(&hKey, 0, g_aKeyPairs[i].pszPrivateKey, strlen(g_aKeyPairs[i].pszPrivateKey),
     296                                             s_apszBadPassword[iPasswd], NULL /*pErrInfo*/, NULL /*pszErrorTag*/);
     297                if (rc != VERR_CR_KEY_DECRYPTION_FAILED)
     298                    RTTestIFailed("Unexpected bad password response %Rrc decoding private key #%u (%u bits) using '%s' as password",
     299                                  rc, i, g_aKeyPairs[i].cBits, s_apszBadPassword[iPasswd]);
     300            }
     301        }
    230302
    231303        /*
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