VirtualBox

Ignore:
Timestamp:
May 21, 2024 12:52:09 PM (8 months ago)
Author:
vboxsync
Message:

IPRT,Main: Reworked the newly introduced RTCrX509Certificate_Generate function. It's now called RTCrX509Certificate_GenerateSelfSignedRsa and takes a few more parameters. We still can't read the output it creates. Added a create-self-signed-rsa-cert command to RTSignTool for easy testing. bugref:10310

Location:
trunk/src/VBox/Runtime/common/crypto
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/crypto/iprt-openssl.cpp

    r98103 r104745  
    4343#ifdef IPRT_WITH_OPENSSL    /* Whole file. */
    4444# include <iprt/err.h>
     45# include <iprt/file.h>
    4546# include <iprt/string.h>
    4647# include <iprt/mem.h>
     
    169170}
    170171
     172
    171173DECLHIDDEN(int) rtCrOpenSslConvertPkcs7Attribute(void **ppvOsslAttrib, PCRTCRPKCS7ATTRIBUTE pAttrib, PRTERRINFO pErrInfo)
    172174{
    173     const unsigned char *pabEncoded;
    174     uint32_t             cbEncoded;
    175     void                *pvFree;
     175    const unsigned char *pabEncoded = NULL;
     176    uint32_t             cbEncoded  = 0;
     177    void                *pvFree     = NULL;
    176178    int rc = RTAsn1EncodeQueryRawBits(RTCrPkcs7Attribute_GetAsn1Core(pAttrib),
    177179                                      (const uint8_t **)&pabEncoded, &cbEncoded, &pvFree, pErrInfo);
     
    199201
    200202
     203/**
     204 * Writes the content of the @a pvMemBio to the new file @a pszFilename.
     205 *
     206 * @returns IPRT status code.
     207 * @param   pvMemBio    The memory BIO to write out.
     208 * @param   pszFilename The destination file.  This will be created.
     209 *                      The function will fail if this already exists.
     210 * @param   pErrInfo    Where to provide additional error details. Optional.
     211 */
     212DECLHIDDEN(int) rtCrOpenSslWriteMemBioToNewFile(void *pvMemBio, const char *pszFilename, PRTERRINFO pErrInfo)
     213{
     214    int rc;
     215
     216    /* Get the BIO buffer pointer first. */
     217    BUF_MEM *pBioBuf = NULL;
     218    long rcOssl = BIO_get_mem_ptr((BIO *)pvMemBio, &pBioBuf);
     219    if (rcOssl > 0)
     220    {
     221        AssertPtr(pBioBuf);
     222        RTFILE hFile = NIL_RTFILE;
     223        rc = RTFileOpen(&hFile, pszFilename,
     224                        RTFILE_O_WRITE | RTFILE_O_DENY_ALL | RTFILE_O_CREATE | (0600 << RTFILE_O_CREATE_MODE_SHIFT));
     225        if (RT_SUCCESS(rc))
     226        {
     227            rc = RTFileWrite(hFile, pBioBuf->data, pBioBuf->length, NULL);
     228            if (RT_SUCCESS(rc))
     229            {
     230                rc = RTFileClose(hFile);
     231                AssertRCStmt(rc, rc = RTErrInfoSetF(pErrInfo, rc, "RTFileClose failed on '%s'", pszFilename));
     232            }
     233            else
     234            {
     235                rc = RTErrInfoSetF(pErrInfo, rc, "RTFileWrite(,,%#zx,) failed on '%s'", pBioBuf->length, pszFilename);
     236                RTFileClose(hFile);
     237            }
     238            if (RT_FAILURE(rc))
     239                RTFileDelete(pszFilename);
     240        }
     241        else
     242            rc = RTErrInfoSetF(pErrInfo, rc, "RTFileOpen failed on '%s'", pszFilename);
     243    }
     244    else
     245        rc = RTErrInfoSet(pErrInfo, VERR_GENERAL_FAILURE, "BIO_get_mem_ptr");
     246    return rc;
     247}
     248
     249
    201250#endif /* IPRT_WITH_OPENSSL */
    202251
  • trunk/src/VBox/Runtime/common/crypto/x509-create-sign.cpp

    r104574 r104745  
    11/* $Id$ */
    22/** @file
    3  * IPRT - Crypto - X.509, Certificate Creation and Signing.
     3 * IPRT - Crypto - X.509, Certificate Creation.
    44 */
    55
    66/*
    7  * Copyright (C) 2006-2023 Oracle and/or its affiliates.
     7 * Copyright (C) 2024 Oracle and/or its affiliates.
    88 *
    99 * This file is part of VirtualBox base platform packages, as
     
    3939*   Header Files                                                                                                                 *
    4040*********************************************************************************************************************************/
    41 
    42 # if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
    43 #  include <io.h>
    44 # endif
    45 
    46 #include <iprt/file.h>
    4741#include "internal/iprt.h"
    4842#include <iprt/crypto/x509.h>
    4943
    50 # ifdef _MSC_VER
    51 #  define IPRT_COMPILER_VCC_WITH_C_INIT_TERM_SECTIONS
    52 #  include "internal/compiler-vcc.h"
    53 # endif
    54 
    55 # if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
    56 #  include <fcntl.h>
    57 # endif
    58 #include <iprt/err.h>
    59 #include <iprt/string.h>
    60 
    6144#ifdef IPRT_WITH_OPENSSL
     45# include <iprt/err.h>
     46# include <iprt/file.h>
     47# include <iprt/rand.h>
     48
     49# include "internal/iprt-openssl.h"
     50# include "internal/openssl-pre.h"
    6251# include <openssl/evp.h>
    6352# include <openssl/pem.h>
    6453# include <openssl/x509.h>
    6554# include <openssl/bio.h>
    66 
    67 #if defined(RT_OS_OS2)
    68 # define _O_WRONLY   O_WRONLY
    69 #endif
    70 
    71 RTDECL(int) RTCrX509Certificate_Generate(const char *pszServerCertificate, const char *pszServerPrivateKey)
     55# include "internal/openssl-post.h"
     56
     57
     58
     59RTDECL(int) RTCrX509Certificate_GenerateSelfSignedRsa(RTDIGESTTYPE enmDigestType, uint32_t cBits, uint32_t cSecsValidFor,
     60                                                      uint32_t fKeyUsage, uint64_t fExtKeyUsage, void *pvSubjectTodo,
     61                                                      const char *pszCertFile, const char *pszPrivateKeyFile, PRTERRINFO pErrInfo)
    7262{
    73     int rc = VINF_SUCCESS;
     63    AssertReturn(cSecsValidFor <= (uint32_t)INT32_MAX, VERR_OUT_OF_RANGE); /* larger values are not portable (win) */
     64    AssertReturn(!fKeyUsage, VERR_NOT_IMPLEMENTED);
     65    AssertReturn(!fExtKeyUsage, VERR_NOT_IMPLEMENTED);
     66    AssertReturn(pvSubjectTodo == NULL, VERR_NOT_IMPLEMENTED);
     67
    7468    /*
    75      * Set up private key using rsa
     69     * Translate enmDigestType.
    7670     */
    77     EVP_PKEY * pkey;
    78 #if (OPENSSL_VERSION_NUMBER >= 0x30000000L) /* OpenSSL 3 needed */
    79     pkey = EVP_RSA_gen(2048);
    80 #else
    81     pkey = EVP_PKEY_new();
    82     RSA * rsa;
    83     rsa = RSA_generate_key(
    84         2048,   /* Number of bits for the key */
     71    const EVP_MD * const pEvpDigest = (const EVP_MD *)rtCrOpenSslConvertDigestType(enmDigestType, pErrInfo);
     72    AssertReturn(pEvpDigest, pErrInfo ? pErrInfo->rc : VERR_CR_DIGEST_NOT_SUPPORTED);
     73
     74    /*
     75     * Create a new RSA private key.
     76     */
     77# if OPENSSL_VERSION_NUMBER >= 0x30000000 /* RSA_generate_key is depreated in v3 */
     78    EVP_PKEY * const pPrivateKey = EVP_RSA_gen(cBits);
     79    if (!pPrivateKey)
     80        return RTErrInfoSetF(pErrInfo, VERR_CR_KEY_GEN_FAILED_RSA, "EVP_RSA_gen(%u) failed", cBits);
     81# else
     82    RSA * const pRsaKey = RSA_generate_key(
     83        cBits,  /* Number of bits for the key */
    8584        RSA_F4, /* Exponent - RSA_F4 is defined as 0x10001L */
    8685        NULL,   /* Callback */
    8786        NULL    /* Callback argument */
    8887    );
    89     EVP_PKEY_assign_RSA(pkey, rsa);
    90 #endif
    91 
    92     if ( pkey == NULL )
    93         return VERR_CR_KEY_GEN_FAILED_RSA;
     88    if (!pRsaKey)
     89        return RTErrInfoSetF(pErrInfo, VERR_CR_KEY_GEN_FAILED_RSA, "RSA_generate_key(%u,RSA_F4,,) failed", cBits);
     90
     91    EVP_PKEY * const pPrivateKey = EVP_PKEY_new();
     92    if (pPrivateKey)
     93        EVP_PKEY_assign_RSA(pPrivateKey, pRsaKey); /* Takes ownership of pRsaKey. */
     94    else
     95    {
     96        RSA_free(pRsaKey);
     97        return RTErrInfoSet(pErrInfo, VERR_NO_MEMORY, "EVP_PKEY_new failed");
     98    }
     99# endif
    94100
    95101    /*
    96      * Set up certificate
     102     * Construct the certificate.
    97103     */
    98     X509* tempX509 = X509_new();
    99     if ( tempX509 == NULL )
    100         return VERR_CR_X509_GENERIC_ERROR;
    101     X509_set_version(tempX509,0); /** Set to X509 version 1 */
    102     ASN1_INTEGER_set(X509_get_serialNumber(tempX509), 1);
    103 #if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
    104     X509_gmtime_adj(X509_getm_notBefore(tempX509), 0);
    105     X509_gmtime_adj(X509_getm_notAfter(tempX509), 60*60*24*3650); /** 10 years time */
    106 #else
    107     X509_gmtime_adj(X509_get_notBefore(tempX509), 0);
    108     X509_gmtime_adj(X509_get_notAfter(tempX509), 60*60*24*3650); /** 10 years time */
    109 #endif
    110     X509_set_pubkey(tempX509,pkey);
    111 
    112     X509_NAME *x509_name = NULL;
    113     x509_name = X509_get_subject_name(tempX509);
    114 
    115     rc = X509_set_issuer_name(tempX509, x509_name);
    116     if ( RT_FAILURE(rc) )
    117         return rc;
    118 
    119     rc = X509_sign( tempX509, pkey, EVP_sha1());
    120     if ( RT_FAILURE(rc) )
    121         return rc;
    122 
    123     RTFILE hKeyFile;
    124     rc = RTFileOpen(&hKeyFile, pszServerPrivateKey, RTFILE_O_WRITE | RTFILE_O_DENY_ALL | RTFILE_O_CREATE | (0600 << RTFILE_O_CREATE_MODE_SHIFT) );
    125     if ( RT_FAILURE(rc) )
    126         return rc;
    127 # ifndef _MSC_VER
    128     int fd1 = (int)RTFileToNative(hKeyFile);
     104    int   rc = VINF_SUCCESS;
     105    X509 *pNewCert = X509_new();
     106    if (pNewCert)
     107    {
     108        int rcOssl;
     109
     110        /* Set to X509 version 1: */
     111# if 0
     112        if (fKeyUsage || fExtKeyUsage)
     113            rcOssl = X509_set_version(pNewCert, RTCRX509TBSCERTIFICATE_V3);
     114        else
     115# endif
     116            rcOssl = X509_set_version(pNewCert, RTCRX509TBSCERTIFICATE_V1);
     117        AssertStmt(rcOssl > 0, rc = RTErrInfoSet(pErrInfo, VERR_GENERAL_FAILURE, "X509_set_version failed"));
     118
     119        /* Set the serial number to a random number in the 1 - 1G range: */
     120        rcOssl = ASN1_INTEGER_set(X509_get_serialNumber(pNewCert), RTRandU32Ex(1, UINT32_MAX / 4));
     121        AssertStmt(rcOssl > 0, rc = RTErrInfoSet(pErrInfo, VERR_GENERAL_FAILURE, "X509_set_version failed"));
     122
     123        /* The certificate is valid from now and the specifice number of seconds forwards: */
     124# if OPENSSL_VERSION_NUMBER >= 0x30000000
     125        AssertStmt(X509_gmtime_adj(X509_getm_notBefore(pNewCert), 0),
     126                   rc = RTErrInfoSet(pErrInfo, VERR_GENERAL_FAILURE, "X509_gmtime_adj/before failed"));
     127        AssertStmt(X509_gmtime_adj(X509_getm_notAfter(pNewCert), cSecsValidFor),
     128                   rc = RTErrInfoSet(pErrInfo, VERR_GENERAL_FAILURE, "X509_gmtime_adj/after failed"));
    129129# else
    130     int fd1 = _open_osfhandle(RTFileToNative(hKeyFile), _O_WRONLY);
    131 # endif
    132     if ( fd1 < 0 )
    133         return VERR_FILE_IO_ERROR;
    134 
    135     BIO *fp1 = BIO_new_fd(fd1, BIO_NOCLOSE);
    136     rc = PEM_write_bio_PrivateKey( fp1, pkey, NULL, NULL, 0, NULL, NULL);
    137     if ( RT_FAILURE(rc) )
    138         return rc;
    139     BIO_free(fp1);
    140 # ifdef _MSC_VER
    141     close(fd1);
    142 #endif
    143     RTFileClose(hKeyFile);
    144 
    145     RTFILE hCertFile;
    146     rc = RTFileOpen(&hCertFile, pszServerCertificate, RTFILE_O_WRITE | RTFILE_O_DENY_ALL | RTFILE_O_CREATE | (0600 << RTFILE_O_CREATE_MODE_SHIFT) );
    147     if ( RT_FAILURE(rc) )
    148         return rc;
    149 # ifndef _MSC_VER
    150     int fd2 = (int)RTFileToNative(hCertFile);
    151 # else
    152     int fd2 = _open_osfhandle(RTFileToNative(hCertFile), _O_WRONLY);
    153 # endif
    154     if ( fd2 < 0 )
    155         return VERR_FILE_IO_ERROR;
    156 
    157     BIO *fp2 = BIO_new_fd(fd2, BIO_NOCLOSE);
    158     rc = PEM_write_bio_X509( fp2, tempX509 );
    159     if ( RT_FAILURE(rc) )
    160         return rc;
    161     BIO_free(fp2);
    162 # ifdef _MSC_VER
    163     close(fd2);
    164 #endif
    165     RTFileClose(hCertFile);
    166 
    167     X509_free(tempX509);
    168     EVP_PKEY_free(pkey);
    169 
     130        AssertStmt(X509_gmtime_adj(X509_get_notBefore(pNewCert), 0),
     131                   rc = RTErrInfoSet(pErrInfo, VERR_GENERAL_FAILURE, "X509_gmtime_adj/before failed"));
     132        AssertStmt(X509_gmtime_adj(X509_get_notAfter(pNewCert), cSecsValidFor),
     133                   rc = RTErrInfoSet(pErrInfo, VERR_GENERAL_FAILURE, "X509_gmtime_adj/after failed"));
     134# endif
     135
     136        /* Set the public key (part of the private): */
     137        rcOssl = X509_set_pubkey(pNewCert, pPrivateKey);
     138        AssertStmt(rcOssl > 0, rc = RTErrInfoSet(pErrInfo, VERR_GENERAL_FAILURE, "X509_set_pubkey failed"));
     139
     140# if 0
     141        /* Set key usage. */
     142        if (fKeyUsage)
     143        {
     144        }
     145        /* Set extended key usage. */
     146        if (fExtKeyUsage)
     147        {
     148        }
     149# endif
     150        /** @todo set other certificate attributes? */
     151
     152
     153        /** @todo check what the subject name is...  Offer way to specify it? */
     154
     155        /* Make it self signed: */
     156        X509_NAME *pX509Name = X509_get_subject_name(pNewCert);
     157        rcOssl = X509_set_issuer_name(pNewCert, pX509Name);
     158        AssertStmt(rcOssl > 0, rc = RTErrInfoSet(pErrInfo, VERR_GENERAL_FAILURE, "X509_set_issuer_name failed"));
     159
     160        if (RT_SUCCESS(rc))
     161        {
     162            /*
     163             * Sign the certificate.
     164             */
     165            rcOssl = X509_sign(pNewCert, pPrivateKey, pEvpDigest);
     166            if (rcOssl > 0)
     167            {
     168                /*
     169                 * Write out the result to the two files.
     170                 */
     171                /* The certificate (not security sensitive). */
     172                BIO * const pCertBio = BIO_new(BIO_s_mem());
     173                if (pCertBio)
     174                {
     175                    rcOssl = PEM_write_bio_X509(pCertBio, pNewCert);
     176                    if (rcOssl > 0)
     177                        rc = rtCrOpenSslWriteMemBioToNewFile(pCertBio, pszCertFile, pErrInfo);
     178                    else
     179                        rc = RTErrInfoSet(pErrInfo, VERR_CR_KEY_GEN_FAILED_RSA, "PEM_write_bio_X509 failed");
     180                    BIO_free(pCertBio);
     181                }
     182                else
     183                    rc = VERR_NO_MEMORY;
     184
     185                if (RT_SUCCESS(rc))
     186                {
     187                    /* The private key as plain text (security sensitive, thus last). */
     188                    BIO * const pPkBio = BIO_new(BIO_s_secmem());
     189                    if (pPkBio)
     190                    {
     191                        rcOssl = PEM_write_bio_PrivateKey(pPkBio, pPrivateKey,
     192                                                          NULL /*enc*/, NULL /*kstr*/, 0 /*klen*/, NULL /*cb*/, NULL /*u*/);
     193                        if (rcOssl > 0)
     194                            rc = rtCrOpenSslWriteMemBioToNewFile(pPkBio, pszPrivateKeyFile, pErrInfo);
     195                        else
     196                            rc = RTErrInfoSet(pErrInfo, VERR_CR_KEY_GEN_FAILED_RSA, "PEM_write_bio_PrivateKey failed");
     197                        BIO_free(pPkBio);
     198                    }
     199                    else
     200                        rc = VERR_NO_MEMORY;
     201                    if (RT_FAILURE(rc))
     202                        RTFileDelete(pszCertFile);
     203                }
     204            }
     205            else
     206                rc = RTErrInfoSet(pErrInfo, VERR_CR_KEY_GEN_FAILED_RSA, "X509_sign failed");
     207        }
     208
     209        X509_free(pNewCert);
     210    }
     211    else
     212        rc = RTErrInfoSet(pErrInfo, VERR_NO_MEMORY, "X509_new failed");
     213
     214    EVP_PKEY_free(pPrivateKey);
    170215    return rc;
    171216}
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