VirtualBox

Changeset 57613 in vbox


Ignore:
Timestamp:
Sep 4, 2015 2:19:44 AM (9 years ago)
Author:
vboxsync
Message:

IPRT,UINetworkReply.cpp: Added RTPathGlob, a set of RTCrStoreCertAddWantedDir/File/Store, a RTCrStoreCertAddWantedFromFishingExpedition, RTCrStoreCertCheckWanted, RTCrStoreCertCount, RTFsIsCaseSensitive and RTFileOpenTemp. Reworked some RTHttp bits and UINetworkReply stuff - this needs testing.

Location:
trunk
Files:
3 added
2 deleted
21 edited
1 moved

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/crypto/store.h

    r57584 r57613  
    2929#include <iprt/crypto/x509.h>
    3030#include <iprt/crypto/taf.h>
     31#include <iprt/sha.h>
    3132
    3233
     
    5657/** Pointer to a certificate store search. */
    5758typedef RTCRSTORECERTSEARCH *PRTCRSTORECERTSEARCH;
     59
     60
     61/**
     62 * Info about a wanted certificate.
     63 *
     64 * All the search criteria are optional, but for a safe and efficient search
     65 * it's recommended to specify all possible ones.  If none are given, the search
     66 * function will fail.
     67 *
     68 * For use with RTCrStoreCertAddFromFishingExpedition and others.
     69 */
     70typedef struct RTCRCERTWANTED
     71{
     72    /** The certificate subject name, optional.
     73     * The format is: "C=US, ST=California, L=Redwood Shores, O=Oracle Corporation" */
     74    const char *pszSubject;
     75    /** The size of the DER (ASN.1) encoded certificate, optional (0). */
     76    uint16_t    cbEncoded;
     77    /** Set if abSha1 contains a valid SHA-1 fingerprint. */
     78    bool        fSha1Fingerprint;
     79    /** Set if abSha512 contains a valid SHA-512 fingerprint. */
     80    bool        fSha512Fingerprint;
     81    /** The SHA-1 fingerprint (of the encoded data).   */
     82    uint8_t     abSha1[RTSHA1_HASH_SIZE];
     83    /** The SHA-512 fingerprint (of the encoded data).   */
     84    uint8_t     abSha512[RTSHA512_HASH_SIZE];
     85    /** User pointer for directly associating other data with the entry.
     86     * Subclassing the structure isn't possible because it's passed as an array. */
     87    void const *pvUser;
     88} RTCRCERTWANTED;
     89/** Pointer to a const certificat wanted structure. */
     90typedef RTCRCERTWANTED const *PCRTCRCERTWANTED;
    5891
    5992
     
    162195                                    PCRTSTRTUPLE paSuffixes, size_t cSuffixes, PRTERRINFO pErrInfo);
    163196
     197RTDECL(int) RTCrStoreCertAddWantedFromDir(RTCRSTORE hStore, uint32_t fFlags,
     198                                          const char *pszDir, PCRTSTRTUPLE paSuffixes, size_t cSuffixes,
     199                                          PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound, PRTERRINFO pErrInfo);
     200
    164201/**
    165202 * Adds certificates from the specified file.
     
    183220RTDECL(int) RTCrStoreCertAddFromFile(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename, PRTERRINFO pErrInfo);
    184221
     222RTDECL(int) RTCrStoreCertAddWantedFromFile(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename,
     223                                           PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound, PRTERRINFO pErrInfo);
     224
    185225/**
    186226 * Adds certificates from the specified java key store file.
     
    229269 */
    230270RTDECL(int) RTCrStoreCertAddFromStore(RTCRSTORE hStore, uint32_t fFlags, RTCRSTORE hStoreSrc);
     271
     272RTDECL(int) RTCrStoreCertAddWantedFromStore(RTCRSTORE hStore, uint32_t fFlags, RTCRSTORE hSrcStore,
     273                                            PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound);
     274
     275RTDECL(int) RTCrStoreCertCheckWanted(RTCRSTORE hStore, PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound);
     276
     277
     278RTDECL(int) RTCrStoreCertAddWantedFromFishingExpedition(RTCRSTORE hStore, uint32_t fFlags,
     279                                                        PCRTCRCERTWANTED paWanted, size_t cWanted,
     280                                                        bool *pafFound, PRTERRINFO pErrInfo);
    231281
    232282/**
     
    240290 */
    241291RTDECL(int) RTCrStoreCertExportAsPem(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename);
     292
     293/**
     294 * Counts the number of certificates in the store.
     295 *
     296 * @returns Certificate count on success, UINT32_MAX on failure.
     297 * @param   hStore              The store which certificates should be counted.
     298 */
     299RTDECL(uint32_t) RTCrStoreCertCount(RTCRSTORE hStore);
    242300
    243301RTDECL(int) RTCrStoreCertFindAll(RTCRSTORE hStore, PRTCRSTORECERTSEARCH pSearch);
  • trunk/include/iprt/dir.h

    r56291 r57613  
    236236 *
    237237 * This is the RTFS_TYPE_MASK stuff shifted down 12 bits and
    238  * identical to the BSD/LINUX ABI.
     238 * identical to the BSD/LINUX ABI.  See RTFS_TYPE_DIRENTRYTYPE_SHIFT.
    239239 */
    240240typedef enum RTDIRENTRYTYPE
  • trunk/include/iprt/err.h

    r57516 r57613  
    24782478/** @name RTCrDigest status codes.
    24792479 * @{ */
    2480 /** OpenSSL failed to initialize the digest algorithm contextn. */
     2480/** OpenSSL failed to initialize the digest algorithm context. */
    24812481#define VERR_CR_DIGEST_OSSL_DIGEST_INIT_ERROR       (-24200)
    24822482/** OpenSSL failed to clone the digest algorithm context. */
     
    24842484/** @} */
    24852485
     2486/** @name RTPath  status codes.
     2487 * @{ */
     2488/** Unknown glob variable.  */
     2489#define VERR_PATH_MATCH_UNKNOWN_VARIABLE            (-24400)
     2490/** The specified glob variable must be first in the pattern. */
     2491#define VERR_PATH_MATCH_VARIABLE_MUST_BE_FIRST      (-24401)
     2492/** Hit unimplemented glob pattern matching feature.  */
     2493#define VERR_PATH_MATCH_FEATURE_NOT_IMPLEMENTED     (-24402)
     2494/** Unknown character class in glob pattern.   */
     2495#define VERR_PATH_GLOB_UNKNOWN_CHAR_CLASS           (-24403)
     2496/** @} */
     2497
    24862498/* SED-END */
    24872499
  • trunk/include/iprt/file.h

    r57004 r57613  
    778778RTDECL(int) RTFileCreateTempSecure(char *pszTemplate);
    779779
     780/**
     781 * Opens a new file with a unique name in the temp directory.
     782 *
     783 * @returns iprt status code.
     784 * @param   pszTemplate     The file name template on input. The actual file
     785 *                          name on success. Empty string on failure.
     786 * @param   fMode           The mode to create the file with.  Use 0600 unless
     787 *                          you have reason not to.
     788 *
     789 * @remarks If actual control over the filename or location is required, we'll
     790 *          create an extended edition of this API.
     791 */
     792RTDECL(int) RTFileOpenTemp(PRTFILE pFile, char *pszFilename, size_t cbFilename, uint64_t fOpen);
     793
    780794
    781795/** @page   pg_rt_filelock      RT File locking API description
  • trunk/include/iprt/fs.h

    r56291 r57613  
    117117/** Type mask (S_IFMT). */
    118118#define RTFS_TYPE_MASK              0170000U
     119/** The shift count to convert between RTFS_TYPE_MASK and DIRENTRYTYPE. */
     120#define RTFS_TYPE_DIRENTRYTYPE_SHIFT    12
    119121
    120122/** Unix attribute mask. */
     
    593595RTR3DECL(int) RTFsQueryProperties(const char *pszFsPath, PRTFSPROPERTIES pProperties);
    594596
     597/**
     598 * Checks if the given volume is case sensitive or not.
     599 *
     600 * This may be misleading in some cases as we lack the necessary APIs to query
     601 * the information on some system (or choose not to use them) and are instead
     602 * returning the general position on case sensitive file name of the system.
     603 *
     604 * @returns @c true if case sensitive, @c false if not.
     605 * @param   pszFsPath       Path within the mounted file system.
     606 */
     607RTR3DECL(bool) RTFsIsCaseSensitive(const char *pszFsPath);
    595608
    596609/**
  • trunk/include/iprt/http.h

    r57577 r57613  
    11/* $Id$ */
    22/** @file
    3  * IPRT - Simple HTTP Communication API.
     3 * IPRT - Simple HTTP/HTTPS Client API.
    44 */
    55
     
    3232RT_C_DECLS_BEGIN
    3333
    34 /** @defgroup grp_rt_http   RTHttp - Simple HTTP API
     34/** @defgroup grp_rt_http   RTHttp - Simple HTTP/HTTPS Client API
    3535 * @ingroup grp_rt
    3636 * @{
     
    3838
    3939/** @todo the following three definitions may move the iprt/types.h later. */
    40 /** RTHTTP interface handle. */
     40/** HTTP/HTTPS client handle. */
    4141typedef R3PTRTYPE(struct RTHTTPINTERNAL *)      RTHTTP;
    42 /** Pointer to a RTHTTP interface handle. */
    43 typedef RTHTTP                                  *PRTHTTP;
    44 /** Nil RTHTTP interface handle. */
     42/** Pointer to a HTTP/HTTPS client handle. */
     43typedef RTHTTP                                 *PRTHTTP;
     44/** Nil HTTP/HTTPS client handle. */
    4545#define NIL_RTHTTP                              ((RTHTTP)0)
    4646
    4747
    4848/**
    49  * Creates a HTTP interface handle.
     49 * Creates a HTTP client instance.
    5050 *
    5151 * @returns iprt status code.
     
    5656
    5757/**
    58  * Destroys a HTTP interface handle.
     58 * Destroys a HTTP client instance.
    5959 *
    6060 * @param   hHttp       Handle to the HTTP interface.
     
    8080 * @returns iprt status code.
    8181 *
    82  * @param   hHttp           HTTP interface handle.
    83  * @param   pcszUrl         URL.
     82 * @param   hHttp           The HTTP client instance.
     83 * @param   pszUrl          URL.
    8484 * @param   ppszNotUtf8     Where to return the poitner to the HTTP response.
    8585 *                          The string is of course zero terminated.  Use
     
    9999 *          containing embedded zero's, use RTHttpGetBinary instead.
    100100 */
    101 RTR3DECL(int) RTHttpGetText(RTHTTP hHttp, const char *pcszUrl, char **ppszNotUtf8);
     101RTR3DECL(int) RTHttpGetText(RTHTTP hHttp, const char *pszUrl, char **ppszNotUtf8);
    102102
    103103/**
     
    113113 * @returns iprt status code.
    114114 *
    115  * @param   hHttp           HTTP interface handle.
    116  * @param   pcszUrl         The URL.
     115 * @param   hHttp           The HTTP client instance.
     116 * @param   pszUrl          The URL.
    117117 * @param   ppvResponse     Where to store the HTTP response data.  Use
    118118 *                          RTHttpFreeResponse to free.
    119119 * @param   pcb             Size of the returned buffer.
    120120 */
    121 RTR3DECL(int) RTHttpGetBinary(RTHTTP hHttp, const char *pcszUrl, void **ppvResponse, size_t *pcb);
     121RTR3DECL(int) RTHttpGetBinary(RTHTTP hHttp, const char *pszUrl, void **ppvResponse, size_t *pcb);
    122122
    123123/**
     
    133133 * @returns iprt status code.
    134134 *
    135  * @param   hHttp           HTTP interface handle.
     135 * @param   hHttp           The HTTP client instance.
    136136 * @param   pszUrl          The URL.
    137137 * @param   pszDstFile      The destination file name.
     
    146146 * @returns iprt status code.
    147147 *
    148  * @param   hHttp           HTTP interface handle.
     148 * @param   hHttp           The HTTP client instance.
    149149 */
    150150RTR3DECL(int) RTHttpAbort(RTHTTP hHttp);
     
    154154 *
    155155 * @returns iprt status code.
    156  * @param   hHttp           HTTP interface handle.
     156 * @param   hHttp           The HTTP client instance.
    157157 */
    158158RTR3DECL(int) RTHttpUseSystemProxySettings(RTHTTP hHttp);
     
    163163 * @returns iprt status code.
    164164 *
    165  * @param   hHttp           HTTP interface handle.
    166  * @param   pcszProxy       URL of the proxy.
     165 * @param   hHttp           The HTTP client instance.
     166 * @param   pszProxy        URL of the proxy.
    167167 * @param   uPort           port number of the proxy, use 0 for not specifying a port.
    168  * @param   pcszUser        Username, pass NULL for no authentication.
    169  * @param   pcszPwd         Password, pass NULL for no authentication.
    170  */
    171 RTR3DECL(int) RTHttpSetProxy(RTHTTP hHttp, const char *pcszProxyUrl, uint32_t uPort,
    172                              const char *pcszProxyUser, const char *pcszProxyPwd);
     168 * @param   pszProxyUser    Username, pass NULL for no authentication.
     169 * @param   pszProxyPwd     Password, pass NULL for no authentication.
     170 */
     171RTR3DECL(int) RTHttpSetProxy(RTHTTP hHttp, const char *pszProxyUrl, uint32_t uPort,
     172                             const char *pszProxyUser, const char *pszProxyPwd);
    173173
    174174/**
     
    177177 * @returns iprt status code.
    178178 *
    179  * @param   hHttp           HTTP interface handle.
     179 * @param   hHttp           The HTTP client instance.
    180180 * @param   cHeaders        Number of custom headers.
    181  * @param   pcszHeaders     Array of headers in form "foo: bar".
     181 * @param   papszHeaders    Array of headers in form "foo: bar".
    182182 */
    183183RTR3DECL(int) RTHttpSetHeaders(RTHTTP hHttp, size_t cHeaders, const char * const *papszHeaders);
    184184
    185185/**
     186 * Tells the HTTP client instance to gather system CA certificates into a
     187 * temporary file and use it for HTTPS connections.
     188 *
     189 * This will be called automatically if a 'https' URL is presented and
     190 * RTHttpSetCaFile hasn't been called yet.
     191 *
     192 * @returns IPRT status code.
     193 * @param   hHttp           The HTTP client instance.
     194 * @param   pErrInfo        Where to store additional error/warning information.
     195 *                          Optional.
     196 */
     197RTR3DECL(int) RTHttpUseTemporaryCaFile(RTHTTP hHttp, PRTERRINFO pErrInfo);
     198
     199/**
    186200 * Set a custom certification authority file, containing root certificates.
    187201 *
    188202 * @returns iprt status code.
    189203 *
    190  * @param   hHttp           HTTP interface handle.
    191  * @param   pcszCAFile      File name containing root certificates.
    192  */
    193 RTR3DECL(int) RTHttpSetCAFile(RTHTTP hHttp, const char *pcszCAFile);
    194 
     204 * @param   hHttp           The HTTP client instance.
     205 * @param   pszCAFile       File name containing root certificates.
     206 *
     207 * @remarks For portable HTTPS support, use RTHttpGatherCaCertsInFile and pass
     208 */
     209RTR3DECL(int) RTHttpSetCAFile(RTHTTP hHttp, const char *pszCAFile);
     210
     211/**
     212 * Gathers certificates into a cryptographic (certificate) store
     213 *
     214 * This is a just a combination of RTHttpGatherCaCertsInStore and
     215 * RTCrStoreCertExportAsPem.
     216 *
     217 * @returns IPRT status code.
     218 * @param   hStore          The certificate store to gather the certificates
     219 *                          in.
     220 * @param   fFlags          RTHTTPGATHERCACERT_F_XXX.
     221 * @param   pErrInfo        Where to store additional error/warning information.
     222 *                          Optional.
     223 */
     224RTR3DECL(int) RTHttpGatherCaCertsInStore(RTCRSTORE hStore, uint32_t fFlags, PRTERRINFO pErrInfo);
     225
     226/**
     227 * Gathers certificates into a file that can be used with RTHttpSetCAFile.
     228 *
     229 * This is a just a combination of RTHttpGatherCaCertsInStore and
     230 * RTCrStoreCertExportAsPem.
     231 *
     232 * @returns IPRT status code.
     233 * @param   pszCaFile       The output file.
     234 * @param   fFlags          RTHTTPGATHERCACERT_F_XXX.
     235 * @param   pErrInfo        Where to store additional error/warning information.
     236 *                          Optional.
     237 */
     238RTR3DECL(int) RTHttpGatherCaCertsInFile(const char *pszCaFile, uint32_t fFlags, PRTERRINFO pErrInfo);
    195239
    196240/** @} */
  • trunk/include/iprt/mangling.h

    r57584 r57613  
    603603# define RTFileOpenF                                    RT_MANGLER(RTFileOpenF)
    604604# define RTFileOpenV                                    RT_MANGLER(RTFileOpenV)
     605# define RTFileOpenTemp                                 RT_MANGLER(RTFileOpenTemp)
    605606# define RTFileQueryFsSizes                             RT_MANGLER(RTFileQueryFsSizes)
    606607# define RTFileQueryInfo                                RT_MANGLER(RTFileQueryInfo)
     
    628629# define RTFileWriteAt                                  RT_MANGLER(RTFileWriteAt)
    629630# define RTFilesystemVfsFromFile                        RT_MANGLER(RTFilesystemVfsFromFile)
     631# define RTFsIsCaseSensitive                            RT_MANGLER(RTFsIsCaseSensitive)
    630632# define RTFsQueryProperties                            RT_MANGLER(RTFsQueryProperties)
    631633# define RTFsQuerySerial                                RT_MANGLER(RTFsQuerySerial)
     
    10611063# define RTPathGetCurrentOnDrive                        RT_MANGLER(RTPathGetCurrentOnDrive)
    10621064# define RTPathGetMode                                  RT_MANGLER(RTPathGetMode)
     1065# define RTPathGlob                                     RT_MANGLER(RTPathGlob)
     1066# define RTPathGlobFree                                 RT_MANGLER(RTPathGlobFree)
    10631067# define RTPathHasSuffix                                RT_MANGLER(RTPathHasSuffix)
    10641068# define RTPathHasPath                                  RT_MANGLER(RTPathHasPath)
     
    28922896# define RTCrStoreCertAddEncoded                        RT_MANGLER(RTCrStoreCertAddEncoded)
    28932897# define RTCrStoreCertByIssuerAndSerialNo               RT_MANGLER(RTCrStoreCertByIssuerAndSerialNo)
     2898# define RTCrStoreCertCount                             RT_MANGLER(RTCrStoreCertCount)
    28942899# define RTCrStoreCertFindAll                           RT_MANGLER(RTCrStoreCertFindAll)
    28952900# define RTCrStoreCertFindBySubjectOrAltSubjectByRfc5280 RT_MANGLER(RTCrStoreCertFindBySubjectOrAltSubjectByRfc5280)
     
    29072912# define RTCrStoreCertAddFromJavaKeyStoreInMem          RT_MANGLER(RTCrStoreCertAddFromJavaKeyStoreInMem)
    29082913# define RTCrStoreCertAddFromStore                      RT_MANGLER(RTCrStoreCertAddFromStore)
     2914# define RTCrStoreCertAddWantedFromDir                  RT_MANGLER(RTCrStoreCertAddWantedFromDir)
     2915# define RTCrStoreCertAddWantedFromFile                 RT_MANGLER(RTCrStoreCertAddWantedFromFile)
     2916# define RTCrStoreCertAddWantedFromStore                RT_MANGLER(RTCrStoreCertAddWantedFromStore)
     2917# define RTCrStoreCertAddWantedFromFishingExpedition    RT_MANGLER(RTCrStoreCertAddWantedFromFishingExpedition)
     2918# define RTCrStoreCertCheckWanted                       RT_MANGLER(RTCrStoreCertCheckWanted)
    29092919# define RTCrStoreCertExportAsPem                       RT_MANGLER(RTCrStoreCertExportAsPem)
    29102920# define RTErrInfoAdd                                   RT_MANGLER(RTErrInfoAdd)
  • trunk/include/iprt/path.h

    r57572 r57613  
    601601 * The first component is the root, volume or UNC specifier, if present.  Use
    602602 * RTPATH_PROP_HAS_ROOT_SPEC() on RTPATHPARSED::fProps to determine its
    603  * precense.
     603 * presence.
    604604 *
    605605 * Other than the root component, no component will include directory separators
     
    11721172RTDECL(int) RTPathTemp(char *pszPath, size_t cchPath);
    11731173
     1174
     1175/**
     1176 * RTPathGlobl result entry.
     1177 */
     1178typedef struct RTPATHGLOBENTRY
     1179{
     1180    /** List entry. */
     1181    struct RTPATHGLOBENTRY *pNext;
     1182    /** RTDIRENTRYTYPE value. */
     1183    uint8_t                 uType;
     1184    /** Unused explicit padding. */
     1185    uint8_t                 bUnused;
     1186    /** The length of the path. */
     1187    uint16_t                cchPath;
     1188    /** The path to the file (variable length). */
     1189    char                    szPath[1];
     1190} RTPATHGLOBENTRY;
     1191/** Pointer to a GLOB result entry. */
     1192typedef RTPATHGLOBENTRY *PRTPATHGLOBENTRY;
     1193/** Pointer to a const GLOB result entry. */
     1194typedef RTPATHGLOBENTRY const *PCRTPATHGLOBENTRY;
     1195/** Pointer to a GLOB result entry pointer. */
     1196typedef PCRTPATHGLOBENTRY *PPCRTPATHGLOBENTRY;
     1197
     1198/**
     1199 * Performs wildcard expansion on a path pattern.
     1200 *
     1201 * @returns IPRT status code.
     1202 *
     1203 * @param   pszPattern      The pattern to expand.
     1204 * @param   fFlags          RTPATHGLOB_F_XXX.
     1205 * @param   ppHead          Where to return the head of the result list.  This
     1206 *                          is always set to NULL on failure.
     1207 * @param   pcResults       Where to return the number of the result. Optional.
     1208 */
     1209RTDECL(int) RTPathGlob(const char *pszPattern, uint32_t fFlags, PPCRTPATHGLOBENTRY ppHead, uint32_t *pcResults);
     1210
     1211/** @name RTPATHGLOB_F_XXX - RTPathGlob flags
     1212 *  @{ */
     1213/** Case insensitive. */
     1214#define RTPATHGLOB_F_IGNORE_CASE        RT_BIT_32(0)
     1215/** Do not expand \${EnvOrSpecialVariable} in the pattern. */
     1216#define RTPATHGLOB_F_NO_VARIABLES       RT_BIT_32(1)
     1217/** Do not interpret a leading tilde as a home directory reference. */
     1218#define RTPATHGLOB_F_NO_TILDE           RT_BIT_32(2)
     1219/** Only return the first match. */
     1220#define RTPATHGLOB_F_FIRST_ONLY         RT_BIT_32(3)
     1221/** Only match directories (implied if pattern ends with slash). */
     1222#define RTPATHGLOB_F_ONLY_DIRS          RT_BIT_32(4)
     1223/** Do not match directories.  (Can't be used with RTPATHGLOB_F_ONLY_DIRS or
     1224 * patterns containing a trailing slash.) */
     1225#define RTPATHGLOB_F_NO_DIRS            RT_BIT_32(5)
     1226/** Disables the '**' wildcard pattern for matching zero or more subdirs. */
     1227#define RTPATHGLOB_F_NO_STARSTAR        RT_BIT_32(6)
     1228/** Mask of valid flags. */
     1229#define RTPATHGLOB_F_MASK               UINT32_C(0x0000007f)
     1230/** @} */
     1231
     1232/**
     1233 * Frees the results produced by RTPathGlob.
     1234 *
     1235 * @param   pHead           What RTPathGlob returned.  NULL ignored.
     1236 */
     1237RTDECL(void) RTPathGlobFree(PCRTPATHGLOBENTRY pHead);
     1238
     1239
    11741240/**
    11751241 * Query information about a file system object.
  • trunk/src/VBox/Frontends/VirtualBox/src/net/UINetworkReply.cpp

    r57581 r57613  
    7272
    7373private:
     74    /** @name Helpers - HTTP stuff
     75     * @{ */
     76    int applyProxyRules();
     77    int applyHttpsCertificates();
     78    int applyRawHeaders();
     79    int performMainRequest();
     80    /** @} */
     81
     82    /* Helper: Main thread runner: */
     83    void run();
     84
    7485    /** Info about wanted certificate. */
    7586    typedef struct CERTINFO
    7687    {
    77         /** The certificate subject name. */
    78         const char *pszSubject;
    79         /** The size of the DER (ASN.1) encoded certificate. */
    80         uint16_t    cbEncoded;
    8188        /** Gives the s_aCerts index this certificate is an alternative edition of,
    8289         * UINT8_MAX if no alternative.  This is a complication caused by VeriSign
     
    8794        /** Set if mandatory. */
    8895        bool        fMandatory;
    89         /** The SHA-1 fingerprint (of the encoded data).   */
    90         uint8_t     abSha1[RTSHA1_HASH_SIZE];
    91         /** The SHA-512 fingerprint (of the encoded data).   */
    92         uint8_t     abSha512[RTSHA512_HASH_SIZE];
    9396        /** Filename in the zip file we download (PEM). */
    9497        const char *pszZipFile;
     
    97100    } CERTINFO;
    98101
    99 
    100     /** @name Helpers - HTTP stuff
    101      * @{ */
    102     int applyProxyRules();
    103     int applyHttpsCertificates();
    104     int applyRawHeaders();
    105     int performMainRequest();
    106     /** @} */
    107 
    108     /* Helper: Main thread runner: */
    109     void run();
    110 
    111102    /** @name Static helpers for HTTP and Certificates handling.
    112103     * @{ */
     
    114105    static int applyProxyRules(RTHTTP hHttp, const QString &strHostName, int iPort);
    115106    static int applyRawHeaders(RTHTTP hHttp, const QList<QByteArray> &headers, const QNetworkRequest &request);
    116     static bool allCertsFound(uint64_t fFoundCerts, bool fOnlyMandatory);
    117     static uint64_t certEntryFoundMask(uint32_t iCert);
    118     static bool checkCertificatesInFile(const char *pszCaCertFile);
    119     static bool checkCertificatesInStore(RTCRSTORE hStore, unsigned *pcCertificates = NULL);
    120     static int downloadCertificates(RTHTTP hHttp, const char *pszCaCertFile);
     107    static unsigned countCertsFound(bool const *pafFoundCerts);
     108    static bool areAllCertsFound(bool const *pafFoundCerts, bool fOnlyMandatory);
     109    static void refreshCertificates(RTHTTP hHttp, RTCRSTORE hOldStore, bool *pafFoundCerts, const char *pszCaCertFile);
     110    static void downloadMissingCertificates(RTCRSTORE hNewStore, bool *pafNewFoundCerts, RTHTTP hHttp,
     111                                            PRTERRINFOSTATIC pStaticErrInfo);
    121112    static int convertVerifyAndAddPemCertificateToStore(RTCRSTORE hStore, void const *pvResponse,
    122                                                         size_t cbResponse, const CERTINFO *pCertInfo);
    123     static int retrieveCertificatesFromSystem(const char *pszCaCertFile);
     113                                                        size_t cbResponse, PCRTCRCERTWANTED pWantedCert);
    124114    /** @} */
    125115
     
    135125
    136126    static const QString s_strCertificateFileName;
    137     static const CERTINFO s_aCerts[3];
     127    static const RTCRCERTWANTED s_aCerts[3];
     128    static const CERTINFO s_CertInfoPcaCls3Gen1Md2;
     129    static const CERTINFO s_CertInfoPcaCls3Gen1Sha1;
     130    static const CERTINFO s_CertInfoPcaCls3Gen5;
     131};
     132
     133/*static*/ const UINetworkReplyPrivateThread::CERTINFO UINetworkReplyPrivateThread::s_CertInfoPcaCls3Gen1Sha1 =
     134{
     135    /*.iAlternativeTo =*/   1,
     136    /*.fMandatory     =*/   false,
     137    /*.pszZipFile     =*/
     138    "VeriSign Root Certificates/Generation 1 (G1) PCAs/Class 3 Public Primary Certification Authority.pem",
     139    /*.apszUrls[3]    =*/
     140    {
     141        "http://www.symantec.com/content/en/us/enterprise/verisign/roots/Class-3-Public-Primary-Certification-Authority.pem",
     142        "http://www.verisign.com/repository/roots/root-certificates/PCA-3.pem", /* dead */
     143        NULL,
     144        "http://update.virtualbox.org/cacerts-symantec-PCA-3-pem-has-gone-missing-again" /* attention getter */
     145    }
     146};
     147
     148/*static*/ const UINetworkReplyPrivateThread::CERTINFO UINetworkReplyPrivateThread::s_CertInfoPcaCls3Gen1Md2 =
     149{
     150    /*.iAlternativeTo =*/   0,
     151    /*.fMandatory     =*/   false,
     152    /*.pszZipFile     =*/   NULL,
     153    /*.apszUrls[3]    =*/   { NULL, NULL, NULL },
     154};
     155
     156/*static*/ const UINetworkReplyPrivateThread::CERTINFO UINetworkReplyPrivateThread::s_CertInfoPcaCls3Gen5 =
     157{
     158    /*.iAlternativeTo =*/   UINT8_MAX,
     159    /*.fMandatory     =*/   true,
     160    /*.pszZipFile     =*/
     161    "VeriSign Root Certificates/Generation 5 (G5) PCA/VeriSign Class 3 Public Primary Certification Authority - G5.pem",
     162    /*.apszUrls[3]    =*/
     163    {
     164        "http://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem",
     165        "http://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class-3-Public-Primary-Certification-Authority-G5.pem", /* (in case they correct above typo) */
     166        "http://www.verisign.com/repository/roots/root-certificates/PCA-3G5.pem", /* dead */
     167        "http://update.virtualbox.org/cacerts-symantec-PCA-3G5-pem-has-gone-missing-again" /* attention getter */
     168    }
    138169};
    139170
     
    141172/**
    142173 * Details on the certificates we are after.
     174 * The pvUser member points to a UINetworkReplyPrivateThread::CERTINFO.
    143175 */
    144 /* static */ const UINetworkReplyPrivateThread::CERTINFO UINetworkReplyPrivateThread::s_aCerts[3] =
     176/* static */ const RTCRCERTWANTED UINetworkReplyPrivateThread::s_aCerts[3] =
    145177{
    146178    /*[0] =*/   /* The reissued version with the SHA-1 signature. */
    147179/** @todo r=bird: Why do we need this certificate? Neither update.virtualbox.org nor www.virtualbox.org uses it...  ElCapitan doesn't ship this. */
    148180    {
    149         /*.pszSubject =*/
    150         "C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority",
    151         /*.cbEncoded      =*/   0x240,
    152         /*.iAlternativeTo =*/   1,
    153         /*.fMandatory     =*/   false,
    154         /*.abSha1         =*/
     181        /*.pszSubject        =*/    "C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority",
     182        /*.cbEncoded         =*/    0x240,
     183        /*.Sha1Fingerprint   =*/    true,
     184        /*.Sha512Fingerprint =*/    true,
     185        /*.abSha1            =*/
    155186        {
    156187            0xa1, 0xdb, 0x63, 0x93, 0x91, 0x6f, 0x17, 0xe4, 0x18, 0x55,
    157188            0x09, 0x40, 0x04, 0x15, 0xc7, 0x02, 0x40, 0xb0, 0xae, 0x6b
    158189        },
    159         /*.abSha512       =*/
     190        /*.abSha512          =*/
    160191        {
    161192            0xbb, 0xf7, 0x8a, 0x19, 0x9f, 0x37, 0xee, 0xa2,
     
    168199            0x0a, 0x67, 0x83, 0x87, 0xc5, 0x45, 0xc4, 0x99
    169200        },
    170         /*.pszZipFile     =*/
    171         "VeriSign Root Certificates/Generation 1 (G1) PCAs/Class 3 Public Primary Certification Authority.pem",
    172         /*.apszUrls[3]    =*/
    173         {
    174             "http://www.symantec.com/content/en/us/enterprise/verisign/roots/Class-3-Public-Primary-Certification-Authority.pem",
    175             "http://www.verisign.com/repository/roots/root-certificates/PCA-3.pem", /* dead */
    176             NULL,
    177             "http://update.virtualbox.org/cacerts-symantec-PCA-3-pem-has-gone-missing-again" /* attention getter */
    178         },
     201        /*.pvUser */ &UINetworkReplyPrivateThread::s_CertInfoPcaCls3Gen1Sha1
    179202    },
    180203    /*[1] =*/   /* The original version with the MD2 signature. */
    181204    {
    182         /*.pszSubject     =*/
    183         "C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority",
    184         /*.cbEncoded      =*/   0x240,
    185         /*.iAlternativeTo =*/   0,
    186         /*.fMandatory     =*/   false,
    187         /*.abSha1         =*/
     205        /*.pszSubject        =*/    "C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority",
     206        /*.cbEncoded         =*/    0x240,
     207        /*.Sha1Fingerprint   =*/    true,
     208        /*.Sha512Fingerprint =*/    true,
     209        /*.abSha1            =*/
    188210        {
    189211            0x74, 0x2c, 0x31, 0x92, 0xe6, 0x07, 0xe4, 0x24, 0xeb, 0x45,
    190212            0x49, 0x54, 0x2b, 0xe1, 0xbb, 0xc5, 0x3e, 0x61, 0x74, 0xe2
    191213        },
    192         /*.abSha512       =*/
     214        /*.abSha512          =*/
    193215        {
    194216            0x7c, 0x2f, 0x94, 0x22, 0x5f, 0x67, 0x98, 0x89,
     
    201223            0xc8, 0x0c, 0x5a, 0xe7, 0x8b, 0x33, 0xf2, 0xaa
    202224        },
    203         /*.pszZipFile     =*/ NULL,
    204         /*.apszUrls[3]    =*/ { NULL, NULL, NULL },
     225        /*.pvUser */ &UINetworkReplyPrivateThread::s_CertInfoPcaCls3Gen1Md2
    205226    },
    206227    /*[2] =*/
    207228    {
    208         /*.pszSubject =*/
     229        /*.pszSubject        =*/
    209230        "C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, "
    210231        "CN=VeriSign Class 3 Public Primary Certification Authority - G5",
    211         /*.cbEncoded      =*/   0x4d7,
    212         /*.iAlternativeTo =*/   UINT8_MAX,
    213         /*.fMandatory     =*/   true,
    214         /*.abSha1         =*/
     232        /*.cbEncoded         =*/    0x4d7,
     233        /*.Sha1Fingerprint   =*/    true,
     234        /*.Sha512Fingerprint =*/    true,
     235        /*.abSha1            =*/
    215236        {
    216237            0x4e, 0xb6, 0xd5, 0x78, 0x49, 0x9b, 0x1c, 0xcf, 0x5f, 0x58,
    217238            0x1e, 0xad, 0x56, 0xbe, 0x3d, 0x9b, 0x67, 0x44, 0xa5, 0xe5
    218239        },
    219         /*.abSha512   =*/
     240        /*.abSha512          =*/
    220241        {
    221242            0xd4, 0xf8, 0x10, 0x54, 0x72, 0x77, 0x0a, 0x2d,
     
    228249            0xd2, 0x6b, 0xa8, 0x9a, 0xf0, 0xb3, 0x6a, 0x01
    229250        },
    230         /*.pszZipFile     =*/
    231         "VeriSign Root Certificates/Generation 5 (G5) PCA/VeriSign Class 3 Public Primary Certification Authority - G5.pem",
    232         /*.apszUrls[3]    =*/
    233         {
    234             "http://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem",
    235             "http://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class-3-Public-Primary-Certification-Authority-G5.pem", /* (in case they correct above typo) */
    236             "http://www.verisign.com/repository/roots/root-certificates/PCA-3G5.pem", /* dead */
    237             "http://update.virtualbox.org/cacerts-symantec-PCA-3G5-pem-has-gone-missing-again" /* attention getter */
    238         },
     251        /*.pvUser */ &UINetworkReplyPrivateThread::s_CertInfoPcaCls3Gen5
    239252    },
    240253};
     
    288301
    289302    /*
    290      * Check that the certificate file is recent and contains the necessary certificates.
     303     * Check the state of our CA certificate file, it's one of the following:
     304     *      - Missing, recreate from scratch (= refresh).
     305     *      - Everything is there and it is less than 28 days old, do nothing.
     306     *      - Everything is there but it's older than 28 days, refresh.
     307     *      - Missing certificates and is older than 1 min, refresh.
     308     *
     309     * Start by creating a store for loading the current state into, as we'll
     310     * be need that for the refresh.
    291311     */
    292     int rc;
    293     if (checkCertificatesInFile(pszCaCertFile))
    294         rc = RTHttpSetCAFile(m_hHttp, pszCaCertFile);
    295     else
    296     {
     312    RTCRSTORE hCurStore = NIL_RTCRSTORE;
     313    int rc = RTCrStoreCreateInMem(&hCurStore, 256);
     314    if (RT_SUCCESS(rc))
     315    {
     316        bool fRefresh    = true;
     317        bool afCertsFound[RT_ELEMENTS(s_aCerts)];
     318        RT_ZERO(afCertsFound);
     319
    297320        /*
    298          * Need to create/update the CA certificate file.  Try see if the necessary
    299          * certificates are to be found somewhere on the local system, then fall back
    300          * to downloading them.
     321         * Load the file if it exists.
     322         *
     323         * To effect regular updates, we need the modification date of the file,
     324         * so we use RTPathQueryInfoEx here and not RTFileExists.
    301325         */
    302         rc = retrieveCertificatesFromSystem(pszCaCertFile);
    303         if (RT_FAILURE(rc))
    304             rc = downloadCertificates(m_hHttp, pszCaCertFile);
    305 
     326        RTFSOBJINFO Info;
     327        int rc = RTPathQueryInfoEx(pszCaCertFile, &Info, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
     328        if (   RT_SUCCESS(rc)
     329            && RTFS_IS_FILE(Info.Attr.fMode))
     330        {
     331            RTERRINFOSTATIC StaticErrInfo;
     332            rc = RTCrStoreCertAddFromFile(hCurStore, RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR, pszCaCertFile,
     333                                          RTErrInfoInitStatic(&StaticErrInfo));
     334            if (RTErrInfoIsSet(&StaticErrInfo.Core))
     335                LogRel(("checkCertificates: %s\n", StaticErrInfo.Core.pszMsg));
     336            else
     337                AssertRC(rc);
     338
     339            /*
     340             * Scan the store the for certificates we need, then see what we
     341             * need to do wrt file age.
     342             */
     343            rc = RTCrStoreCertCheckWanted(hCurStore, s_aCerts, RT_ELEMENTS(s_aCerts), afCertsFound);
     344            AssertRC(rc);
     345            RTTIMESPEC RefreshAge;
     346            uint32_t   cSecRefresh = rc == VINF_SUCCESS  ? 28 * RT_SEC_1DAY /* all found */ : 60 /* stuff missing */;
     347            fRefresh = RTTimeSpecCompare(&Info.ModificationTime, RTTimeSpecSubSeconds(RTTimeNow(&RefreshAge), cSecRefresh)) <= 0;
     348        }
     349
     350        /*
     351         * Refresh the file if necessary.
     352         */
     353        if (fRefresh)
     354            refreshCertificates(m_hHttp, hCurStore, afCertsFound, pszCaCertFile);
     355
     356        RTCrStoreRelease(hCurStore);
     357
     358        /*
     359         * Final verdict.
     360         */
     361        if (areAllCertsFound(afCertsFound, true /*fOnlyMandatory*/))
     362            rc = VINF_SUCCESS;
     363        else
     364            rc = VERR_NOT_FOUND; /** @todo r=bird: Why not try and let RTHttpGet* bitch if the necessary certs are missing? */
     365
     366        /*
     367         * Set our custom CA file.
     368         */
    306369        if (RT_SUCCESS(rc))
    307370            rc = RTHttpSetCAFile(m_hHttp, pszCaCertFile);
    308371    }
    309 
    310372    return rc;
    311373}
     
    426488
    427489/**
    428  * Checks if the certificates we desire are all present in the given file, and
    429  * that the file is recent enough (not for downloaded certs).
     490 * Counts the number of certificates found in a search result array.
    430491 *
    431  * @returns true if fine, false if not.
    432  * @param   pszCaCertFile   The path to the certificate file.
     492 * @returns Number of wanted certifcates we've found.
     493 * @param   pafFoundCerts       Array parallel to s_aCerts with the status of
     494 *                              each wanted certificate.
    433495 */
    434 /*static*/ bool
    435 UINetworkReplyPrivateThread::checkCertificatesInFile(const char *pszCaCertFile)
    436 {
    437     bool fFoundCerts = false;
    438 
    439     /*
    440      * Check whether the file exists.
    441      */
    442     RTFSOBJINFO Info;
    443     int rc = RTPathQueryInfoEx(pszCaCertFile, &Info, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
    444     if (   RT_SUCCESS(rc)
    445         && RTFS_IS_FILE(Info.Attr.fMode))
    446     {
    447         /*
    448          * Load the CA certificate file into a store and use
    449          * checkCertificatesInStore to do the real work.
    450          */
    451         RTCRSTORE hStore;
    452         int rc = RTCrStoreCreateInMem(&hStore, 256);
    453         if (RT_SUCCESS(rc))
    454         {
    455             RTERRINFOSTATIC StaticErrInfo;
    456             rc = RTCrStoreCertAddFromFile(hStore, RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR, pszCaCertFile,
    457                                           RTErrInfoInitStatic(&StaticErrInfo));
    458             if (RTErrInfoIsSet(&StaticErrInfo.Core))
    459                 LogRel(("checkCertificates: %s\n", StaticErrInfo.Core.pszMsg));
    460             else
    461                 AssertRC(rc);
    462 
    463             unsigned cCertificates = 0;
    464             fFoundCerts = checkCertificatesInStore(hStore, &cCertificates);
    465 
    466             RTCrStoreRelease(hStore);
    467 
    468             /*
    469              * If there are more than two certificates in the database, we're looking
    470              * at a mirror of the system CA stores.  Refresh our snapshot once every 28 days.
    471              */
    472             RTTIMESPEC MaxAge;
    473             if (   fFoundCerts
    474                 && cCertificates > 2
    475                 && RTTimeSpecCompare(&Info.ModificationTime, RTTimeSpecSubSeconds(RTTimeNow(&MaxAge), 28 *24*3600)) < 0)
    476                 fFoundCerts = false;
    477         }
    478     }
    479 
    480     return fFoundCerts;
     496/*static*/ unsigned
     497UINetworkReplyPrivateThread::countCertsFound(bool const *pafFoundCerts)
     498{
     499    unsigned cFound = 0;
     500    for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
     501        cFound += pafFoundCerts[i];
     502    return cFound;
    481503}
    482504
     
    485507 *
    486508 * @returns true if we have, false if we haven't.
    487  * @param   fFoundCerts         The mask of found certificates (see
    488  *                              certEntryFoundMask).
     509 * @param   pafFoundCerts       Array parallel to s_aCerts with the status of
     510 *                              each wanted certificate.
    489511 * @param   fOnlyMandatory      Only require mandatory certificates to be
    490512 *                              present.  If false, all certificates must be
     
    492514 */
    493515/*static*/ bool
    494 UINetworkReplyPrivateThread::allCertsFound(uint64_t fFoundCerts, bool fOnlyMandatory)
    495 {
    496     AssertCompile(RT_ELEMENTS(s_aCerts) < 64);
    497 
    498     /* Add non-mandatory flags before comparing. */
    499     if (   fOnlyMandatory
    500         && fFoundCerts != RT_BIT_64(RT_ELEMENTS(s_aCerts)) - UINT64_C(1))
     516UINetworkReplyPrivateThread::areAllCertsFound(bool const *pafFoundCerts, bool fOnlyMandatory)
     517{
     518    if (fOnlyMandatory)
     519    {
    501520        for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
    502             if (!s_aCerts[i].fMandatory)
    503                 fFoundCerts |= RT_BIT_64(i);
    504 
    505     return fFoundCerts == RT_BIT_64(RT_ELEMENTS(s_aCerts)) - UINT64_C(1);
    506 }
    507 
    508 /**
    509  * Calculates the 64-bit 'found' mask for a certificate entry.
    510  *
    511  * @returns 64-bit mask.
    512  * @param   iCert               The certificate entry.
    513  */
    514 /*static*/ uint64_t
    515 UINetworkReplyPrivateThread::certEntryFoundMask(uint32_t iCert)
    516 {
    517     Assert(iCert < RT_ELEMENTS(s_aCerts));
    518     uint64_t fMask = RT_BIT_64(iCert);
    519 
     521            if (   !pafFoundCerts[i]
     522                && ((const CERTINFO *)s_aCerts[i].pvUser)->fMandatory)
     523                return false;
     524    }
     525    else
     526        for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
     527            if (!pafFoundCerts[i])
     528                return false;
     529    return true;
     530}
     531
     532/*static*/ void
     533UINetworkReplyPrivateThread::refreshCertificates(RTHTTP hHttp, RTCRSTORE hOldStore, bool *pafOldFoundCerts,
     534                                                 const char *pszCaCertFile)
     535{
    520536    /*
    521      * Tedium: Also mark certificates that this is an alternative to, we only need
    522      *         the public key once.
     537     * Collect the standard assortment of SSL certificates.
    523538     */
    524     uint8_t iAlt = s_aCerts[iCert].iAlternativeTo;
    525     if (iAlt != UINT8_MAX)
    526     {
    527         unsigned cMax = 10;
    528         do
    529         {
    530             Assert(iAlt < RT_ELEMENTS(s_aCerts));
    531             Assert(cMax > 1);
    532             Assert(strcmp(s_aCerts[iAlt].pszSubject, s_aCerts[iCert].pszSubject) == 0);
    533             fMask |= RT_BIT_64(iAlt);
    534             iAlt = s_aCerts[iAlt].iAlternativeTo;
    535         } while (iAlt != iCert && cMax-- > 0);
    536     }
    537 
    538     return fMask;
    539 }
    540 
    541 /**
    542  * Checks if the certificates we desire are all present in the given store.
    543  *
    544  * @returns true if present, false if not.
    545  * @param   hStore              The store to examine.
    546  * @param   pcCertificates      Where to return the number of certificates in
    547  *                              the store. Optional.
    548  */
    549 /* static */ bool
    550 UINetworkReplyPrivateThread::checkCertificatesInStore(RTCRSTORE hStore, unsigned *pcCertificates /* = NULL*/)
    551 {
    552     if (pcCertificates)
    553         *pcCertificates = 0;
    554 
    555     /*
    556      * Enumerate the store, checking for the certificates we need.
    557      */
    558     RTCRSTORECERTSEARCH Search;
    559     int rc = RTCrStoreCertFindAll(hStore, &Search);
     539    uint32_t  cHint = RTCrStoreCertCount(hOldStore);
     540    RTCRSTORE hNewStore;
     541    int rc = RTCrStoreCreateInMem(&hNewStore, cHint > 32 && cHint < _32K ? cHint + 16 : 256);
    560542    if (RT_SUCCESS(rc))
    561543    {
    562         uint64_t      fFoundCerts   = 0;
    563         unsigned      cCertificates = 0;
    564         PCRTCRCERTCTX pCertCtx;
    565         while ((pCertCtx = RTCrStoreCertSearchNext(hStore, &Search)) != NULL)
    566         {
    567             if (   (pCertCtx->fFlags & RTCRCERTCTX_F_ENC_MASK) == RTCRCERTCTX_F_ENC_X509_DER
    568                 && pCertCtx->cbEncoded > 0
    569                 && pCertCtx->pCert)
     544        RTERRINFOSTATIC StaticErrInfo;
     545        rc = RTHttpGatherCaCertsInStore(hNewStore, 0 /*fFlags*/, RTErrInfoInitStatic(&StaticErrInfo));
     546        if (RTErrInfoIsSet(&StaticErrInfo.Core))
     547            LogRel(("refreshCertificates/#1: %s\n", StaticErrInfo.Core.pszMsg));
     548        else
     549            AssertLogRelRC(rc);
     550
     551        if (RT_SUCCESS(rc))
     552        {
     553            /*
     554             * Check and see what we've got.  If we haven't got all we desire,
     555             * try add it from the previous store.
     556             */
     557            bool afNewFoundCerts[RT_ELEMENTS(s_aCerts)];
     558            RT_ZERO(afNewFoundCerts); /* paranoia */
     559
     560            rc = RTCrStoreCertCheckWanted(hNewStore, s_aCerts, RT_ELEMENTS(s_aCerts), afNewFoundCerts);
     561            AssertLogRelRC(rc);
     562            Assert(rc != VINF_SUCCESS || areAllCertsFound(afNewFoundCerts, false /*fOnlyMandatory*/));
     563            if (rc != VINF_SUCCESS)
    570564            {
    571                 cCertificates++;
    572 
    573                 /*
    574                  * It is a X.509 certificate.  Check if it matches any of those we're looking for.
    575                  */
    576                 for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
    577                     if (   pCertCtx->cbEncoded == s_aCerts[i].cbEncoded
    578                         && RTCrX509Name_MatchWithString(&pCertCtx->pCert->TbsCertificate.Subject, s_aCerts[i].pszSubject))
    579                     {
    580                         if (RTSha1Check(pCertCtx->pabEncoded, pCertCtx->cbEncoded, s_aCerts[i].abSha1))
    581                         {
    582                             if (RTSha512Check(pCertCtx->pabEncoded, pCertCtx->cbEncoded, s_aCerts[i].abSha512))
    583                             {
    584                                 fFoundCerts |= certEntryFoundMask(i);
    585                                 break;
    586                             }
    587                         }
    588                     }
     565                rc = RTCrStoreCertAddWantedFromStore(hNewStore,
     566                                                     RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR,
     567                                                     hOldStore, s_aCerts, RT_ELEMENTS(s_aCerts), afNewFoundCerts);
     568                AssertLogRelRC(rc);
     569                Assert(rc != VINF_SUCCESS || areAllCertsFound(afNewFoundCerts, false /*fOnlyMandatory*/));
    589570            }
    590             RTCrCertCtxRelease(pCertCtx);
     571
     572            /*
     573             * If that didn't help, seek out certificates in more obscure places,
     574             * like java, mozilla and mutt.
     575             */
     576            if (rc != VINF_SUCCESS)
     577            {
     578                rc = RTCrStoreCertAddWantedFromFishingExpedition(hNewStore,
     579                                                                 RTCRCERTCTX_F_ADD_IF_NOT_FOUND
     580                                                                 | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR,
     581                                                                 s_aCerts, RT_ELEMENTS(s_aCerts), afNewFoundCerts,
     582                                                                 RTErrInfoInitStatic(&StaticErrInfo));
     583                if (RTErrInfoIsSet(&StaticErrInfo.Core))
     584                    LogRel(("refreshCertificates/#2: %s\n", StaticErrInfo.Core.pszMsg));
     585                Assert(rc != VINF_SUCCESS || areAllCertsFound(afNewFoundCerts, false /*fOnlyMandatory*/));
     586            }
     587
     588            /*
     589             * If that didn't help, try download the certificates.
     590             */
     591            if (rc != VINF_SUCCESS)
     592                downloadMissingCertificates(hNewStore, afNewFoundCerts, hHttp, &StaticErrInfo);
     593
     594            /*
     595             * If we've got the same or better hit rate than the old store,
     596             * replace the CA certs file.
     597             */
     598            if (   areAllCertsFound(afNewFoundCerts, false /*fOnlyMandatory*/)
     599                || (   countCertsFound(afNewFoundCerts) >= countCertsFound(pafOldFoundCerts)
     600                    &&    areAllCertsFound(afNewFoundCerts, true /*fOnlyMandatory*/)
     601                       >= areAllCertsFound(pafOldFoundCerts, true /*fOnlyMandatory*/) ) )
     602            {
     603                rc = RTCrStoreCertExportAsPem(hNewStore, 0 /*fFlags*/, pszCaCertFile);
     604                if (RT_SUCCESS(rc))
     605                    memcpy(pafOldFoundCerts, afNewFoundCerts, sizeof(afNewFoundCerts));
     606                else
     607                    RT_ZERO(pafOldFoundCerts);
     608            }
    591609        }
    592         int rc2 = RTCrStoreCertSearchDestroy(hStore, &Search); AssertRC(rc2);
    593 
    594         /*
    595          * Set the certificate count.
    596          */
    597         if (pcCertificates)
    598             *pcCertificates = cCertificates;
    599 
    600         /*
    601          * Did we locate all of them?
    602          */
    603         if (allCertsFound(fFoundCerts, true /* fOnlyMandatory */)) /** @todo combine the two certificate retrieval approaches */
    604             return true;
    605     }
    606     AssertRC(rc);
    607     return false;
    608 }
    609 
    610 /*static*/ int
    611 UINetworkReplyPrivateThread::downloadCertificates(RTHTTP hHttp, const char *pszCaCertFile)
    612 {
    613     /*
    614      * Prepare temporary certificate store.
    615      */
    616     RTCRSTORE hStore;
    617     int rc = RTCrStoreCreateInMem(&hStore, RT_ELEMENTS(s_aCerts));
    618     AssertRCReturn(rc, rc);
    619 
    620     /*
    621      * Accounts for certificates we've downloaded, verified and added to the store.
    622      */
    623     uint64_t fFoundCerts = 0;
    624     AssertCompile(RT_ELEMENTS(s_aCerts) < 64);
     610        RTCrStoreRelease(hNewStore);
     611    }
     612}
     613
     614/*static*/ void
     615UINetworkReplyPrivateThread::downloadMissingCertificates(RTCRSTORE hNewStore, bool *pafNewFoundCerts, RTHTTP hHttp,
     616                                                         PRTERRINFOSTATIC pStaticErrInfo)
     617{
     618    int rc;
    625619
    626620    /*
     
    640634        {
    641635            for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
    642                 if (s_aCerts[i].pszZipFile)
     636                if (!pafNewFoundCerts[i])
    643637                {
    644                     void  *pvFile;
    645                     size_t cbFile;
    646                     rc = RTZipPkzipMemDecompress(&pvFile, &cbFile, pvRootsZip, cbRootsZip, s_aCerts[i].pszZipFile);
    647                     if (RT_SUCCESS(rc))
     638                    CERTINFO const *pInfo = (CERTINFO const *)s_aCerts[i].pvUser;
     639                    if (pInfo->pszZipFile)
    648640                    {
    649                         rc = convertVerifyAndAddPemCertificateToStore(hStore, pvFile, cbFile, &s_aCerts[i]);
    650                         RTMemFree(pvFile);
     641                        void  *pvFile;
     642                        size_t cbFile;
     643                        rc = RTZipPkzipMemDecompress(&pvFile, &cbFile, pvRootsZip, cbRootsZip, pInfo->pszZipFile);
    651644                        if (RT_SUCCESS(rc))
    652                             fFoundCerts |= certEntryFoundMask(i);
     645                        {
     646                            rc = convertVerifyAndAddPemCertificateToStore(hNewStore, pvFile, cbFile, &s_aCerts[i]);
     647                            RTMemFree(pvFile);
     648                            if (RT_SUCCESS(rc))
     649                            {
     650                                /*
     651                                 * Successfully added. Mark it as found and return if we've got them all.
     652                                 */
     653                                pafNewFoundCerts[i] = true;
     654                                if (areAllCertsFound(pafNewFoundCerts, false /* fOnlyMandatory */))
     655                                {
     656                                    RTHttpFreeResponse(pvRootsZip);
     657                                    return;
     658                                }
     659                            }
     660                        }
    653661                    }
    654662                }
    655663            RTHttpFreeResponse(pvRootsZip);
    656             if (allCertsFound(fFoundCerts, false /* fOnlyMandatory */))
    657                 break;
    658664        }
    659665    }
    660666
    661667    /*
    662      * Fallback: Try download certificates separately.
     668     * Try download certificates separately.
    663669     */
    664     if (allCertsFound(fFoundCerts, false /* fOnlyMandatory */))
    665         for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
    666             if (!(fFoundCerts & RT_BIT_64(i)))
    667                 for (uint32_t iUrl = 0; iUrl < RT_ELEMENTS(s_aCerts[i].apszUrls); i++)
    668                     if (s_aCerts[i].apszUrls[iUrl])
     670    for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
     671        if (!pafNewFoundCerts[i])
     672        {
     673            CERTINFO const *pInfo = (CERTINFO const *)s_aCerts[i].pvUser;
     674            for (uint32_t iUrl = 0; iUrl < RT_ELEMENTS(pInfo->apszUrls); i++)
     675                if (pInfo->apszUrls[iUrl])
     676                {
     677                    void  *pvResponse;
     678                    size_t cbResponse;
     679                    rc = RTHttpGetBinary(hHttp, pInfo->apszUrls[iUrl], &pvResponse, &cbResponse);
     680                    if (RT_SUCCESS(rc))
    669681                    {
    670                         void  *pvResponse;
    671                         size_t cbResponse;
    672                         rc = RTHttpGetBinary(hHttp, s_aCerts[i].apszUrls[iUrl], &pvResponse, &cbResponse);
     682                        rc = convertVerifyAndAddPemCertificateToStore(hNewStore, pvResponse, cbResponse, &s_aCerts[i]);
     683                        RTHttpFreeResponse(pvResponse);
    673684                        if (RT_SUCCESS(rc))
    674685                        {
    675                             rc = convertVerifyAndAddPemCertificateToStore(hStore, pvResponse, cbResponse, &s_aCerts[i]);
    676                             RTHttpFreeResponse(pvResponse);
    677                             if (RT_SUCCESS(rc))
    678                             {
    679                                 fFoundCerts |= certEntryFoundMask(i);
    680                                 break;
    681                             }
     686                            pafNewFoundCerts[i] = true;
     687                            break;
    682688                        }
    683689                    }
    684 
    685     /*
    686      * See if we've got the certificates we want, save it we do.
    687      */
    688     if (allCertsFound(fFoundCerts, true /*fOnlyMandatory*/))
    689         rc = RTCrStoreCertExportAsPem(hStore, 0 /*fFlags*/, pszCaCertFile);
    690     else if (RT_SUCCESS(rc))
    691         rc = VERR_NOT_FOUND;
    692 
    693     RTCrStoreRelease(hStore);
    694     return rc;
     690                }
     691        }
    695692}
    696693
     
    703700 * @param   pvResponse          The raw PEM certificate file bytes.
    704701 * @param   cbResponse          The number of bytes.
    705  * @param   pCertInfo           The certificate info (we use hashes and encoded
     702 * @param   pWantedCert         The certificate info (we use hashes and encoded
    706703 *                              size).
    707704 */
     
    709706UINetworkReplyPrivateThread::convertVerifyAndAddPemCertificateToStore(RTCRSTORE hStore,
    710707                                                                      void const *pvResponse, size_t cbResponse,
    711                                                                       const CERTINFO *pCertInfo)
     708                                                                      PCRTCRCERTWANTED pWantedCert)
    712709{
    713710    /*
     
    730727        rc = VERR_NOT_FOUND;
    731728        for (PCRTCRPEMSECTION pCur = pSectionHead; pCur; pCur = pCur->pNext)
    732             if (pCur->cbData == pCertInfo->cbEncoded)
     729            if (pCur->cbData == pWantedCert->cbEncoded)
    733730            {
    734                 if (   RTSha1Check(pCur->pbData, pCur->cbData, pCertInfo->abSha1)
    735                     && RTSha512Check(pCur->pbData, pCur->cbData, pCertInfo->abSha512))
     731                if (   RTSha1Check(pCur->pbData, pCur->cbData, pWantedCert->abSha1)
     732                    && RTSha512Check(pCur->pbData, pCur->cbData, pWantedCert->abSha512))
    736733                {
    737734                    /*
     
    754751            else
    755752                LogRel(("convertVerifyAndAddPemCertificateToStore: cbData=%#zx expected %#zx\n",
    756                         pCur->cbData, pCertInfo->cbEncoded));
     753                        pCur->cbData, pWantedCert->cbEncoded));
    757754
    758755        RTCrPemFreeSections(pSectionHead);
     
    760757    return rc;
    761758}
    762 
    763 /**
    764  * Tries to retrieve an up to date list of certificates from the system that
    765  * includes the necessary certs.
    766  *
    767  * @returns IPRT status code, success indicating that we've found what we need.
    768  * @param   pszCaCertFile           Where to store the certificates.
    769  */
    770 /*static*/ int
    771 UINetworkReplyPrivateThread::retrieveCertificatesFromSystem(const char *pszCaCertFile)
    772 {
    773     /*
    774      * Duplicate the user and system stores.
    775      */
    776     RTERRINFOSTATIC StaticErrInfo;
    777     RTCRSTORE hUserStore;
    778     int rc = RTCrStoreCreateSnapshotById(&hUserStore, RTCRSTOREID_USER_TRUSTED_CAS_AND_CERTIFICATES,
    779                                          RTErrInfoInitStatic(&StaticErrInfo));
    780     if (RT_FAILURE(rc))
    781         hUserStore = NIL_RTCRSTORE;
    782     if (RTErrInfoIsSet(&StaticErrInfo.Core))
    783         LogRel(("retrieveCertificatesFromSystem/#1: %s\n", StaticErrInfo.Core.pszMsg));
    784 
    785     RTCRSTORE hSystemStore;
    786     rc = RTCrStoreCreateSnapshotById(&hSystemStore, RTCRSTOREID_SYSTEM_TRUSTED_CAS_AND_CERTIFICATES,
    787                                      RTErrInfoInitStatic(&StaticErrInfo));
    788     if (RT_FAILURE(rc))
    789         hUserStore = NIL_RTCRSTORE;
    790     if (RTErrInfoIsSet(&StaticErrInfo.Core))
    791         LogRel(("retrieveCertificatesFromSystem/#2: %s\n", StaticErrInfo.Core.pszMsg));
    792 
    793     /*
    794      * Merge the two.
    795      */
    796     int rc2 = RTCrStoreCertAddFromStore(hUserStore, RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR,
    797                                         hSystemStore);
    798     AssertRC(rc2);
    799     RTCrStoreRelease(hSystemStore);
    800     hSystemStore = NIL_RTCRSTORE;
    801 
    802     /*
    803      * See if we've got the certificates we want, save it we do.
    804      */
    805     if (checkCertificatesInStore(hUserStore))
    806         rc = RTCrStoreCertExportAsPem(hUserStore, 0 /*fFlags*/, pszCaCertFile);
    807     else
    808         rc = VERR_NOT_FOUND;
    809     RTCrStoreRelease(hUserStore);
    810     return rc;
    811 }
    812 
    813759
    814760
  • trunk/src/VBox/Runtime/Makefile.kmk

    r57586 r57613  
    368368        common/crypto/store.cpp \
    369369        common/crypto/store-inmem.cpp \
    370         common/crypto/RTCrStoreCertAddFromFile.cpp \
    371         common/crypto/RTCrStoreCertAddFromDir.cpp \
    372         common/crypto/RTCrStoreCertAddFromStore.cpp \
     370        common/crypto/store-cert-add-basic.cpp \
    373371        common/crypto/RTCrStoreCertAddFromJavaKeyStore.cpp \
     372        common/crypto/RTCrStoreCertAddWantedFromFishingExpedition.cpp \
    374373        common/crypto/RTCrStoreCertExportAsPem.cpp \
    375374        common/dbg/dbg.cpp \
     
    465464        common/path/RTPathExt.cpp \
    466465        common/path/RTPathFilename.cpp \
     466        common/path/RTPathGlob.cpp \
    467467        common/path/RTPathHasExt.cpp \
    468468        common/path/RTPathHasPath.cpp \
  • trunk/src/VBox/Runtime/common/crypto/store-cert-add-basic.cpp

    r57607 r57613  
    3333
    3434#include <iprt/assert.h>
     35#include <iprt/crypto/pem.h>
    3536#include <iprt/dir.h>
    3637#include <iprt/err.h>
     38#include <iprt/file.h>
     39#include <iprt/mem.h>
    3740#include <iprt/path.h>
     41#include <iprt/sha.h>
    3842#include <iprt/string.h>
     43
     44#include "x509-internal.h"
     45
     46
     47/*********************************************************************************************************************************
     48*   Global Variables                                                                                                             *
     49*********************************************************************************************************************************/
     50/** BEGIN CERTIFICATE / END CERTIFICATE. */
     51static RTCRPEMMARKERWORD const g_aWords_Certificate[] =
     52{
     53    { RT_STR_TUPLE("CERTIFICATE") }
     54};
     55
     56/** BEGIN TRUSTED CERTIFICATE / END TRUSTED CERTIFICATE. */
     57static RTCRPEMMARKERWORD const g_aWords_TrustedCertificate[] =
     58{
     59    { RT_STR_TUPLE("TRUSTED") },
     60    { RT_STR_TUPLE("CERTIFICATE") }
     61};
     62
     63/** BEGIN X509 CERTIFICATE / END X509 CERTIFICATE. (old) */
     64static RTCRPEMMARKERWORD const g_aWords_X509Certificate[] =
     65{
     66    { RT_STR_TUPLE("X509") },
     67    { RT_STR_TUPLE("CERTIFICATE") }
     68};
     69
     70/**
     71 * X509 Certificate markers.
     72 *
     73 * @remark See crypto/pem/pem.h in OpenSSL for a matching list.
     74 */
     75RTCRPEMMARKER const g_aX509CertificateMarkers[3] =
     76{
     77    { g_aWords_Certificate,         RT_ELEMENTS(g_aWords_Certificate) },
     78    { g_aWords_TrustedCertificate,  RT_ELEMENTS(g_aWords_TrustedCertificate) },
     79    { g_aWords_X509Certificate,     RT_ELEMENTS(g_aWords_X509Certificate) }
     80};
     81
     82
     83
     84/**
     85 * Checks if we've found all the certificates already.
     86 *
     87 * @returns true if all found, false if not.
     88 * @param   afFound             Indicator array.
     89 * @param   cWanted             Number of wanted certificates.
     90 */
     91DECLINLINE(bool) rtCrStoreAllDone(bool const *afFound, size_t cWanted)
     92{
     93    while (cWanted-- > 0)
     94        if (!afFound[cWanted])
     95            return false;
     96    return true;
     97}
     98
     99
     100/**
     101 * Checks if the given certificate specs matches the given wanted poster.
     102 *
     103 * @returns true if match, false if not.
     104 * @param   pWanted     The certificate wanted poster.
     105 * @param   cbEncoded   The candidate certificate encoded size.
     106 * @param   paSha1      The candidate certificate SHA-1 fingerprint.
     107 * @param   paSha512    The candidate certificate SHA-512 fingerprint.
     108 * @param   pCert       The decoded candidate certificate, optional.  If not
     109 *                      given the result will be uncertain.
     110 */
     111DECLINLINE(bool) rtCrStoreIsCertEqualToWanted(PCRTCRCERTWANTED pWanted,
     112                                              size_t cbEncoded,
     113                                              uint8_t const pabSha1[RTSHA1_HASH_SIZE],
     114                                              uint8_t const pabSha512[RTSHA512_HASH_SIZE],
     115                                              PCRTCRX509CERTIFICATE pCert)
     116{
     117    if (   pWanted->cbEncoded != cbEncoded
     118        && pWanted->cbEncoded != 0)
     119        return false;
     120
     121    if (   pWanted->fSha1Fingerprint
     122        && memcmp(pWanted->abSha1, pabSha1, RTSHA1_HASH_SIZE) != 0)
     123        return false;
     124
     125    if (   pWanted->fSha512Fingerprint
     126        && memcmp(pWanted->abSha512, pabSha512, RTSHA512_HASH_SIZE) != 0)
     127        return false;
     128
     129    if (   pWanted->pszSubject
     130        && pCert
     131        && !RTCrX509Name_MatchWithString(&pCert->TbsCertificate.Subject, pWanted->pszSubject))
     132        return false;
     133
     134    return true;
     135}
     136
     137
     138/**
     139 * Checks if a certificate is wanted.
     140 *
     141 * @returns true if match, false if not.
     142 * @param   paWanted    The certificate wanted posters.
     143 * @param   cWanted     The number of wanted posters.
     144 * @param   apfFound    Found initicators running paralell to @a paWanted.
     145 * @param   cbEncoded   The candidate certificate encoded size.
     146 * @param   paSha1      The candidate certificate SHA-1 fingerprint.
     147 * @param   paSha512    The candidate certificate SHA-512 fingerprint.
     148 * @param   pCert       The decoded candidate certificate, optional.  If not
     149 *                      given the result will be uncertain.
     150 */
     151DECLINLINE(bool) rtCrStoreIsCertWanted(PCRTCRCERTWANTED paWanted, size_t cWanted, bool const *pafFound, size_t cbEncoded,
     152                                       uint8_t const pabSha1[RTSHA1_HASH_SIZE], uint8_t const pabSha512[RTSHA512_HASH_SIZE],
     153                                       PCRTCRX509CERTIFICATE pCert)
     154{
     155    for (size_t iCert = 0; iCert < cWanted; iCert++)
     156        if (!pafFound[iCert])
     157            if (rtCrStoreIsCertEqualToWanted(&paWanted[iCert], cbEncoded, pabSha1, pabSha512, pCert))
     158                return true;
     159    return false;
     160}
     161
     162
     163/**
     164 * Marks a certificate as found after it has been added to the store.
     165 *
     166 * May actually mark several certificates as found if there are duplicates or
     167 * ambiguities in the wanted list.
     168 *
     169 * @returns true if all have been found, false if more to search for.
     170 *
     171 * @param   apfFound    Found initicators running paralell to @a paWanted.
     172 *                      This is what this function updates.
     173 * @param   paWanted    The certificate wanted posters.
     174 * @param   cWanted     The number of wanted posters.
     175 * @param   cbEncoded   The candidate certificate encoded size.
     176 * @param   paSha1      The candidate certificate SHA-1 fingerprint.
     177 * @param   paSha512    The candidate certificate SHA-512 fingerprint.
     178 * @param   pCert       The decoded candidate certificate, optional.  If not
     179 *                      given the result will be uncertain.
     180 */
     181static bool rtCrStoreMarkCertFound(bool *pafFound, PCRTCRCERTWANTED paWanted, size_t cWanted, size_t cbEncoded,
     182                                   uint8_t const pabSha1[RTSHA1_HASH_SIZE], uint8_t const pabSha512[RTSHA512_HASH_SIZE],
     183                                   PCRTCRX509CERTIFICATE pCert)
     184{
     185    size_t cFound = 0;
     186    for (size_t iCert = 0; iCert < cWanted; iCert++)
     187        if (pafFound[iCert])
     188            cFound++;
     189        else if (rtCrStoreIsCertEqualToWanted(&paWanted[iCert], cbEncoded, pabSha1, pabSha512, pCert))
     190        {
     191            pafFound[iCert] = true;
     192            cFound++;
     193        }
     194    return cFound == cWanted;
     195}
     196
     197
     198RTDECL(int) RTCrStoreCertAddFromStore(RTCRSTORE hStore, uint32_t fFlags, RTCRSTORE hStoreSrc)
     199{
     200    /*
     201     * Validate input.
     202     */
     203    AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
     204
     205    /*
     206     * Enumerate all the certificates in the source store, adding them to the destination.
     207     */
     208    RTCRSTORECERTSEARCH Search;
     209    int rc = RTCrStoreCertFindAll(hStoreSrc, &Search);
     210    if (RT_SUCCESS(rc))
     211    {
     212        PCRTCRCERTCTX pCertCtx;
     213        while ((pCertCtx = RTCrStoreCertSearchNext(hStoreSrc, &Search)) != NULL)
     214        {
     215            int rc2 = RTCrStoreCertAddEncoded(hStore, pCertCtx->fFlags | (fFlags & RTCRCERTCTX_F_ADD_IF_NOT_FOUND),
     216                                              pCertCtx->pabEncoded, pCertCtx->cbEncoded, NULL);
     217            if (RT_FAILURE(rc2))
     218            {
     219                rc = rc2;
     220                if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
     221                    break;
     222            }
     223            RTCrCertCtxRelease(pCertCtx);
     224        }
     225
     226        int rc2 = RTCrStoreCertSearchDestroy(hStoreSrc, &Search); AssertRC(rc2);
     227    }
     228    return rc;
     229}
     230RT_EXPORT_SYMBOL(RTCrStoreCertAddFromStore);
     231
     232
     233RTDECL(int) RTCrStoreCertAddWantedFromStore(RTCRSTORE hStore, uint32_t fFlags, RTCRSTORE hSrcStore,
     234                                            PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound)
     235{
     236    /*
     237     * Validate input a little.
     238     */
     239    AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
     240    fFlags |= RTCRCERTCTX_F_ADD_IF_NOT_FOUND; /* forced */
     241
     242    AssertReturn(cWanted, VERR_NOT_FOUND);
     243    for (uint32_t i = 0; i < cWanted; i++)
     244    {
     245        AssertReturn(!paWanted[i].pszSubject || *paWanted[i].pszSubject, VERR_INVALID_PARAMETER);
     246        AssertReturn(   paWanted[i].pszSubject
     247                     || paWanted[i].fSha1Fingerprint
     248                     || paWanted[i].fSha512Fingerprint,
     249                     VERR_INVALID_PARAMETER);
     250    }
     251
     252    /*
     253     * Make sure we've got a result array.
     254     */
     255    bool *pafFoundFree = NULL;
     256    if (!pafFound)
     257    {
     258        pafFound = pafFoundFree = (bool *)RTMemTmpAllocZ(sizeof(bool) * cWanted);
     259        AssertReturn(pafFound, VERR_NO_TMP_MEMORY);
     260    }
     261
     262    /*
     263     * Enumerate the store entries.
     264     */
     265    RTCRSTORECERTSEARCH Search;
     266    int rc = RTCrStoreCertFindAll(hSrcStore, &Search);
     267    if (RT_SUCCESS(rc))
     268    {
     269        rc = VWRN_NOT_FOUND;
     270        PCRTCRCERTCTX pCertCtx;
     271        while ((pCertCtx = RTCrStoreCertSearchNext(hSrcStore, &Search)) != NULL)
     272        {
     273            if (   (pCertCtx->fFlags & RTCRCERTCTX_F_ENC_MASK) == RTCRCERTCTX_F_ENC_X509_DER
     274                && pCertCtx->cbEncoded > 0
     275                && pCertCtx->pCert)
     276            {
     277                /*
     278                 * If the certificate is wanted, try add it to the store.
     279                 */
     280                uint8_t abSha1[RTSHA1_HASH_SIZE];
     281                RTSha1(pCertCtx->pabEncoded, pCertCtx->cbEncoded, abSha1);
     282                uint8_t abSha512[RTSHA512_HASH_SIZE];
     283                RTSha1(pCertCtx->pabEncoded, pCertCtx->cbEncoded, abSha512);
     284                if (rtCrStoreIsCertWanted(paWanted, cWanted, pafFound, pCertCtx->cbEncoded, abSha1, abSha512, pCertCtx->pCert))
     285                {
     286                    int rc2 = RTCrStoreCertAddEncoded(hStore,
     287                                                      RTCRCERTCTX_F_ENC_X509_DER | (fFlags & RTCRCERTCTX_F_ADD_IF_NOT_FOUND),
     288                                                      pCertCtx->pabEncoded, pCertCtx->cbEncoded, NULL /*pErrInfo*/);
     289                    if (RT_SUCCESS(rc2))
     290                    {
     291                        /*
     292                         * Mark it as found, stop if we've found all.
     293                         */
     294                        if (rtCrStoreMarkCertFound(pafFound, paWanted, cWanted,
     295                                                   pCertCtx->cbEncoded, abSha1, abSha512, pCertCtx->pCert))
     296                        {
     297                            if (RT_SUCCESS(rc))
     298                                rc = VINF_SUCCESS;
     299                            RTCrCertCtxRelease(pCertCtx);
     300                            break;
     301                        }
     302                    }
     303                    else
     304                    {
     305                        /*
     306                         * Some error adding the certificate.  Since it cannot be anything with
     307                         * the encoding, it must be something with the store or resources, so
     308                         * always return the error status.
     309                         */
     310                        rc = rc2;
     311                        if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
     312                        {
     313                            RTCrCertCtxRelease(pCertCtx);
     314                            break;
     315                        }
     316                    }
     317                }
     318            }
     319            RTCrCertCtxRelease(pCertCtx);
     320        }
     321        int rc2 = RTCrStoreCertSearchDestroy(hSrcStore, &Search);
     322        AssertRC(rc2);
     323    }
     324
     325    if (pafFoundFree)
     326        RTMemTmpFree(pafFoundFree);
     327    return rc;
     328}
     329RT_EXPORT_SYMBOL(RTCrStoreCertAddWantedFromStore);
     330
     331
     332RTDECL(int) RTCrStoreCertCheckWanted(RTCRSTORE hStore, PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound)
     333{
     334    /*
     335     * Validate input a little.
     336     */
     337    AssertReturn(cWanted, VERR_NOT_FOUND);
     338    for (uint32_t i = 0; i < cWanted; i++)
     339    {
     340        AssertReturn(!paWanted[i].pszSubject || *paWanted[i].pszSubject, VERR_INVALID_PARAMETER);
     341        AssertReturn(   paWanted[i].pszSubject
     342                     || paWanted[i].fSha1Fingerprint
     343                     || paWanted[i].fSha512Fingerprint,
     344                     VERR_INVALID_PARAMETER);
     345    }
     346    AssertPtrReturn(pafFound, VERR_INVALID_POINTER);
     347
     348    /*
     349     * Clear the found array.
     350     */
     351    for (uint32_t iCert = 0; iCert < cWanted; iCert++)
     352        pafFound[iCert] = false;
     353
     354    /*
     355     * Enumerate the store entries.
     356     */
     357    RTCRSTORECERTSEARCH Search;
     358    int rc = RTCrStoreCertFindAll(hStore, &Search);
     359    if (RT_SUCCESS(rc))
     360    {
     361        rc = VWRN_NOT_FOUND;
     362        PCRTCRCERTCTX pCertCtx;
     363        while ((pCertCtx = RTCrStoreCertSearchNext(hStore, &Search)) != NULL)
     364        {
     365            if (   (pCertCtx->fFlags & RTCRCERTCTX_F_ENC_MASK) == RTCRCERTCTX_F_ENC_X509_DER
     366                && pCertCtx->cbEncoded > 0
     367                && pCertCtx->pCert)
     368            {
     369                /*
     370                 * Hash it and check if it's wanted.  Stop when we've found all.
     371                 */
     372                uint8_t abSha1[RTSHA1_HASH_SIZE];
     373                RTSha1(pCertCtx->pabEncoded, pCertCtx->cbEncoded, abSha1);
     374                uint8_t abSha512[RTSHA512_HASH_SIZE];
     375                RTSha1(pCertCtx->pabEncoded, pCertCtx->cbEncoded, abSha512);
     376                if (rtCrStoreMarkCertFound(pafFound, paWanted, cWanted, pCertCtx->cbEncoded, abSha1, abSha512, pCertCtx->pCert))
     377                {
     378                    rc = VINF_SUCCESS;
     379                    RTCrCertCtxRelease(pCertCtx);
     380                    break;
     381                }
     382            }
     383            RTCrCertCtxRelease(pCertCtx);
     384        }
     385        int rc2 = RTCrStoreCertSearchDestroy(hStore, &Search);
     386        AssertRC(rc2);
     387    }
     388
     389    return rc;
     390}
     391RT_EXPORT_SYMBOL(RTCrStoreCertAddWantedFromStore);
     392
     393
     394RTDECL(int) RTCrStoreCertAddFromFile(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename, PRTERRINFO pErrInfo)
     395{
     396    AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
     397
     398    size_t      cbContent;
     399    void        *pvContent;
     400    int rc = RTFileReadAllEx(pszFilename, 0, 64U*_1M, RTFILE_RDALL_O_DENY_WRITE, &pvContent, &cbContent);
     401    if (RT_SUCCESS(rc))
     402    {
     403        /*
     404         * Is it a java key store file?
     405         */
     406        if (   cbContent > 32
     407            && ((uint32_t const *)pvContent)[0] == RT_H2BE_U32_C(UINT32_C(0xfeedfeed)) /* magic */
     408            && ((uint32_t const *)pvContent)[1] == RT_H2BE_U32_C(UINT32_C(0x00000002)) /* version */ )
     409            rc = RTCrStoreCertAddFromJavaKeyStoreInMem(hStore, fFlags, pvContent, cbContent, pszFilename, pErrInfo);
     410        /*
     411         * No assume PEM or DER encoded binary certificate.
     412         */
     413        else
     414        {
     415            PCRTCRPEMSECTION pSectionHead;
     416            rc = RTCrPemParseContent(pvContent, cbContent,
     417                                     (fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)
     418                                     ? RTCRPEMREADFILE_F_CONTINUE_ON_ENCODING_ERROR : 0,
     419                                     g_aX509CertificateMarkers, RT_ELEMENTS(g_aX509CertificateMarkers),
     420                                     &pSectionHead, pErrInfo);
     421            if (RT_SUCCESS(rc))
     422            {
     423                PCRTCRPEMSECTION pCurSec = pSectionHead;
     424                while (pCurSec)
     425                {
     426                    int rc2 = RTCrStoreCertAddEncoded(hStore,
     427                                                      RTCRCERTCTX_F_ENC_X509_DER | (fFlags & RTCRCERTCTX_F_ADD_IF_NOT_FOUND),
     428                                                      pCurSec->pbData, pCurSec->cbData,
     429                                                      !RTErrInfoIsSet(pErrInfo) ? pErrInfo : NULL);
     430                    if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
     431                    {
     432                        rc = rc2;
     433                        if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
     434                            break;
     435                    }
     436                    pCurSec = pCurSec->pNext;
     437                }
     438
     439                RTCrPemFreeSections(pSectionHead);
     440            }
     441        }
     442        RTFileReadAllFree(pvContent, cbContent);
     443    }
     444    else
     445        rc = RTErrInfoSetF(pErrInfo, rc, "RTFileReadAllEx failed with %Rrc on '%s'", rc, pszFilename);
     446    return rc;
     447}
     448RT_EXPORT_SYMBOL(RTCrStoreCertAddFromFile);
     449
     450
     451RTDECL(int) RTCrStoreCertAddWantedFromFile(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename,
     452                                           PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound, PRTERRINFO pErrInfo)
     453{
     454    /*
     455     * Validate input a little.
     456     */
     457    AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
     458    fFlags |= RTCRCERTCTX_F_ADD_IF_NOT_FOUND; /* forced */
     459
     460    AssertReturn(cWanted, VERR_NOT_FOUND);
     461    for (uint32_t i = 0; i < cWanted; i++)
     462    {
     463        AssertReturn(!paWanted[i].pszSubject || *paWanted[i].pszSubject, VERR_INVALID_PARAMETER);
     464        AssertReturn(   paWanted[i].pszSubject
     465                     || paWanted[i].fSha1Fingerprint
     466                     || paWanted[i].fSha512Fingerprint,
     467                     VERR_INVALID_PARAMETER);
     468    }
     469
     470    /*
     471     * Make sure we've got a result array.
     472     */
     473    bool *pafFoundFree = NULL;
     474    if (!pafFound)
     475    {
     476        pafFound = pafFoundFree = (bool *)RTMemTmpAllocZ(sizeof(bool) * cWanted);
     477        AssertReturn(pafFound, VERR_NO_TMP_MEMORY);
     478    }
     479
     480    size_t cbContent;
     481    void  *pvContent;
     482    int rc = RTFileReadAllEx(pszFilename, 0, 64U*_1M, RTFILE_RDALL_O_DENY_WRITE, &pvContent, &cbContent);
     483    if (RT_SUCCESS(rc))
     484    {
     485        /*
     486         * Is it a java key store file?   If so, load it into a tmp store
     487         * which we can search.  Don't want to duplicate the JKS reader code.
     488         */
     489        if (   cbContent > 32
     490            && ((uint32_t const *)pvContent)[0] == RT_H2BE_U32_C(UINT32_C(0xfeedfeed)) /* magic */
     491            && ((uint32_t const *)pvContent)[1] == RT_H2BE_U32_C(UINT32_C(0x00000002)) /* version */ )
     492        {
     493            RTCRSTORE hTmpStore;
     494            rc = RTCrStoreCreateInMem(&hTmpStore, 64);
     495            if (RT_SUCCESS(rc))
     496            {
     497                rc = RTCrStoreCertAddFromJavaKeyStoreInMem(hStore, fFlags, pvContent, cbContent, pszFilename, pErrInfo);
     498                if (RT_SUCCESS(rc))
     499                    rc = RTCrStoreCertAddWantedFromStore(hStore, fFlags, hTmpStore, paWanted, cWanted, pafFound);
     500                RTCrStoreRelease(hTmpStore);
     501            }
     502            else
     503                rc = RTErrInfoSet(pErrInfo, rc, "Error creating temporary crypto store");
     504        }
     505        /*
     506         * No assume PEM or DER encoded binary certificate.  Inspect them one by one.
     507         */
     508        else
     509        {
     510            PCRTCRPEMSECTION pSectionHead;
     511            rc = RTCrPemParseContent(pvContent, cbContent,
     512                                     (fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)
     513                                     ? RTCRPEMREADFILE_F_CONTINUE_ON_ENCODING_ERROR : 0,
     514                                     g_aX509CertificateMarkers, RT_ELEMENTS(g_aX509CertificateMarkers),
     515                                     &pSectionHead, pErrInfo);
     516            if (RT_SUCCESS(rc))
     517            {
     518                rc = VWRN_NOT_FOUND;
     519                for (PCRTCRPEMSECTION pCurSec = pSectionHead; pCurSec; pCurSec = pCurSec->pNext)
     520                {
     521                    if (!pCurSec->cbData)
     522                        continue;
     523
     524                    /*
     525                     * See if this is a binary blob we might be interested in.
     526                     */
     527                    uint8_t abSha1[RTSHA1_HASH_SIZE];
     528                    RTSha1(pCurSec->pbData, pCurSec->cbData, abSha1);
     529                    uint8_t abSha512[RTSHA512_HASH_SIZE];
     530                    RTSha1(pCurSec->pbData, pCurSec->cbData, abSha512);
     531                    if (!rtCrStoreIsCertWanted(paWanted, cWanted, pafFound, pCurSec->cbData, abSha1, abSha512, NULL))
     532                        continue;
     533
     534                    /*
     535                     * Decode the certificate so we can match the subject string.
     536                     */
     537                    RTASN1CURSORPRIMARY Cursor;
     538                    RTAsn1CursorInitPrimary(&Cursor, pCurSec->pbData, (uint32_t)pCurSec->cbData,
     539                                            !RTErrInfoIsSet(pErrInfo) ? pErrInfo : NULL,
     540                                            &g_RTAsn1DefaultAllocator, RTASN1CURSOR_FLAGS_DER, "InMem");
     541                    RTCRX509CERTIFICATE X509Cert;
     542                    int rc2 = RTCrX509Certificate_DecodeAsn1(&Cursor.Cursor, 0, &X509Cert, "Cert");
     543                    if (RT_SUCCESS(rc2))
     544                    {
     545                        rc2 = RTCrX509Certificate_CheckSanity(&X509Cert, 0, !RTErrInfoIsSet(pErrInfo) ? pErrInfo : NULL, "Cert");
     546                        if (RT_SUCCESS(rc2))
     547                        {
     548                            if (rtCrStoreIsCertWanted(paWanted, cWanted, pafFound, pCurSec->cbData, abSha1, abSha512, &X509Cert))
     549                            {
     550                                /*
     551                                 * The certificate is wanted, now add it to the store.
     552                                 */
     553                                rc2 = RTCrStoreCertAddEncoded(hStore,
     554                                                              RTCRCERTCTX_F_ENC_X509_DER
     555                                                              | (fFlags & RTCRCERTCTX_F_ADD_IF_NOT_FOUND),
     556                                                              pCurSec->pbData, pCurSec->cbData,
     557                                                              !RTErrInfoIsSet(pErrInfo) ? pErrInfo : NULL);
     558                                if (RT_SUCCESS(rc2))
     559                                {
     560                                    /*
     561                                     * Mark it as found, stop if we've found all.
     562                                     */
     563                                    if (rtCrStoreMarkCertFound(pafFound, paWanted, cWanted,
     564                                                               pCurSec->cbData, abSha1, abSha512, &X509Cert))
     565                                    {
     566                                        RTAsn1VtDelete(&X509Cert.SeqCore.Asn1Core);
     567                                        rc = VINF_SUCCESS;
     568                                        break;
     569                                    }
     570                                }
     571                            }
     572                        }
     573                        else
     574                            Assert(!pErrInfo || RTErrInfoIsSet(pErrInfo));
     575                        RTAsn1VtDelete(&X509Cert.SeqCore.Asn1Core);
     576                    }
     577                    else if (!RTErrInfoIsSet(pErrInfo))
     578                        RTErrInfoSetF(pErrInfo, rc2, "RTCrX509Certificate_DecodeAsn1 failed");
     579
     580                    /*
     581                     * Stop on error, if requested.  Otherwise, let pErrInfo keep it.
     582                     */
     583                    if (RT_FAILURE(rc2) && !(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
     584                    {
     585                        rc = rc2;
     586                        break;
     587                    }
     588                } /* For each PEM section. */
     589
     590                RTCrPemFreeSections(pSectionHead);
     591            }
     592        }
     593        RTFileReadAllFree(pvContent, cbContent);
     594    }
     595    else
     596        rc = RTErrInfoSetF(pErrInfo, rc, "RTFileReadAllEx failed with %Rrc on '%s'", rc, pszFilename);
     597
     598    if (pafFoundFree)
     599        RTMemTmpFree(pafFoundFree);
     600    return rc;
     601}
     602RT_EXPORT_SYMBOL(RTCrStoreCertAddWantedFromFile);
    39603
    40604
     
    88652        if (cchPath > 0)
    89653        {
    90             size_t const cbFilename = sizeof(szPath) - cchPath;
     654            size_t const cbMaxFilename = sizeof(szPath) - cchPath;
    91655
    92656            /*
     
    109673                    if (RT_SUCCESS(rc2))
    110674                    {
    111                         if (   !RTDirEntryIsStdDotLink(&u.DirEntry)
     675                        if (   (   u.DirEntry.enmType == RTDIRENTRYTYPE_FILE
     676                                || u.DirEntry.enmType == RTDIRENTRYTYPE_SYMLINK
     677                                || (   u.DirEntry.enmType == RTDIRENTRYTYPE_UNKNOWN
     678                                    && !RTDirEntryIsStdDotLink(&u.DirEntry)) )
    112679                            && rtCrStoreIsSuffixMatch(&u.DirEntry, paSuffixes, cSuffixes) )
    113680                        {
    114                             if (u.DirEntry.cbName < cbFilename)
     681                            if (u.DirEntry.cbName < cbMaxFilename)
    115682                            {
    116683                                memcpy(&szPath[cchPath], u.DirEntry.szName, u.DirEntry.cbName + 1);
     
    131698                                }
    132699                            }
    133                             else if (   u.DirEntry.enmType == RTDIRENTRYTYPE_FILE
    134                                      || u.DirEntry.enmType == RTDIRENTRYTYPE_SYMLINK
    135                                      || u.DirEntry.enmType == RTDIRENTRYTYPE_UNKNOWN)
     700                            else
    136701                            {
    137702                                rc = RTErrInfoAddF(pErrInfo, VERR_FILENAME_TOO_LONG,
     
    160725    return rc;
    161726}
    162 
    163 
     727RT_EXPORT_SYMBOL(RTCrStoreCertAddFromDir);
     728
     729
     730RTDECL(int) RTCrStoreCertAddWantedFromDir(RTCRSTORE hStore, uint32_t fFlags,
     731                                          const char *pszDir, PCRTSTRTUPLE paSuffixes, size_t cSuffixes,
     732                                          PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound, PRTERRINFO pErrInfo)
     733{
     734    /*
     735     * Validate input a little.
     736     */
     737    AssertReturn(*pszDir, VERR_PATH_ZERO_LENGTH);
     738    AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
     739    fFlags |= RTCRCERTCTX_F_ADD_IF_NOT_FOUND; /* forced */
     740
     741    AssertReturn(cWanted, VERR_NOT_FOUND);
     742    for (uint32_t i = 0; i < cWanted; i++)
     743    {
     744        AssertReturn(!paWanted[i].pszSubject || *paWanted[i].pszSubject, VERR_INVALID_PARAMETER);
     745        AssertReturn(   paWanted[i].pszSubject
     746                     || paWanted[i].fSha1Fingerprint
     747                     || paWanted[i].fSha512Fingerprint,
     748                     VERR_INVALID_PARAMETER);
     749    }
     750
     751    /*
     752     * Prepare for constructing path to the files in the directory, so that we
     753     * can open them.
     754     */
     755    char szPath[RTPATH_MAX];
     756    int rc = RTStrCopy(szPath, sizeof(szPath), pszDir);
     757    if (RT_SUCCESS(rc))
     758    {
     759        size_t cchPath = RTPathEnsureTrailingSeparator(szPath, sizeof(szPath));
     760        if (cchPath > 0)
     761        {
     762            size_t const cbMaxFilename = sizeof(szPath) - cchPath;
     763
     764            /*
     765             * Enumerate the directory.
     766             */
     767            PRTDIR hDir;
     768            rc = RTDirOpen(&hDir, pszDir);
     769            if (RT_SUCCESS(rc))
     770            {
     771                rc = VWRN_NOT_FOUND;
     772                for (;;)
     773                {
     774                    /* Read the next entry. */
     775                    union
     776                    {
     777                        RTDIRENTRY  DirEntry;
     778                        uint8_t     abPadding[RT_OFFSETOF(RTDIRENTRY, szName) + RTPATH_MAX];
     779                    } u;
     780                    size_t cbEntry = sizeof(u);
     781                    int rc2 = RTDirRead(hDir, &u.DirEntry, &cbEntry);
     782                    if (RT_SUCCESS(rc2))
     783                    {
     784                        if (   (   u.DirEntry.enmType == RTDIRENTRYTYPE_FILE
     785                                || u.DirEntry.enmType == RTDIRENTRYTYPE_SYMLINK
     786                                || (   u.DirEntry.enmType == RTDIRENTRYTYPE_UNKNOWN
     787                                    && !RTDirEntryIsStdDotLink(&u.DirEntry)) )
     788                            && rtCrStoreIsSuffixMatch(&u.DirEntry, paSuffixes, cSuffixes) )
     789                        {
     790                            if (u.DirEntry.cbName < cbMaxFilename)
     791                            {
     792                                memcpy(&szPath[cchPath], u.DirEntry.szName, u.DirEntry.cbName);
     793                                szPath[cchPath + u.DirEntry.cbName] = '\0';
     794                                if (u.DirEntry.enmType != RTDIRENTRYTYPE_FILE)
     795                                    RTDirQueryUnknownType(szPath, true /*fFollowSymlinks*/, &u.DirEntry.enmType);
     796                                if (u.DirEntry.enmType == RTDIRENTRYTYPE_FILE)
     797                                {
     798                                    rc2 = RTCrStoreCertAddWantedFromFile(hStore, fFlags, szPath,
     799                                                                         paWanted, cWanted, pafFound, pErrInfo);
     800                                    if (rc2 == VINF_SUCCESS)
     801                                    {
     802                                        Assert(rtCrStoreAllDone(pafFound, cWanted));
     803                                        if (RT_SUCCESS(rc))
     804                                            rc = VINF_SUCCESS;
     805                                        break;
     806                                    }
     807                                    if (RT_FAILURE(rc2) && !(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
     808                                    {
     809                                        rc = rc2;
     810                                        break;
     811                                    }
     812                                }
     813                            }
     814                            else
     815                            {
     816                                /*
     817                                 * pErrInfo keeps the status code unless it's fatal.
     818                                 */
     819                                RTErrInfoAddF(pErrInfo, VERR_FILENAME_TOO_LONG,
     820                                              "  Too long filename (%u bytes)", u.DirEntry.cbName);
     821                                if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
     822                                {
     823                                    rc = VERR_FILENAME_TOO_LONG;
     824                                    break;
     825                                }
     826                            }
     827                        }
     828                    }
     829                    else
     830                    {
     831                        if (rc2 != VERR_NO_MORE_FILES)
     832                        {
     833                            RTErrInfoAddF(pErrInfo, rc2, "RTDirRead failed: %Rrc", rc2);
     834                            if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
     835                                rc = rc2;
     836                        }
     837                        break;
     838                    }
     839                }
     840                RTDirClose(hDir);
     841            }
     842        }
     843        else
     844            rc = VERR_FILENAME_TOO_LONG;
     845    }
     846    return rc;
     847}
     848RT_EXPORT_SYMBOL(RTCrStoreCertAddWantedFromDir);
     849
  • trunk/src/VBox/Runtime/common/crypto/store.cpp

    r57572 r57613  
    288288
    289289
     290RTDECL(uint32_t) RTCrStoreCertCount(RTCRSTORE hStore)
     291{
     292    PRTCRSTOREINT pThis = (PRTCRSTOREINT)hStore;
     293    AssertPtrReturn(pThis, UINT32_MAX);
     294    AssertReturn(pThis->u32Magic == RTCRSTOREINT_MAGIC, UINT32_MAX);
     295
     296    RTCRSTORECERTSEARCH Search;
     297    int rc = pThis->pProvider->pfnCertFindAll(pThis->pvProvider, &Search);
     298    AssertRCReturn(rc, UINT32_MAX);
     299
     300
     301    uint32_t cCerts = 0;
     302    PCRTCRCERTCTX pCur;
     303    while ((pCur = pThis->pProvider->pfnCertSearchNext(pThis->pvProvider, &Search)) != NULL)
     304    {
     305        RTCrCertCtxRelease(pCur);
     306        cCerts++;
     307    }
     308
     309    return cCerts;
     310}
     311
     312
    290313#ifdef IPRT_WITH_OPENSSL
    291314/*
  • trunk/src/VBox/Runtime/common/crypto/x509-internal.h

    r56290 r57613  
    2929#define ___common_crypto_x509_internal_h
    3030
     31#include <iprt/crypto/pem.h>
     32extern RTCRPEMMARKER const g_aX509CertificateMarkers[3];
     33
    3134#define RTASN1TMPL_TEMPLATE_FILE "../common/crypto/x509-template.h"
    3235#include <iprt/asn1-generator-internal-header.h>
  • trunk/src/VBox/Runtime/common/misc/http.cpp

    r57577 r57613  
    3232#include "internal/iprt.h"
    3333
     34#include <iprt/asm.h>
    3435#include <iprt/assert.h>
     36#include <iprt/crypto/store.h>
    3537#include <iprt/env.h>
    3638#include <iprt/err.h>
     39#include <iprt/file.h>
    3740#include <iprt/mem.h>
     41#include <iprt/path.h>
     42#include <iprt/stream.h>
    3843#include <iprt/string.h>
    39 #include <iprt/file.h>
    40 #include <iprt/stream.h>
     44
     45#include "internal/magics.h"
    4146
    4247#include <curl/curl.h>
    43 #include "internal/magics.h"
    4448
    4549
     
    4751*   Structures and Typedefs                                                                                                      *
    4852*********************************************************************************************************************************/
     53/**
     54 * Internal HTTP client instance.
     55 */
    4956typedef struct RTHTTPINTERNAL
    5057{
     
    5259    uint32_t            u32Magic;
    5360    /** cURL handle. */
    54     CURL                *pCurl;
     61    CURL               *pCurl;
    5562    /** The last response code. */
    5663    long                lLastResp;
    57     /** custom headers */
    58     struct curl_slist   *pHeaders;
    59     /** CA certificate for HTTPS authentication check. */
    60     char                *pcszCAFile;
     64    /** Custom headers/ */
     65    struct curl_slist  *pHeaders;
     66    /** CA certificate file for HTTPS authentication. */
     67    char               *pszCaFile;
     68    /** Whether to delete the CA on destruction. */
     69    bool                fDeleteCaFile;
    6170    /** Abort the current HTTP request if true. */
    62     bool                fAbort;
     71    bool volatile       fAbort;
     72    /** Set if someone is preforming an HTTP operation. */
     73    bool volatile       fBusy;
    6374    /** The location field for 301 responses. */
    64     char                *pszRedirLocation;
     75    char               *pszRedirLocation;
     76
     77    /** Output callback data. */
     78    union
     79    {
     80        /** For file destination.  */
     81        RTFILE          hFile;
     82        /** For memory destination. */
     83        struct
     84        {
     85            /** The current size (sans terminator char). */
     86            size_t      cb;
     87            /** The currently allocated size. */
     88            size_t      cbAllocated;
     89            /** Pointer to the buffer. */
     90            uint8_t    *pb;
     91        } Mem;
     92    } Output;
     93    /** Output callback status. */
     94    int                 rcOutput;
     95    /** Download size hint set by the progress callback. */
     96    uint64_t            cbDownloadHint;
    6597} RTHTTPINTERNAL;
     98/** Pointer to an internal HTTP client instance. */
    6699typedef RTHTTPINTERNAL *PRTHTTPINTERNAL;
    67 
    68 typedef struct RTHTTPMEMCHUNK
    69 {
    70     uint8_t    *pu8Mem;
    71     size_t      cb;
    72 } RTHTTPMEMCHUNK;
    73 typedef RTHTTPMEMCHUNK *PRTHTTPMEMCHUNK;
    74100
    75101
     
    77103*   Defined Constants And Macros                                                                                                 *
    78104*********************************************************************************************************************************/
    79 #define CURL_FAILED(rcCurl) (RT_UNLIKELY(rcCurl != CURLE_OK))
     105/** @def RTHTTP_MAX_MEM_DOWNLOAD
     106 * The max size we are allowed to download to a memory buffer.
     107 *
     108 * @remarks The minus 1 is for the trailing zero terminator we always add.
     109 */
     110#if ARCH_BITS == 64
     111# define RTHTTP_MAX_MEM_DOWNLOAD_SIZE       (UINT32_C(64)*_1M - 1)
     112#else
     113# define RTHTTP_MAX_MEM_DOWNLOAD_SIZE       (UINT32_C(32)*_1M - 1)
     114#endif
     115
     116/** Checks whether a cURL return code indicates success. */
     117#define CURL_SUCCESS(rcCurl)    RT_LIKELY(rcCurl == CURLE_OK)
     118/** Checks whether a cURL return code indicates failure. */
     119#define CURL_FAILURE(rcCurl)    RT_UNLIKELY(rcCurl != CURLE_OK)
    80120
    81121/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
     
    97137
    98138
     139/*********************************************************************************************************************************
     140*   Internal Functions                                                                                                           *
     141*********************************************************************************************************************************/
     142static void rtHttpUnsetCaFile(PRTHTTPINTERNAL pThis);
     143
     144
    99145RTR3DECL(int) RTHttpCreate(PRTHTTP phHttp)
    100146{
    101147    AssertPtrReturn(phHttp, VERR_INVALID_PARAMETER);
    102148
     149    /** @todo r=bird: rainy day: curl_global_init is not thread safe, only a
     150     *        problem if multiple threads get here at the same time. */
     151    int rc = VERR_HTTP_INIT_FAILED;
    103152    CURLcode rcCurl = curl_global_init(CURL_GLOBAL_ALL);
    104     if (CURL_FAILED(rcCurl))
    105         return VERR_HTTP_INIT_FAILED;
    106 
    107     CURL *pCurl = curl_easy_init();
    108     if (!pCurl)
    109         return VERR_HTTP_INIT_FAILED;
    110 
    111     PRTHTTPINTERNAL pHttpInt = (PRTHTTPINTERNAL)RTMemAllocZ(sizeof(RTHTTPINTERNAL));
    112     if (!pHttpInt)
    113         return VERR_NO_MEMORY;
    114 
    115     pHttpInt->u32Magic = RTHTTP_MAGIC;
    116     pHttpInt->pCurl = pCurl;
    117 
    118     *phHttp = (RTHTTP)pHttpInt;
     153    if (!CURL_FAILURE(rcCurl))
     154    {
     155        CURL *pCurl = curl_easy_init();
     156        if (pCurl)
     157        {
     158            PRTHTTPINTERNAL pThis = (PRTHTTPINTERNAL)RTMemAllocZ(sizeof(RTHTTPINTERNAL));
     159            if (pThis)
     160            {
     161                pThis->u32Magic = RTHTTP_MAGIC;
     162                pThis->pCurl    = pCurl;
     163
     164                *phHttp = (RTHTTP)pThis;
     165
     166                return VINF_SUCCESS;
     167            }
     168            rc = VERR_NO_MEMORY;
     169        }
     170        else
     171            rc = VERR_HTTP_INIT_FAILED;
     172    }
     173    curl_global_cleanup();
     174    return rc;
     175}
     176
     177
     178RTR3DECL(void) RTHttpDestroy(RTHTTP hHttp)
     179{
     180    if (hHttp == NIL_RTHTTP)
     181        return;
     182
     183    PRTHTTPINTERNAL pThis = hHttp;
     184    RTHTTP_VALID_RETURN_VOID(pThis);
     185
     186    Assert(!pThis->fBusy);
     187
     188    pThis->u32Magic = RTHTTP_MAGIC_DEAD;
     189
     190    curl_easy_cleanup(pThis->pCurl);
     191    pThis->pCurl = NULL;
     192
     193    if (pThis->pHeaders)
     194        curl_slist_free_all(pThis->pHeaders);
     195
     196    rtHttpUnsetCaFile(pThis);
     197    Assert(!pThis->pszCaFile);
     198
     199    if (pThis->pszRedirLocation)
     200        RTStrFree(pThis->pszRedirLocation);
     201
     202    RTMemFree(pThis);
     203
     204    curl_global_cleanup();
     205}
     206
     207
     208RTR3DECL(int) RTHttpAbort(RTHTTP hHttp)
     209{
     210    PRTHTTPINTERNAL pThis = hHttp;
     211    RTHTTP_VALID_RETURN(pThis);
     212
     213    pThis->fAbort = true;
    119214
    120215    return VINF_SUCCESS;
     
    122217
    123218
    124 RTR3DECL(void) RTHttpDestroy(RTHTTP hHttp)
    125 {
    126     if (!hHttp)
    127         return;
    128 
    129     PRTHTTPINTERNAL pHttpInt = hHttp;
    130     RTHTTP_VALID_RETURN_VOID(pHttpInt);
    131 
    132     pHttpInt->u32Magic = RTHTTP_MAGIC_DEAD;
    133 
    134     curl_easy_cleanup(pHttpInt->pCurl);
    135 
    136     if (pHttpInt->pHeaders)
    137         curl_slist_free_all(pHttpInt->pHeaders);
    138 
    139     if (pHttpInt->pcszCAFile)
    140         RTStrFree(pHttpInt->pcszCAFile);
    141 
    142     if (pHttpInt->pszRedirLocation)
    143         RTStrFree(pHttpInt->pszRedirLocation);
    144 
    145     RTMemFree(pHttpInt);
    146 
    147     curl_global_cleanup();
    148 }
    149 
    150 
    151 static DECLCALLBACK(size_t) rtHttpWriteData(void *pvBuf, size_t cb, size_t n, void *pvUser)
    152 {
    153     PRTHTTPMEMCHUNK pMem = (PRTHTTPMEMCHUNK)pvUser;
    154     size_t cbAll = cb * n;
    155 
    156     pMem->pu8Mem = (uint8_t*)RTMemRealloc(pMem->pu8Mem, pMem->cb + cbAll + 1);
    157     if (pMem->pu8Mem)
    158     {
    159         memcpy(&pMem->pu8Mem[pMem->cb], pvBuf, cbAll);
    160         pMem->cb += cbAll;
    161         pMem->pu8Mem[pMem->cb] = '\0';
    162     }
    163     return cbAll;
    164 }
    165 
    166 
    167 static DECLCALLBACK(int) rtHttpProgress(void *pData, double DlTotal, double DlNow, double UlTotal, double UlNow)
    168 {
    169     PRTHTTPINTERNAL pHttpInt = (PRTHTTPINTERNAL)pData;
    170     AssertReturn(pHttpInt->u32Magic == RTHTTP_MAGIC, 1);
    171 
    172     return pHttpInt->fAbort ? 1 : 0;
    173 }
    174 
    175 
    176 RTR3DECL(int) RTHttpAbort(RTHTTP hHttp)
    177 {
    178     PRTHTTPINTERNAL pHttpInt = hHttp;
    179     RTHTTP_VALID_RETURN(pHttpInt);
    180 
    181     pHttpInt->fAbort = true;
    182 
    183     return VINF_SUCCESS;
    184 }
    185 
    186 
    187219RTR3DECL(int) RTHttpGetRedirLocation(RTHTTP hHttp, char **ppszRedirLocation)
    188220{
    189     PRTHTTPINTERNAL pHttpInt = hHttp;
    190     RTHTTP_VALID_RETURN(pHttpInt);
    191 
    192     if (!pHttpInt->pszRedirLocation)
     221    PRTHTTPINTERNAL pThis = hHttp;
     222    RTHTTP_VALID_RETURN(pThis);
     223    Assert(!pThis->fBusy);
     224
     225    if (!pThis->pszRedirLocation)
    193226        return VERR_HTTP_NOT_FOUND;
    194227
    195     *ppszRedirLocation = RTStrDup(pHttpInt->pszRedirLocation);
    196     return VINF_SUCCESS;
     228    return RTStrDupEx(ppszRedirLocation, pThis->pszRedirLocation);
    197229}
    198230
     
    200232RTR3DECL(int) RTHttpUseSystemProxySettings(RTHTTP hHttp)
    201233{
    202     PRTHTTPINTERNAL pHttpInt = hHttp;
    203     RTHTTP_VALID_RETURN(pHttpInt);
     234    PRTHTTPINTERNAL pThis = hHttp;
     235    RTHTTP_VALID_RETURN(pThis);
    204236
    205237    /*
     
    213245        if (!strncmp(szProxy, RT_STR_TUPLE("http://")))
    214246        {
    215             rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXY, &szProxy[sizeof("http://") - 1]);
    216             if (CURL_FAILED(rcCurl))
     247            rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXY, &szProxy[sizeof("http://") - 1]);
     248            if (CURL_FAILURE(rcCurl))
    217249                return VERR_INVALID_PARAMETER;
    218             rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYPORT, 80);
    219             if (CURL_FAILED(rcCurl))
     250            rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYPORT, 80);
     251            if (CURL_FAILURE(rcCurl))
    220252                return VERR_INVALID_PARAMETER;
    221253        }
    222254        else
    223255        {
    224             rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXY, &szProxy[sizeof("http://") - 1]);
    225             if (CURL_FAILED(rcCurl))
     256            rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXY, &szProxy[sizeof("http://") - 1]);
     257            if (CURL_FAILURE(rcCurl))
    226258                return VERR_INVALID_PARAMETER;
    227259        }
     
    237269                             const char *pcszProxyUser, const char *pcszProxyPwd)
    238270{
    239     PRTHTTPINTERNAL pHttpInt = hHttp;
    240     RTHTTP_VALID_RETURN(pHttpInt);
     271    PRTHTTPINTERNAL pThis = hHttp;
     272    RTHTTP_VALID_RETURN(pThis);
    241273    AssertPtrReturn(pcszProxy, VERR_INVALID_PARAMETER);
    242274
    243     int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXY, pcszProxy);
    244     if (CURL_FAILED(rcCurl))
     275    int rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXY, pcszProxy);
     276    if (CURL_FAILURE(rcCurl))
    245277        return VERR_INVALID_PARAMETER;
    246278
    247279    if (uPort != 0)
    248280    {
    249         rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYPORT, (long)uPort);
    250         if (CURL_FAILED(rcCurl))
     281        rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYPORT, (long)uPort);
     282        if (CURL_FAILURE(rcCurl))
    251283            return VERR_INVALID_PARAMETER;
    252284    }
     
    254286    if (pcszProxyUser && pcszProxyPwd)
    255287    {
    256         rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYUSERNAME, pcszProxyUser);
    257         if (CURL_FAILED(rcCurl))
     288        rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYUSERNAME, pcszProxyUser);
     289        if (CURL_FAILURE(rcCurl))
    258290            return VERR_INVALID_PARAMETER;
    259291
    260         rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYPASSWORD, pcszProxyPwd);
    261         if (CURL_FAILED(rcCurl))
     292        rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYPASSWORD, pcszProxyPwd);
     293        if (CURL_FAILURE(rcCurl))
    262294            return VERR_INVALID_PARAMETER;
    263295    }
     
    269301RTR3DECL(int) RTHttpSetHeaders(RTHTTP hHttp, size_t cHeaders, const char * const *papszHeaders)
    270302{
    271     PRTHTTPINTERNAL pHttpInt = hHttp;
    272     RTHTTP_VALID_RETURN(pHttpInt);
     303    PRTHTTPINTERNAL pThis = hHttp;
     304    RTHTTP_VALID_RETURN(pThis);
    273305
    274306    if (!cHeaders)
    275307    {
    276         if (pHttpInt->pHeaders)
    277             curl_slist_free_all(pHttpInt->pHeaders);
    278         pHttpInt->pHeaders = 0;
     308        if (pThis->pHeaders)
     309            curl_slist_free_all(pThis->pHeaders);
     310        pThis->pHeaders = 0;
    279311        return VINF_SUCCESS;
    280312    }
     
    284316        pHeaders = curl_slist_append(pHeaders, papszHeaders[i]);
    285317
    286     pHttpInt->pHeaders = pHeaders;
    287     int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_HTTPHEADER, pHeaders);
    288     if (CURL_FAILED(rcCurl))
     318    pThis->pHeaders = pHeaders;
     319    int rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_HTTPHEADER, pHeaders);
     320    if (CURL_FAILURE(rcCurl))
    289321        return VERR_INVALID_PARAMETER;
    290322
     
    293325
    294326
    295 RTR3DECL(int) RTHttpSetCAFile(RTHTTP hHttp, const char *pcszCAFile)
    296 {
    297     PRTHTTPINTERNAL pHttpInt = hHttp;
    298     RTHTTP_VALID_RETURN(pHttpInt);
    299 
    300     if (pHttpInt->pcszCAFile)
    301         RTStrFree(pHttpInt->pcszCAFile);
    302     pHttpInt->pcszCAFile = RTStrDup(pcszCAFile);
    303     if (!pHttpInt->pcszCAFile)
    304         return VERR_NO_MEMORY;
    305 
     327/**
     328 * Set the CA file to NULL, deleting any temporary file if necessary.
     329 *
     330 * @param   pThis           The HTTP/HTTPS client instance.
     331 */
     332static void rtHttpUnsetCaFile(PRTHTTPINTERNAL pThis)
     333{
     334    if (pThis->pszCaFile)
     335    {
     336        if (pThis->fDeleteCaFile)
     337        {
     338            int rc2 = RTFileDelete(pThis->pszCaFile);
     339            AssertMsg(RT_SUCCESS(rc2) || !RTFileExists(pThis->pszCaFile), ("rc=%Rrc '%s'\n", rc2, pThis->pszCaFile));
     340        }
     341        RTStrFree(pThis->pszCaFile);
     342        pThis->pszCaFile = NULL;
     343    }
     344}
     345
     346
     347RTR3DECL(int) RTHttpSetCAFile(RTHTTP hHttp, const char *pszCaFile)
     348{
     349    PRTHTTPINTERNAL pThis = hHttp;
     350    RTHTTP_VALID_RETURN(pThis);
     351
     352    rtHttpUnsetCaFile(pThis);
     353
     354    pThis->fDeleteCaFile = false;
     355    if (pszCaFile)
     356        return RTStrDupEx(&pThis->pszCaFile, pszCaFile);
    306357    return VINF_SUCCESS;
    307358}
     359
     360
     361RTR3DECL(int) RTHttpUseTemporaryCaFile(RTHTTP hHttp, PRTERRINFO pErrInfo)
     362{
     363    PRTHTTPINTERNAL pThis = hHttp;
     364    RTHTTP_VALID_RETURN(pThis);
     365
     366    /*
     367     * Create a temporary file.
     368     */
     369    int rc = VERR_NO_STR_MEMORY;
     370    char *pszCaFile = RTStrAlloc(RTPATH_MAX);
     371    if (pszCaFile)
     372    {
     373        RTFILE hFile;
     374        rc = RTFileOpenTemp(&hFile, pszCaFile, RTPATH_MAX,
     375                            RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE | (0600 << RTFILE_O_CREATE_MODE_SHIFT));
     376        if (RT_SUCCESS(rc))
     377        {
     378            /*
     379             * Gather certificates into a temporary store and export them to the temporary file.
     380             */
     381            RTCRSTORE hStore;
     382            rc = RTCrStoreCreateInMem(&hStore, 256);
     383            if (RT_SUCCESS(rc))
     384            {
     385                rc = RTHttpGatherCaCertsInStore(hStore, 0 /*fFlags*/, pErrInfo);
     386                if (RT_SUCCESS(rc))
     387                    /** @todo Consider adding an API for exporting to a RTFILE... */
     388                    rc = RTCrStoreCertExportAsPem(hStore, 0 /*fFlags*/, pszCaFile);
     389                RTCrStoreRelease(hStore);
     390            }
     391            RTFileClose(hFile);
     392            if (RT_SUCCESS(rc))
     393            {
     394                /*
     395                 * Set the CA file for the instance.
     396                 */
     397                rtHttpUnsetCaFile(pThis);
     398
     399                pThis->fDeleteCaFile = true;
     400                pThis->pszCaFile = pszCaFile;
     401                return VINF_SUCCESS;
     402            }
     403
     404            int rc2 = RTFileDelete(pszCaFile);
     405            AssertRC(rc2);
     406        }
     407        else
     408            RTErrInfoAddF(pErrInfo, rc, "Error creating temorary file: %Rrc", rc);
     409
     410        RTStrFree(pszCaFile);
     411    }
     412    return rc;
     413}
     414
     415
     416RTR3DECL(int) RTHttpGatherCaCertsInStore(RTCRSTORE hStore, uint32_t fFlags, PRTERRINFO pErrInfo)
     417{
     418    uint32_t const cBefore = RTCrStoreCertCount(hStore);
     419    AssertReturn(cBefore != UINT32_MAX, VERR_INVALID_HANDLE);
     420
     421    /*
     422     * Add the user store, quitely ignoring any errors.
     423     */
     424    RTCRSTORE hSrcStore;
     425    int rcUser = RTCrStoreCreateSnapshotById(&hSrcStore, RTCRSTOREID_USER_TRUSTED_CAS_AND_CERTIFICATES, pErrInfo);
     426    if (RT_SUCCESS(rcUser))
     427    {
     428        rcUser = RTCrStoreCertAddFromStore(hStore, RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR,
     429                                           hSrcStore);
     430        RTCrStoreRelease(hSrcStore);
     431    }
     432
     433    /*
     434     * Ditto for the system store.
     435     */
     436    int rcSystem = RTCrStoreCreateSnapshotById(&hSrcStore, RTCRSTOREID_USER_TRUSTED_CAS_AND_CERTIFICATES, pErrInfo);
     437    if (RT_SUCCESS(rcSystem))
     438    {
     439        rcSystem = RTCrStoreCertAddFromStore(hStore, RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR,
     440                                             hSrcStore);
     441        RTCrStoreRelease(hSrcStore);
     442    }
     443
     444    /*
     445     * If the number of certificates increased, we consider it a success.
     446     */
     447    if (RTCrStoreCertCount(hStore) > cBefore)
     448    {
     449        if (RT_FAILURE(rcSystem))
     450            return -rcSystem;
     451        if (RT_FAILURE(rcUser))
     452            return -rcUser;
     453        return rcSystem != VINF_SUCCESS ? rcSystem : rcUser;
     454    }
     455
     456    if (RT_FAILURE(rcSystem))
     457        return rcSystem;
     458    if (RT_FAILURE(rcUser))
     459        return rcSystem;
     460    return VERR_NOT_FOUND;
     461}
     462
     463
     464RTR3DECL(int) RTHttpGatherCaCertsInFile(const char *pszCaFile, uint32_t fFlags, PRTERRINFO pErrInfo)
     465{
     466    RTCRSTORE hStore;
     467    int rc = RTCrStoreCreateInMem(&hStore, 256);
     468    if (RT_SUCCESS(rc))
     469    {
     470        rc = RTHttpGatherCaCertsInStore(hStore, fFlags, pErrInfo);
     471        if (RT_SUCCESS(rc))
     472            rc = RTCrStoreCertExportAsPem(hStore, 0 /*fFlags*/, pszCaFile);
     473        RTCrStoreRelease(hStore);
     474    }
     475    return rc;
     476}
     477
    308478
    309479
     
    312482 *
    313483 * @returns IPRT status code.
    314  * @param   pHttpInt            HTTP instance.
    315  * @param   rcCurl              What curl returned.
    316  */
    317 static int rtHttpGetCalcStatus(PRTHTTPINTERNAL pHttpInt, int rcCurl)
     484 * @param   pThis           The HTTP/HTTPS client instance.
     485 * @param   rcCurl          What curl returned.
     486 */
     487static int rtHttpGetCalcStatus(PRTHTTPINTERNAL pThis, int rcCurl)
    318488{
    319489    int rc = VERR_INTERNAL_ERROR;
    320490
    321     if (pHttpInt->pszRedirLocation)
    322     {
    323         RTStrFree(pHttpInt->pszRedirLocation);
    324         pHttpInt->pszRedirLocation = NULL;
     491    if (pThis->pszRedirLocation)
     492    {
     493        RTStrFree(pThis->pszRedirLocation);
     494        pThis->pszRedirLocation = NULL;
    325495    }
    326496    if (rcCurl == CURLE_OK)
    327497    {
    328         curl_easy_getinfo(pHttpInt->pCurl, CURLINFO_RESPONSE_CODE, &pHttpInt->lLastResp);
    329         switch (pHttpInt->lLastResp)
     498        curl_easy_getinfo(pThis->pCurl, CURLINFO_RESPONSE_CODE, &pThis->lLastResp);
     499        switch (pThis->lLastResp)
    330500        {
    331501            case 200:
     
    338508            {
    339509                const char *pszRedirect;
    340                 curl_easy_getinfo(pHttpInt->pCurl, CURLINFO_REDIRECT_URL, &pszRedirect);
     510                curl_easy_getinfo(pThis->pCurl, CURLINFO_REDIRECT_URL, &pszRedirect);
    341511                size_t cb = strlen(pszRedirect);
    342512                if (cb > 0 && cb < 2048)
    343                     pHttpInt->pszRedirLocation = RTStrDup(pszRedirect);
     513                    pThis->pszRedirLocation = RTStrDup(pszRedirect);
    344514                rc = VERR_HTTP_REDIRECTED;
    345515                break;
     
    399569
    400570/**
     571 * cURL callback for reporting progress, we use it for checking for abort.
     572 */
     573static int rtHttpProgress(void *pData, double rdTotalDownload, double rdDownloaded, double rdTotalUpload, double rdUploaded)
     574{
     575    PRTHTTPINTERNAL pThis = (PRTHTTPINTERNAL)pData;
     576    AssertReturn(pThis->u32Magic == RTHTTP_MAGIC, 1);
     577
     578    pThis->cbDownloadHint = (uint64_t)rdTotalDownload;
     579
     580    return pThis->fAbort ? 1 : 0;
     581}
     582
     583
     584/**
     585 * Whether we're likely to need SSL to handle the give URL.
     586 *
     587 * @returns true if we need, false if we probably don't.
     588 * @param   pszUrl              The URL.
     589 */
     590static bool rtHttpNeedSsl(const char *pszUrl)
     591{
     592    return RTStrNICmp(pszUrl, RT_STR_TUPLE("https:")) == 0;
     593}
     594
     595
     596/**
     597 * Applies recoded settings to the cURL instance before doing work.
     598 *
     599 * @returns IPRT status code.
     600 * @param   pThis           The HTTP/HTTPS client instance.
     601 * @param   pszUrl          The URL.
     602 */
     603static int rtHttpApplySettings(PRTHTTPINTERNAL pThis, const char *pszUrl)
     604{
     605    /*
     606     * The URL.
     607     */
     608    int rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_URL, pszUrl);
     609    if (CURL_FAILURE(rcCurl))
     610        return VERR_INVALID_PARAMETER;
     611
     612    /*
     613     * Setup SSL.  Can be a bit of work.
     614     */
     615    rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_SSLVERSION, (long)CURL_SSLVERSION_TLSv1);
     616    if (CURL_FAILURE(rcCurl))
     617        return VERR_INVALID_PARAMETER;
     618
     619    const char *pszCaFile = pThis->pszCaFile;
     620    if (   !pszCaFile
     621        && rtHttpNeedSsl(pszUrl))
     622    {
     623        int rc = RTHttpUseTemporaryCaFile(pThis, NULL);
     624        if (RT_SUCCESS(rc))
     625            pszCaFile = pThis->pszCaFile;
     626        else
     627            return rc; /* Non-portable alternative: pszCaFile = "/etc/ssl/certs/ca-certificates.crt"; */
     628    }
     629    if (pszCaFile)
     630    {
     631        rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_CAINFO, pszCaFile);
     632        if (CURL_FAILURE(rcCurl))
     633            return VERR_INTERNAL_ERROR;
     634    }
     635
     636    /*
     637     * Progress/abort.
     638     */
     639    rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROGRESSFUNCTION, &rtHttpProgress);
     640    if (CURL_FAILURE(rcCurl))
     641        return VERR_INTERNAL_ERROR;
     642    rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROGRESSDATA, (void *)pThis);
     643    if (CURL_FAILURE(rcCurl))
     644        return VERR_INTERNAL_ERROR;
     645    rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_NOPROGRESS, (long)0);
     646    if (CURL_FAILURE(rcCurl))
     647        return VERR_INTERNAL_ERROR;
     648
     649    return VINF_SUCCESS;
     650}
     651
     652
     653/**
     654 * cURL callback for writing data.
     655 */
     656static size_t rtHttpWriteData(void *pvBuf, size_t cbUnit, size_t cUnits, void *pvUser)
     657{
     658    PRTHTTPINTERNAL pThis = (PRTHTTPINTERNAL)pvUser;
     659
     660    /*
     661     * Do max size and overflow checks.
     662     */
     663    size_t const cbToAppend = cbUnit * cUnits;
     664    size_t const cbCurSize  = pThis->Output.Mem.cb;
     665    size_t const cbNewSize  = cbCurSize + cbToAppend;
     666    if (   cbToAppend < RTHTTP_MAX_MEM_DOWNLOAD_SIZE
     667        && cbNewSize  < RTHTTP_MAX_MEM_DOWNLOAD_SIZE)
     668    {
     669        if (cbNewSize + 1 <= pThis->Output.Mem.cbAllocated)
     670        {
     671            memcpy(&pThis->Output.Mem.pb[cbCurSize], pvBuf, cbToAppend);
     672            pThis->Output.Mem.cb = cbNewSize;
     673            pThis->Output.Mem.pb[cbNewSize] = '\0';
     674            return VINF_SUCCESS;
     675        }
     676
     677        /*
     678         * We need to reallocate the output buffer.
     679         */
     680        /** @todo this could do with a better strategy wrt growth. */
     681        size_t cbAlloc = RT_ALIGN_Z(cbNewSize + 1, 64);
     682        if (   cbAlloc <= pThis->cbDownloadHint
     683            && pThis->cbDownloadHint < RTHTTP_MAX_MEM_DOWNLOAD_SIZE)
     684            cbAlloc = RT_ALIGN_Z(pThis->cbDownloadHint + 1, 64);
     685
     686        uint8_t *pbNew = (uint8_t *)RTMemRealloc(pThis->Output.Mem.pb, cbAlloc);
     687        if (pbNew)
     688        {
     689            memcpy(&pbNew[cbCurSize], pvBuf, cbToAppend);
     690            pbNew[cbNewSize] = '\0';
     691
     692            pThis->Output.Mem.cbAllocated = cbAlloc;
     693            pThis->Output.Mem.pb = pbNew;
     694            pThis->Output.Mem.cb = cbNewSize;
     695            return VINF_SUCCESS;
     696        }
     697
     698        pThis->rcOutput = VERR_NO_MEMORY;
     699    }
     700    else
     701        pThis->rcOutput      = VERR_TOO_MUCH_DATA;
     702
     703    /*
     704     * Failure - abort.
     705     */
     706    RTMemFree(pThis->Output.Mem.pb);
     707    pThis->Output.Mem.pb = NULL;
     708    pThis->Output.Mem.cb = RTHTTP_MAX_MEM_DOWNLOAD_SIZE;
     709    pThis->fAbort        = true;
     710    return 0;
     711}
     712
     713
     714/**
    401715 * Internal worker that performs a HTTP GET.
    402716 *
    403717 * @returns IPRT status code.
    404  * @param   hHttp               The HTTP instance.
    405  * @param   pcszUrl             The URL.
     718 * @param   hHttp               The HTTP/HTTPS client instance.
     719 * @param   pszUrl              The URL.
    406720 * @param   ppvResponse         Where to return the pointer to the allocated
    407721 *                              response data (RTMemFree).  There will always be
     
    409723 *                              is not part of the size returned via @a pcb.
    410724 * @param   pcb                 The size of the response data.
    411  */
    412 RTR3DECL(int) rtHttpGet(RTHTTP hHttp, const char *pcszUrl, uint8_t **ppvResponse, size_t *pcb)
    413 {
    414     PRTHTTPINTERNAL pHttpInt = hHttp;
    415     RTHTTP_VALID_RETURN(pHttpInt);
    416 
    417     pHttpInt->fAbort = false;
    418 
    419     int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_URL, pcszUrl);
    420     if (CURL_FAILED(rcCurl))
    421         return VERR_INVALID_PARAMETER;
    422 
    423 #if 0
    424     rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_VERBOSE, 1);
    425     if (CURL_FAILED(rcCurl))
    426         return VERR_INVALID_PARAMETER;
    427 #endif
    428 
    429     const char *pcszCAFile = "/etc/ssl/certs/ca-certificates.crt";
    430     if (pHttpInt->pcszCAFile)
    431         pcszCAFile = pHttpInt->pcszCAFile;
    432     if (RTFileExists(pcszCAFile))
    433     {
    434         rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_CAINFO, pcszCAFile);
    435         if (CURL_FAILED(rcCurl))
    436             return VERR_INTERNAL_ERROR;
    437     }
    438 
    439     RTHTTPMEMCHUNK Chunk = { NULL, 0 };
    440     rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEFUNCTION, &rtHttpWriteData);
    441     if (CURL_FAILED(rcCurl))
    442         return VERR_INTERNAL_ERROR;
    443     rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEDATA, (void *)&Chunk);
    444     if (CURL_FAILED(rcCurl))
    445         return VERR_INTERNAL_ERROR;
    446     rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROGRESSFUNCTION, &rtHttpProgress);
    447     if (CURL_FAILED(rcCurl))
    448         return VERR_INTERNAL_ERROR;
    449     rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROGRESSDATA, (void *)pHttpInt);
    450     if (CURL_FAILED(rcCurl))
    451         return VERR_INTERNAL_ERROR;
    452     rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_NOPROGRESS, (long)0);
    453     if (CURL_FAILED(rcCurl))
    454         return VERR_INTERNAL_ERROR;
    455     rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_SSLVERSION, (long)CURL_SSLVERSION_TLSv1);
    456     if (CURL_FAILED(rcCurl))
    457         return VERR_INVALID_PARAMETER;
    458 
    459     rcCurl = curl_easy_perform(pHttpInt->pCurl);
    460 
    461     int rc = rtHttpGetCalcStatus(pHttpInt, rcCurl);
     725 *
     726 * @remarks We ASSUME the API user doesn't do concurrent GETs in different
     727 *          threads, because that will probably blow up!
     728 */
     729static int rtHttpGetToMem(RTHTTP hHttp, const char *pszUrl, uint8_t **ppvResponse, size_t *pcb)
     730{
     731    PRTHTTPINTERNAL pThis = hHttp;
     732    RTHTTP_VALID_RETURN(pThis);
     733
     734    /*
     735     * Reset the return values in case of more "GUI programming" on the client
     736     * side (i.e. a programming style not bothering checking return codes).
     737     */
     738    *ppvResponse = NULL;
     739    *pcb         = 0;
     740
     741    /*
     742     * Set the busy flag (paranoia).
     743     */
     744    bool fBusy = ASMAtomicXchgBool(&pThis->fBusy, true);
     745    AssertReturn(fBusy, VERR_WRONG_ORDER);
     746
     747    /*
     748     * Reset the state and apply settings.
     749     */
     750    pThis->fAbort = false;
     751    pThis->rcOutput = VINF_SUCCESS;
     752    pThis->cbDownloadHint = 0;
     753
     754    int rc = rtHttpApplySettings(hHttp, pszUrl);
    462755    if (RT_SUCCESS(rc))
    463756    {
    464         *ppvResponse = Chunk.pu8Mem;
    465         *pcb         = Chunk.cb;
    466     }
    467     else
    468     {
    469         if (Chunk.pu8Mem)
    470             RTMemFree(Chunk.pu8Mem);
    471         *ppvResponse = NULL;
    472         *pcb         = 0;
    473     }
    474 
     757        RT_ZERO(pThis->Output.Mem);
     758        int rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_WRITEFUNCTION, &rtHttpWriteData);
     759        if (!CURL_FAILURE(rcCurl))
     760            rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_WRITEDATA, (void *)pThis);
     761        if (!CURL_FAILURE(rcCurl))
     762        {
     763            /*
     764             * Perform the HTTP operation.
     765             */
     766            rcCurl = curl_easy_perform(pThis->pCurl);
     767            rc = rtHttpGetCalcStatus(pThis, rcCurl);
     768            if (RT_SUCCESS(rc))
     769                rc = pThis->rcOutput;
     770            if (RT_SUCCESS(rc))
     771            {
     772                *ppvResponse = pThis->Output.Mem.pb;
     773                *pcb         = pThis->Output.Mem.cb;
     774            }
     775            else if (pThis->Output.Mem.pb)
     776                RTMemFree(pThis->Output.Mem.pb);
     777            RT_ZERO(pThis->Output.Mem);
     778        }
     779        else
     780            rc = VERR_INTERNAL_ERROR_3;
     781    }
     782
     783    ASMAtomicWriteBool(&pThis->fBusy, false);
    475784    return rc;
    476785}
    477786
    478787
    479 RTR3DECL(int) RTHttpGetText(RTHTTP hHttp, const char *pcszUrl, char **ppszNotUtf8)
     788RTR3DECL(int) RTHttpGetText(RTHTTP hHttp, const char *pszUrl, char **ppszNotUtf8)
    480789{
    481790    uint8_t *pv;
    482791    size_t   cb;
    483     int rc = rtHttpGet(hHttp, pcszUrl, &pv, &cb);
     792    int rc = rtHttpGetToMem(hHttp, pszUrl, &pv, &cb);
    484793    if (RT_SUCCESS(rc))
    485794    {
     
    501810
    502811
    503 RTR3DECL(int) RTHttpGetBinary(RTHTTP hHttp, const char *pcszUrl, void **ppvResponse, size_t *pcb)
    504 {
    505     return rtHttpGet(hHttp, pcszUrl, (uint8_t **)ppvResponse, pcb);
     812RTR3DECL(int) RTHttpGetBinary(RTHTTP hHttp, const char *pszUrl, void **ppvResponse, size_t *pcb)
     813{
     814    return rtHttpGetToMem(hHttp, pszUrl, (uint8_t **)ppvResponse, pcb);
    506815}
    507816
     
    513822
    514823
    515 static size_t rtHttpWriteDataToFile(void *pvBuf, size_t cb, size_t n, void *pvUser)
    516 {
    517     size_t cbAll = cb * n;
    518     RTFILE hFile = (RTFILE)(intptr_t)pvUser;
    519 
     824/**
     825 * cURL callback for writing data to a file.
     826 */
     827static size_t rtHttpWriteDataToFile(void *pvBuf, size_t cbUnit, size_t cUnits, void *pvUser)
     828{
     829    PRTHTTPINTERNAL pThis = (PRTHTTPINTERNAL)pvUser;
    520830    size_t cbWritten = 0;
    521     int rc = RTFileWrite(hFile, pvBuf, cbAll, &cbWritten);
     831    int rc = RTFileWrite(pThis->Output.hFile, pvBuf, cbUnit * cUnits, &cbWritten);
    522832    if (RT_SUCCESS(rc))
    523833        return cbWritten;
     834    pThis->rcOutput = rc;
    524835    return 0;
    525836}
     
    528839RTR3DECL(int) RTHttpGetFile(RTHTTP hHttp, const char *pszUrl, const char *pszDstFile)
    529840{
    530     PRTHTTPINTERNAL pHttpInt = hHttp;
    531     RTHTTP_VALID_RETURN(pHttpInt);
    532 
    533     /*
    534      * Set up the request.
    535      */
    536     pHttpInt->fAbort = false;
    537 
    538     int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_URL, pszUrl);
    539     if (CURL_FAILED(rcCurl))
    540         return VERR_INVALID_PARAMETER;
    541 
    542 #if 0
    543     rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_VERBOSE, 1);
    544     if (CURL_FAILED(rcCurl))
    545         return VERR_INVALID_PARAMETER;
    546 #endif
    547 
    548     const char *pcszCAFile = "/etc/ssl/certs/ca-certificates.crt";
    549     if (pHttpInt->pcszCAFile)
    550         pcszCAFile = pHttpInt->pcszCAFile;
    551     if (RTFileExists(pcszCAFile))
    552     {
    553         rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_CAINFO, pcszCAFile);
    554         if (CURL_FAILED(rcCurl))
    555             return VERR_INTERNAL_ERROR;
    556     }
    557 
    558     rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEFUNCTION, &rtHttpWriteDataToFile);
    559     if (CURL_FAILED(rcCurl))
    560         return VERR_INTERNAL_ERROR;
    561     rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROGRESSFUNCTION, &rtHttpProgress);
    562     if (CURL_FAILED(rcCurl))
    563         return VERR_INTERNAL_ERROR;
    564     rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROGRESSDATA, (void *)pHttpInt);
    565     if (CURL_FAILED(rcCurl))
    566         return VERR_INTERNAL_ERROR;
    567     rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_NOPROGRESS, (long)0);
    568     if (CURL_FAILED(rcCurl))
    569         return VERR_INTERNAL_ERROR;
    570 
    571     /*
    572      * Open the output file.
    573      */
    574     RTFILE hFile;
    575     int rc = RTFileOpen(&hFile, pszDstFile, RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_READWRITE);
     841    PRTHTTPINTERNAL pThis = hHttp;
     842    RTHTTP_VALID_RETURN(pThis);
     843
     844    /*
     845     * Set the busy flag (paranoia).
     846     */
     847    bool fBusy = ASMAtomicXchgBool(&pThis->fBusy, true);
     848    AssertReturn(fBusy, VERR_WRONG_ORDER);
     849
     850    /*
     851     * Reset the state and apply settings.
     852     */
     853    pThis->fAbort = false;
     854    pThis->rcOutput = VINF_SUCCESS;
     855    pThis->cbDownloadHint = 0;
     856
     857    int rc = rtHttpApplySettings(hHttp, pszUrl);
    576858    if (RT_SUCCESS(rc))
    577859    {
    578         rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEDATA, (void *)(uintptr_t)hFile);
    579         if (!CURL_FAILED(rcCurl))
     860        pThis->Output.hFile = NIL_RTFILE;
     861        int rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_WRITEFUNCTION, &rtHttpWriteDataToFile);
     862        if (!CURL_FAILURE(rcCurl))
     863            rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_WRITEDATA, (void *)pThis);
     864        if (!CURL_FAILURE(rcCurl))
    580865        {
    581866            /*
    582              * Perform the request.
     867             * Open the output file.
    583868             */
    584             rcCurl = curl_easy_perform(pHttpInt->pCurl);
    585             rc = rtHttpGetCalcStatus(pHttpInt, rcCurl);
     869            rc = RTFileOpen(&pThis->Output.hFile, pszDstFile, RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_READWRITE);
     870            if (RT_SUCCESS(rc))
     871            {
     872                /*
     873                 * Perform the HTTP operation.
     874                 */
     875                rcCurl = curl_easy_perform(pThis->pCurl);
     876                rc = rtHttpGetCalcStatus(pThis, rcCurl);
     877                if (RT_SUCCESS(rc))
     878                     rc = pThis->rcOutput;
     879
     880                int rc2 = RTFileClose(pThis->Output.hFile);
     881                if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
     882                    rc = rc2;
     883            }
     884            pThis->Output.hFile = NIL_RTFILE;
    586885        }
    587886        else
    588             rc = VERR_INTERNAL_ERROR;
    589 
    590         int rc2 = RTFileClose(hFile);
    591         if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
    592             rc = rc2;
    593     }
    594 
     887            rc = VERR_INTERNAL_ERROR_3;
     888    }
     889
     890    ASMAtomicWriteBool(&pThis->fBusy, false);
    595891    return rc;
    596892}
  • trunk/src/VBox/Runtime/common/path/RTPathEnsureTrailingSeparator.cpp

    r57572 r57613  
    4444        if (RTPATH_IS_SLASH(ch) || RTPATH_IS_VOLSEP(ch))
    4545            return off;
     46        if (off + 2 <= cbPath)
     47        {
     48            pszPath[off++] = RTPATH_SLASH;
     49            pszPath[off]   = '\0';
     50            return off;
     51        }
    4652    }
    47 
    48     if (off + 2 < cbPath)
     53    else if (off + 3 <= cbPath)
    4954    {
    5055        pszPath[off++] = '.';
  • trunk/src/VBox/Runtime/generic/RTCrStoreCreateSnapshotById-generic.cpp

    r57572 r57613  
    146146    }
    147147    else
    148         RTErrInfoSet(pErrInfo, rc, "RTCrStoreCreateInMem failed");
     148        RTErrInfoAdd(pErrInfo, rc, "  RTCrStoreCreateInMem failed");
    149149    return rc;
    150150}
  • trunk/src/VBox/Runtime/generic/createtemp-generic.cpp

    r57358 r57613  
    235235}
    236236RT_EXPORT_SYMBOL(RTFileCreateTempSecure);
     237
     238
     239RTDECL(int) RTFileOpenTemp(PRTFILE phFile, char *pszFilename, size_t cbFilename, uint64_t fOpen)
     240{
     241    AssertReturn((fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE, VERR_INVALID_FLAGS);
     242    AssertReturn(fOpen & RTFILE_O_WRITE, VERR_INVALID_FLAGS);
     243
     244    /*
     245     * Start by obtaining the path to the temporary directory.
     246     */
     247    int rc = RTPathTemp(pszFilename, cbFilename);
     248    if (RT_SUCCESS(rc))
     249    {
     250        /*
     251         * Add a filename pattern.
     252         */
     253        static char const s_szTemplate[] = "IPRT-XXXXXXXXXXXX.tmp";
     254        rc = RTPathAppend(pszFilename, cbFilename, s_szTemplate);
     255        if (RT_SUCCESS(rc))
     256        {
     257            char * const pszX = RTStrEnd(pszFilename, cbFilename) - (sizeof(s_szTemplate) - 1) + 5;
     258            unsigned     cXes = sizeof(s_szTemplate) - 1 - 4 - 5;
     259            Assert(pszX[0] == 'X'); Assert(pszX[-1] == '-'); Assert(pszX[cXes] == '.');
     260
     261            /*
     262             * Try 10000 times with random names.
     263             */
     264            unsigned cTriesLeft = 10000;
     265            while (cTriesLeft-- > 0)
     266            {
     267                rtCreateTempFillTemplate(pszX, cXes);
     268                rc = RTFileOpen(phFile, pszFilename, fOpen);
     269                if (RT_SUCCESS(rc))
     270                    return rc;
     271            }
     272        }
     273    }
     274
     275    if (cbFilename)
     276        *pszFilename = '\0';
     277    *phFile = NIL_RTFILE;
     278    return rc;
     279}
     280RT_EXPORT_SYMBOL(RTFileOpenTemp);
     281
     282
  • trunk/src/VBox/Runtime/generic/fs-stubs-generic.cpp

    r57358 r57613  
    6868{
    6969    pProperties->cbMaxComponent = 255;
     70#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) || defined(RT_OS_DARWIN)
     71    pProperties->fCaseSensitive = false;
     72#else
    7073    pProperties->fCaseSensitive = true;
     74#endif
    7175    pProperties->fCompressed = false;
    7276    pProperties->fFileCompression = false;
     
    7882}
    7983
     84
     85RTR3DECL(bool) RTFsIsCaseSensitive(const char *pszFsPath)
     86{
     87#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) || defined(RT_OS_DARWIN)
     88    return false;
     89#else
     90    return true;
     91#endif
     92}
     93
  • trunk/src/VBox/Runtime/r3/nt/fs-nt.cpp

    r57358 r57613  
    226226
    227227
     228RTR3DECL(bool) RTFsIsCaseSensitive(const char *pszFsPath)
     229{
     230    return false;
     231}
     232
    228233
    229234RTR3DECL(int) RTFsQueryType(const char *pszFsPath, PRTFSTYPE penmType)
  • trunk/src/VBox/Runtime/r3/posix/fs-posix.cpp

    r57358 r57613  
    153153             */
    154154            pProperties->cbMaxComponent = StatVFS.f_namemax;
     155#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
     156            pProperties->fCaseSensitive = false;
     157#else
    155158            pProperties->fCaseSensitive = true;
     159#endif
    156160            pProperties->fCompressed = false;
    157161            pProperties->fFileCompression = false;
     
    168172             pszFsPath, pszFsPath, pProperties, pProperties->cbMaxComponent, pProperties->fReadOnly, rc));
    169173    return rc;
     174}
     175
     176
     177RTR3DECL(bool) RTFsIsCaseSensitive(const char *pszFsPath)
     178{
     179#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
     180    return false;
     181#else
     182    return true;
     183#endif
    170184}
    171185
  • trunk/src/VBox/Runtime/r3/win/fs-win.cpp

    r57358 r57613  
    335335    RTUtf16Free(pwszFsRoot);
    336336    return rc;
     337}
     338
     339
     340RTR3DECL(bool) RTFsIsCaseSensitive(const char *pszFsPath)
     341{
     342    return false;
    337343}
    338344
  • trunk/src/VBox/Runtime/testcase/Makefile.kmk

    r57604 r57613  
    9696        tstOnce \
    9797        tstRTPath \
     98        tstRTPathGlob \
    9899        tstRTPipe \
    99100        tstRTPoll \
     
    493494tstRTPath_SOURCES = tstRTPath.cpp
    494495
     496tstRTPathGlob_TEMPLATE = VBOXR3TSTEXE
     497tstRTPathGlob_SOURCES = tstRTPathGlob.cpp
     498
    495499tstRTPipe_TEMPLATE = VBOXR3TSTEXE
    496500tstRTPipe_SOURCES = tstRTPipe.cpp
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