VirtualBox

Changeset 59679 in vbox for trunk/src/VBox/Main


Ignore:
Timestamp:
Feb 15, 2016 1:10:06 PM (9 years ago)
Author:
vboxsync
Message:

ApplianceImpl: Signature and certificate validation updates.

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

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/include/ApplianceImplPrivate.h

    r59669 r59679  
    6969      , hMemFileTheirManifest(NIL_RTVFSFILE)
    7070      , fSignerCertLoaded(false)
     71      , fCertificateIsSelfSigned(false)
     72      , fSignatureValid(false)
    7173      , fCertificateValid(false)
    72       , fSignatureValid(false)
     74      , fCertificateMissingPath(true)
     75      , fCertificateValidTime(false)
    7376      , pbSignedDigest(NULL)
    7477      , cbSignedDigest(0)
     
    126129            fSignerCertLoaded = false;
    127130        }
    128         enmSignedDigestType    = RTDIGESTTYPE_INVALID;
    129         fSignatureValid        = false;
    130         fCertificateValid      = false;
    131         fDeterminedDigestTypes = false;
    132         fDigestTypes           = RTMANIFEST_ATTR_SHA1 | RTMANIFEST_ATTR_SHA256 | RTMANIFEST_ATTR_SHA512;
     131        enmSignedDigestType      = RTDIGESTTYPE_INVALID;
     132        fCertificateIsSelfSigned = false;
     133        fSignatureValid          = false;
     134        fCertificateValid        = false;
     135        fCertificateMissingPath  = true;
     136        fCertificateValidTime    = false;
     137        fDeterminedDigestTypes   = false;
     138        fDigestTypes             = RTMANIFEST_ATTR_SHA1 | RTMANIFEST_ATTR_SHA256 | RTMANIFEST_ATTR_SHA512;
     139        strCertError.setNull();
    133140    }
    134141
     
    167174    /** Set if the SignerCert member contains usable data. */
    168175    bool                fSignerCertLoaded;
     176    /** Cached RTCrX509Validity_IsValidAtTimeSpec result set by read(). */
     177    bool                fCertificateIsSelfSigned;
     178    /** Set by read() if pbSignedDigest verified correctly against SignerCert. */
     179    bool                fSignatureValid;
    169180    /** Set by read() when the SignerCert checked out fine. */
    170181    bool                fCertificateValid;
    171     /** Set by read() if pbSignedDigest verified correctly against SignerCert. */
    172     bool                fSignatureValid;
     182    /** Set by read() when the SignerCert certificate path couldn't be built. */
     183    bool                fCertificateMissingPath;
     184    /** Set by read() when the SignerCert (+path) is valid in the temporal sense. */
     185    bool                fCertificateValidTime;
     186    /** For keeping certificate error messages we delay from read() to import(). */
     187    Utf8Str             strCertError;
    173188    /** The signed digest of the manifest. */
    174189    uint8_t            *pbSignedDigest;
  • trunk/src/VBox/Main/src-server/ApplianceImpl.cpp

    r59621 r59679  
    11191119void Appliance::i_addWarning(const char* aWarning, ...)
    11201120{
    1121     va_list args;
    1122     va_start(args, aWarning);
    1123     Utf8Str str(aWarning, args);
    1124     va_end(args);
    1125     m->llWarnings.push_back(str);
     1121    try
     1122    {
     1123        va_list args;
     1124        va_start(args, aWarning);
     1125        Utf8Str str(aWarning, args);
     1126        va_end(args);
     1127        m->llWarnings.push_back(str);
     1128    }
     1129    catch (...)
     1130    {
     1131        AssertFailed();
     1132    }
    11261133}
    11271134
     
    12161223
    12171224        case TaskOVF::Import:
    1218             if (pTask->locInfo.storageType == VFSType_File)
    1219                 pTask->rc = pAppliance->i_importFS(pTask);
     1225            /** @todo allow overriding these? */
     1226            if (!pAppliance->m->fSignatureValid && pAppliance->m->pbSignedDigest)
     1227                pTask->rc = pAppliance->setError(E_FAIL, tr("The manifest signature for '%s' is not valid"),
     1228                                                 pTask->locInfo.strPath.c_str());
     1229            else if (!pAppliance->m->fCertificateValid && pAppliance->m->pbSignedDigest)
     1230            {
     1231                if (pAppliance->m->strCertError.isNotEmpty())
     1232                    pTask->rc = pAppliance->setError(E_FAIL, tr("The certificate used to signed '%s' is not valid: %s"),
     1233                                                     pTask->locInfo.strPath.c_str(), pAppliance->m->strCertError.c_str());
     1234                else
     1235                    pTask->rc = pAppliance->setError(E_FAIL, tr("The certificate used to signed '%s' is not valid"),
     1236                                                     pTask->locInfo.strPath.c_str());
     1237            }
     1238            else if (pAppliance->m->fCertificateMissingPath && pAppliance->m->pbSignedDigest)
     1239                pTask->rc = pAppliance->setError(E_FAIL, tr("The certificate used to signed '%s' is does not have a valid CA path"),
     1240                                                 pTask->locInfo.strPath.c_str());
    12201241            else
    1221                 pTask->rc = E_NOTIMPL;
     1242            {
     1243                if (pTask->locInfo.storageType == VFSType_File)
     1244                    pTask->rc = pAppliance->i_importFS(pTask);
     1245                else
     1246                    pTask->rc = E_NOTIMPL;
     1247            }
    12221248            break;
    12231249
  • trunk/src/VBox/Main/src-server/ApplianceImplImport.cpp

    r59671 r59679  
    15701570    {
    15711571        m->fSignerCertLoaded = true;
     1572        m->fCertificateIsSelfSigned = RTCrX509Certificate_IsSelfSigned(&m->SignerCert);
    15721573
    15731574        /*
     
    17011702        /*
    17021703         * Validate the signed digest.
     1704         *
     1705         * It's possible we should allow the user to ignore signature
     1706         * mismatches, but for now it's a show stopper.
    17031707         */
    17041708        HRESULT hrc;
     
    17341738                    RTCrPkixSignatureRelease(hSignature);
    17351739                }
    1736             }
     1740                else
     1741                    hrc = setErrorVrc(vrc, tr("RTCrPkixSignatureCreateByObjId failed: %Rrc"), vrc);
     1742            }
     1743            else
     1744                hrc = setErrorVrc(vrc, tr("RTCrDigestUpdateFromVfsFile failed: %Rrc"), vrc);
    17371745            RTCrDigestRelease(hDigest);
    17381746        }
     
    17411749
    17421750        /*
    1743          * If the signed digest checked out, validate the certificate.
     1751         * Validate the certificate.
     1752         *
     1753         * We don't fail here on if we cannot validate the certificate, we postpone
     1754         * that till the import stage, so that we can allow the user to ignore it.
     1755         *
     1756         * The certificate validity time is deliberately ignored as the OVF
     1757         * specification does not include a way of timestamping the signature
     1758         * and it would be seriously annoying for users if OVAs expired with
     1759         * their certificates.  This is of course a security concern, but the
     1760         * whole signing of OVFs is currently weirdly trusting (self signed
     1761         * certs), so this is the least of our current problems.
    17441762         */
    1745         if (SUCCEEDED(hrc))
    1746         {
    1747             RTERRINFOSTATIC StaticErrInfo;
    1748             if (RTCrX509Certificate_IsSelfSigned(&m->SignerCert))
    1749             {
    1750                 /*
    1751                  * It's a self signed certificate.  We assume the frontend will
    1752                  * present this fact to the user and give a choice whether this
    1753                  * is acceptible.  But, first make sure it makes internal sense.
    1754                  */
    1755                 /** @todo Not entirely sure if we care whether a self issued certificate is
    1756                    marked as CA. But let's be a little bit picky about it for now. */
    1757                 if (   m->SignerCert.TbsCertificate.T3.pBasicConstraints
    1758                     && m->SignerCert.TbsCertificate.T3.pBasicConstraints->CA.fValue)
     1763        Assert(!m->fCertificateValid);
     1764        Assert(m->fCertificateMissingPath);
     1765        Assert(!m->fCertificateValidTime);
     1766        Assert(m->strCertError.isEmpty());
     1767        Assert(m->fCertificateIsSelfSigned == RTCrX509Certificate_IsSelfSigned(&m->SignerCert));
     1768
     1769        HRESULT hrc2 = S_OK;
     1770        RTERRINFOSTATIC StaticErrInfo;
     1771        if (m->fCertificateIsSelfSigned)
     1772        {
     1773            /*
     1774             * It's a self signed certificate.  We assume the frontend will
     1775             * present this fact to the user and give a choice whether this
     1776             * is acceptible.  But, first make sure it makes internal sense.
     1777             */
     1778            m->fCertificateMissingPath = false;
     1779            vrc = RTCrX509Certificate_VerifySignatureSelfSigned(&m->SignerCert, RTErrInfoInitStatic(&StaticErrInfo));
     1780            if (RT_SUCCESS(vrc))
     1781            {
     1782                m->fCertificateValid = true;
     1783
     1784                /* Check whether the certificate is currently valid, just warn if not. */
     1785                RTTIMESPEC Now;
     1786                if (RTCrX509Validity_IsValidAtTimeSpec(&m->SignerCert.TbsCertificate.Validity, RTTimeNow(&Now)))
     1787                    m->fCertificateValidTime = true;
     1788                else
     1789                    i_addWarning(tr("Self signed certificate used to sign '%s' is not currently valid"),
     1790                                 pTask->locInfo.strPath.c_str());
     1791
     1792                /* Just warn if it's not a CA. Self-signed certificates are
     1793                   hardly trustworthy to start with without the user's consent. */
     1794                if (   !m->SignerCert.TbsCertificate.T3.pBasicConstraints
     1795                    || !m->SignerCert.TbsCertificate.T3.pBasicConstraints->CA.fValue)
     1796                    i_addWarning(tr("Self signed certificate used to sign '%s' is not marked as certificate authority (CA)"),
     1797                                 pTask->locInfo.strPath.c_str());
     1798            }
     1799            else
     1800            {
     1801                try { m->strCertError = Utf8StrFmt(tr("Verification of the self signed certificate failed (%Rrc, %s)"),
     1802                                                   vrc, StaticErrInfo.Core.pszMsg); }
     1803                catch (...) { AssertFailed(); }
     1804                i_addWarning(tr("Verification of the self signed certificate used to sign '%s' failed (%Rrc): %s"),
     1805                             pTask->locInfo.strPath.c_str(), vrc, StaticErrInfo.Core.pszMsg);
     1806            }
     1807        }
     1808        else
     1809        {
     1810            /*
     1811             * The certificate is not self-signed.  Use the system certificate
     1812             * stores to try build a path that validates successfully.
     1813             */
     1814            RTCRX509CERTPATHS hCertPaths;
     1815            vrc = RTCrX509CertPathsCreate(&hCertPaths, &m->SignerCert);
     1816            if (RT_SUCCESS(vrc))
     1817            {
     1818                /* Get trusted certificates from the system and add them to the path finding mission. */
     1819                RTCRSTORE hTrustedCerts;
     1820                vrc = RTCrStoreCreateSnapshotOfUserAndSystemTrustedCAsAndCerts(&hTrustedCerts,
     1821                                                                               RTErrInfoInitStatic(&StaticErrInfo));
     1822                if (RT_SUCCESS(vrc))
    17591823                {
    1760                     vrc = RTCrX509Certificate_VerifySignatureSelfSigned(&m->SignerCert, RTErrInfoInitStatic(&StaticErrInfo));
     1824                    vrc = RTCrX509CertPathsSetTrustedStore(hCertPaths, hTrustedCerts);
     1825                    if (RT_FAILURE(vrc))
     1826                        hrc2 = setError(E_FAIL, tr("RTCrX509CertPathsSetTrustedStore failed (%Rrc)"), vrc);
     1827                    RTCrStoreRelease(hTrustedCerts);
     1828                }
     1829                else
     1830                    hrc2 = setError(E_FAIL,
     1831                                    tr("Failed to query trusted CAs and Certificates from the system and for the current user (%Rrc, %s)"),
     1832                                    vrc, StaticErrInfo.Core.pszMsg);
     1833
     1834                /* Add untrusted intermediate certificates. */
     1835                if (RT_SUCCESS(vrc))
     1836                {
     1837                    /// @todo RTCrX509CertPathsSetUntrustedStore(hCertPaths, hAdditionalCerts);
     1838                    /// By scanning for additional certificates in the .cert file?  It would be
     1839                    /// convenient to be able to supply intermediate certificates for the user,
     1840                    /// right?  Or would that be unacceptable as it may weaken security?
     1841                    ///
     1842                    /// Anyway, we should look for intermediate certificates on the system, at
     1843                    /// least.
     1844                }
     1845                if (RT_SUCCESS(vrc))
     1846                {
     1847                    /*
     1848                     * Do the building and verification of certificate paths.
     1849                     */
     1850                    vrc = RTCrX509CertPathsBuild(hCertPaths, RTErrInfoInitStatic(&StaticErrInfo));
    17611851                    if (RT_SUCCESS(vrc))
    17621852                    {
    1763                         /** @todo Consider the certificate expiration date!! Though see timestamp
    1764                          *        concern below in the non-self-issued case */
    1765                         hrc = S_OK;
    1766                         m->fCertificateValid = true;
     1853                        vrc = RTCrX509CertPathsValidateAll(hCertPaths, NULL, RTErrInfoInitStatic(&StaticErrInfo));
     1854                        if (RT_SUCCESS(vrc))
     1855                        {
     1856                            /*
     1857                             * Mark the certificate as good.
     1858                             */
     1859                            /** @todo check the certificate purpose? If so, share with self-signed. */
     1860                            m->fCertificateValid = true;
     1861                            m->fCertificateMissingPath = false;
     1862
     1863                            /*
     1864                             * We add a warning if the certificate path isn't valid at the current
     1865                             * time.  Since the time is only considered during path validation and we
     1866                             * can repeat the validation process (but not building), it's easy to check.
     1867                             */
     1868                            RTTIMESPEC Now;
     1869                            vrc = RTCrX509CertPathsSetValidTimeSpec(hCertPaths, RTTimeNow(&Now));
     1870                            if (RT_SUCCESS(vrc))
     1871                            {
     1872                                vrc = RTCrX509CertPathsValidateAll(hCertPaths, NULL, RTErrInfoInitStatic(&StaticErrInfo));
     1873                                if (RT_SUCCESS(vrc))
     1874                                    m->fCertificateValidTime = true;
     1875                                else
     1876                                    i_addWarning(tr("The certificate used to sign '%s' (or a certificate in the path) is not currently valid (%Rrc)"),
     1877                                                 pTask->locInfo.strPath.c_str(), vrc);
     1878                            }
     1879                            else
     1880                                hrc2 = setErrorVrc(vrc, "RTCrX509CertPathsSetValidTimeSpec failed: %Rrc", vrc);
     1881                        }
     1882                        else if (vrc == VERR_CR_X509_CPV_NO_TRUSTED_PATHS)
     1883                        {
     1884                            m->fCertificateValid = true;
     1885                            i_addWarning(tr("No trusted certificate paths"));
     1886                        }
     1887                        else
     1888                            hrc2 = setError(E_FAIL, tr("Certificate path validation failed (%Rrc, %s)"),
     1889                                            vrc, StaticErrInfo.Core.pszMsg);
    17671890                    }
    17681891                    else
    1769                         hrc = setErrorVrc(vrc, tr("Verification of the self signed certificate used to sign '%s' failed (%Rrc): %s"),
    1770                                           pTask->locInfo.strPath.c_str(), vrc, StaticErrInfo.Core.pszMsg);
     1892                        hrc2 = setError(E_FAIL, tr("Certificate path building failed (%Rrc, %s)"),
     1893                                        vrc, StaticErrInfo.Core.pszMsg);
    17711894                }
    1772                 else
    1773                     hrc = setError(E_FAIL,
    1774                                    tr("Self signed certificate used to sign '%s' is not marked as certificate authority (CA)"),
    1775                                    pTask->locInfo.strPath.c_str());
     1895                RTCrX509CertPathsRelease(hCertPaths);
    17761896            }
    17771897            else
    1778             {
    1779                 /*
    1780                  * The certificate is not self-signed.  Use the system certificate
    1781                  * stores to try validate it.
    1782                  */
    1783                 RTCRX509CERTPATHS hCertPaths;
    1784                 vrc = RTCrX509CertPathsCreate(&hCertPaths, &m->SignerCert);
    1785                 if (RT_SUCCESS(vrc))
    1786                 {
    1787                     /* Get trusted certificates from the system and add them to the path finding mission. */
    1788                     RTCRSTORE hTrustedCerts;
    1789                     vrc = RTCrStoreCreateSnapshotOfUserAndSystemTrustedCAsAndCerts(&hTrustedCerts,
    1790                                                                                    RTErrInfoInitStatic(&StaticErrInfo));
    1791                     if (RT_SUCCESS(vrc))
    1792                     {
    1793                         vrc = RTCrX509CertPathsSetTrustedStore(hCertPaths, hTrustedCerts);
    1794                         if (RT_FAILURE(vrc))
    1795                             hrc = setError(E_FAIL, tr("RTCrX509CertPathsSetTrustedStore failed (%Rrc)"), vrc);
    1796                         RTCrStoreRelease(hTrustedCerts);
    1797                     }
    1798                     else
    1799                         hrc = setError(E_FAIL,
    1800                                        tr("Failed to query trusted CAs and Certificates from the system and for the current user (%Rrc, %s)"),
    1801                                        vrc, StaticErrInfo.Core.pszMsg);
    1802 
    1803                     /* Add untrusted intermediate certificates. */
    1804                     if (RT_SUCCESS(vrc))
    1805                     {
    1806                         /// @todo RTCrX509CertPathsSetUntrustedStore(hCertPaths, hAdditionalCerts);
    1807                         /// By scanning for additional certificates in the .cert file?  It would be
    1808                         /// convenient to be able to supply intermediate certificates for the user,
    1809                         /// right?  Or would that be unacceptable as it may weaken security?
    1810                         ///
    1811                         /// Anyway, we should look for intermediate certificates on the system, at
    1812                         /// least.
    1813                     }
    1814 
    1815                     /* Set the validation timestamp? */
    1816                     if (RT_SUCCESS(vrc))
    1817                     {
    1818                         /// @todo RTCrX509CertPathsSetValidTimeSpec(hCertPaths, pValidationTime);
    1819                         /// Not having a timestamp signature is a bit crippling to deployment using
    1820                         /// certificates with a short expiration date...  Need to allow the user to
    1821                     }
    1822 
    1823                     if (RT_SUCCESS(vrc))
    1824                     {
    1825                         /*
    1826                          * Do the building and verification.
    1827                          */
    1828                         vrc = RTCrX509CertPathsBuild(hCertPaths, RTErrInfoInitStatic(&StaticErrInfo));
    1829                         if (RT_SUCCESS(vrc))
    1830                         {
    1831                             vrc = RTCrX509CertPathsValidateAll(hCertPaths, NULL, RTErrInfoInitStatic(&StaticErrInfo));
    1832                             if (RT_SUCCESS(vrc))
    1833                             {
    1834                                 /*
    1835                                  * The certificate is good.
    1836                                  */
    1837                                 /** @todo check the certificate purpose? */
    1838                                 m->fCertificateValid = true;
    1839                                 hrc = S_OK;
    1840                             }
    1841                             else
    1842                                 hrc = setError(E_FAIL, tr("Certificate path validation failed (%Rrc, %s)"),
    1843                                                vrc, StaticErrInfo.Core.pszMsg);
    1844                         }
    1845                         else
    1846                             hrc = setError(E_FAIL, tr("Certificate path building failed (%Rrc, %s)"),
    1847                                            vrc, StaticErrInfo.Core.pszMsg);
    1848 
    1849                     }
    1850                     RTCrX509CertPathsRelease(hCertPaths);
    1851                 }
    1852             }
     1898                hrc2 = setErrorVrc(vrc, tr("RTCrX509CertPathsCreate failed: %Rrc"), vrc);
    18531899        }
     1900
     1901        /* Merge statuses from signature and certificate validation, prefering the signature one. */
     1902        if (SUCCEEDED(hrc) && FAILED(hrc2))
     1903            hrc = hrc2;
     1904        if (FAILED(hrc))
     1905            return hrc;
    18541906    }
    18551907
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