зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1411683 - Add foreach and segment utility methods to nsNSSCertList r=keeler
This adds two methods to nsNSSCertList: ForEachCertificateInChain, and SegmentCertificateChain. The ForEach method calls a supplied function for each certificate in the chain, one by one. That method is then used by the Segment method, which (assuming the chain is ordered) splits it into Root, End Entity, and everything in-between as a list of Intermediates. This patch does _not_ try to add these methods to the IDL, as it's not straightforward to me on how to handle the nsCOMPtr or std::function arguments. These methods will be first used by Bug 1409259. MozReview-Commit-ID: 8qjwF3juLTr --HG-- extra : rebase_source : 39e2e8530ac23c6b96eb73f406bca32a59bcccf5
This commit is contained in:
Родитель
6594c2801b
Коммит
de44bcbd15
|
@ -12,7 +12,12 @@ typedef struct CERTCertListStr CERTCertList;
|
|||
%}
|
||||
[ptr] native CERTCertListPtr(CERTCertList);
|
||||
|
||||
[scriptable, uuid(ae74cda5-cd2f-473f-96f5-f0b7fff62c68)]
|
||||
%{C++
|
||||
class nsNSSCertList;
|
||||
%}
|
||||
[ptr] native nsNSSCertListPtr(nsNSSCertList);
|
||||
|
||||
[scriptable, builtinclass, uuid(ae74cda5-cd2f-473f-96f5-f0b7fff62c68)]
|
||||
interface nsIX509CertList : nsISupports {
|
||||
[must_use]
|
||||
void addCert(in nsIX509Cert cert);
|
||||
|
@ -37,6 +42,12 @@ interface nsIX509CertList : nsISupports {
|
|||
*/
|
||||
[must_use]
|
||||
boolean equals(in nsIX509CertList other);
|
||||
|
||||
/**
|
||||
* Retrieves the PSM helper class that wraps the NSS certificate list
|
||||
*/
|
||||
[notxpcom, noscript, must_use]
|
||||
nsNSSCertListPtr getCertList();
|
||||
};
|
||||
|
||||
%{C++
|
||||
|
|
|
@ -1142,6 +1142,12 @@ void nsNSSCertList::destructorSafeDestroyNSSReference()
|
|||
mCertList = nullptr;
|
||||
}
|
||||
|
||||
nsNSSCertList*
|
||||
nsNSSCertList::GetCertList()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNSSCertList::AddCert(nsIX509Cert* aCert)
|
||||
{
|
||||
|
@ -1399,6 +1405,96 @@ nsNSSCertList::Equals(nsIX509CertList* other, bool* result)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsNSSCertList::ForEachCertificateInChain(ForEachCertOperation& aOperation)
|
||||
{
|
||||
nsCOMPtr<nsISimpleEnumerator> chainElt;
|
||||
nsresult rv = GetEnumerator(getter_AddRefs(chainElt));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Each chain may have multiple certificates.
|
||||
bool hasMore = false;
|
||||
rv = chainElt->HasMoreElements(&hasMore);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!hasMore) {
|
||||
return NS_OK; // Empty lists are fine
|
||||
}
|
||||
|
||||
do {
|
||||
nsCOMPtr<nsISupports> certSupports;
|
||||
rv = chainElt->GetNext(getter_AddRefs(certSupports));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIX509Cert> cert = do_QueryInterface(certSupports, &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = chainElt->HasMoreElements(&hasMore);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool continueLoop = true;
|
||||
rv = aOperation(cert, hasMore, continueLoop);
|
||||
if (NS_FAILED(rv) || !continueLoop) {
|
||||
return rv;
|
||||
}
|
||||
} while (hasMore);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsNSSCertList::SegmentCertificateChain(/* out */ nsCOMPtr<nsIX509Cert>& aRoot,
|
||||
/* out */ nsCOMPtr<nsIX509CertList>& aIntermediates,
|
||||
/* out */ nsCOMPtr<nsIX509Cert>& aEndEntity)
|
||||
{
|
||||
if (aRoot || aIntermediates || aEndEntity) {
|
||||
// All passed-in nsCOMPtrs should be empty for the state machine to work
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
aIntermediates = new nsNSSCertList();
|
||||
|
||||
nsresult rv = ForEachCertificateInChain(
|
||||
[&aRoot, &aIntermediates, &aEndEntity] (nsCOMPtr<nsIX509Cert> aCert,
|
||||
bool hasMore, bool& aContinue) {
|
||||
if (!aRoot) {
|
||||
// This is the root
|
||||
aRoot = aCert;
|
||||
} else if (!hasMore) {
|
||||
// This is the end entity
|
||||
aEndEntity = aCert;
|
||||
} else {
|
||||
// One of (potentially many) intermediates
|
||||
if (NS_FAILED(aIntermediates->AddCert(aCert))) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
});
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!aRoot || !aEndEntity) {
|
||||
// No self-sigend (or empty) chains allowed
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsNSSCertListEnumerator, nsISimpleEnumerator)
|
||||
|
||||
nsNSSCertListEnumerator::nsNSSCertListEnumerator(
|
||||
|
|
|
@ -69,6 +69,9 @@ SECStatus ConstructCERTCertListFromReversedDERArray(
|
|||
|
||||
} // namespace mozilla
|
||||
|
||||
typedef const std::function<nsresult(nsCOMPtr<nsIX509Cert>& aCert,
|
||||
bool aHasMore, /* out */ bool& aContinue)> ForEachCertOperation;
|
||||
|
||||
class nsNSSCertList: public nsIX509CertList,
|
||||
public nsISerializable,
|
||||
public nsNSSShutDownObject
|
||||
|
@ -88,6 +91,26 @@ public:
|
|||
const mozilla::UniqueCERTCertList& certList,
|
||||
const nsNSSShutDownPreventionLock& proofOfLock);
|
||||
|
||||
// For each certificate in this CertList, run the operation aOperation.
|
||||
// To end early with NS_OK, set the `aContinue` argument false before
|
||||
// returning. To end early with an error, return anything except NS_OK.
|
||||
// The `aHasMore` argument is false when this is the last certificate in the
|
||||
// chain.
|
||||
nsresult ForEachCertificateInChain(ForEachCertOperation& aOperation);
|
||||
|
||||
// Split a certificate chain into the root, intermediates (if any), and end
|
||||
// entity. This method does so blindly, assuming that the current list object
|
||||
// is ordered [root, intermediates..., end entity]. If that isn't true, this
|
||||
// method will return the certificates at the two ends without regard to the
|
||||
// actual chain of trust. Callers are encouraged to check, if there's any
|
||||
// doubt.
|
||||
// Will return error if used on self-signed or empty chains.
|
||||
// This method requires that all arguments be empty, notably the list
|
||||
// `aIntermediates` must be empty.
|
||||
nsresult SegmentCertificateChain(/* out */ nsCOMPtr<nsIX509Cert>& aRoot,
|
||||
/* out */ nsCOMPtr<nsIX509CertList>& aIntermediates,
|
||||
/* out */ nsCOMPtr<nsIX509Cert>& aEndEntity);
|
||||
|
||||
private:
|
||||
virtual ~nsNSSCertList();
|
||||
virtual void virtualDestroyNSSReference() override;
|
||||
|
|
|
@ -0,0 +1,392 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "nsIX509Cert.h"
|
||||
#include "nsIX509CertDB.h"
|
||||
#include "nsIX509CertList.h"
|
||||
#include "nsNSSCertificate.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
// certspec (for pycert.py)
|
||||
//
|
||||
// issuer:ca
|
||||
// subject:ca
|
||||
// extension:basicConstraints:cA,
|
||||
// extension:keyUsage:cRLSign,keyCertSign
|
||||
// serialNumber:1
|
||||
const char* kCaPem = "-----BEGIN CERTIFICATE-----\n" \
|
||||
"MIICsjCCAZygAwIBAgIBATALBgkqhkiG9w0BAQswDTELMAkGA1UEAwwCY2EwIhgP\n" \
|
||||
"MjAxNTExMjgwMDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowDTELMAkGA1UEAwwCY2Ew\n" \
|
||||
"ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQ\n" \
|
||||
"PTwT2erkNUq07PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH\n" \
|
||||
"9xzVJJwCfs1D/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw\n" \
|
||||
"4A8Njf1mCyuwJJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86\n" \
|
||||
"exCABiTMHGyXrZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0\n" \
|
||||
"ipVhHe4m1iWdq5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2N\n" \
|
||||
"AgMBAAGjHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMAsGCSqGSIb3DQEB\n" \
|
||||
"CwOCAQEAchHf1yV+blE6fvS53L3DGmvxEpn9+t+xwOvWczBmLFEzUPdncakdaWlQ\n" \
|
||||
"v7q81BPyjBqkYbQi15Ws81hY3dnXn8LT1QktCL9guvc3z4fMdQbRjpjcIReCYt3E\n" \
|
||||
"PB22Jl2FCm6ii4XL0qDFD26WK3zMe2Uks6t55f8VeDTBGNoPp2JMsWY1Pi4vR6wK\n" \
|
||||
"AY96WoXS/qrYkmMEOgFu907pApeAeE8VJzXjqMLF6/W1VN7ISnGzWQ8zKQnlp3YA\n" \
|
||||
"mvWZQcD6INK8mvpZxIeu6NtHaKEXGw7tlGekmkVhapPtQZYnWcsXybRrZf5g3hOh\n" \
|
||||
"JFPl8kW42VoxXL11PP5NX2ylTsJ//g==\n" \
|
||||
"-----END CERTIFICATE-----";
|
||||
|
||||
// certspec (for pycert.py)
|
||||
//
|
||||
// issuer:ca
|
||||
// subject:ca-intermediate
|
||||
// extension:basicConstraints:cA,
|
||||
// extension:keyUsage:cRLSign,keyCertSign
|
||||
// serialNumber:2
|
||||
const char* kCaIntermediatePem = "-----BEGIN CERTIFICATE-----\n" \
|
||||
"MIICvzCCAamgAwIBAgIBAjALBgkqhkiG9w0BAQswDTELMAkGA1UEAwwCY2EwIhgP\n" \
|
||||
"MjAxNTExMjgwMDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowGjEYMBYGA1UEAwwPY2Et\n" \
|
||||
"aW50ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuohR\n" \
|
||||
"qESOFtZB/W62iAY2ED08E9nq5DVKtOz1aFdsJHvBxyWo4NgfvbGcBptuGobya+Kv\n" \
|
||||
"WnVramRxCHqlWqdFh/cc1SScAn7NQ/weadA4ICmTqyDDSeTbuUzCa2wO7RWCD/F+\n" \
|
||||
"rWkasdMCOosqQe6ncOAPDY39ZgsrsCSSpH25iGF5kLFXkD3SO8XguEgfqDfTiEPv\n" \
|
||||
"JxbYVbdmWqp+ApAvOnsQgAYkzBxsl62WYVu34pYSwHUxowyR3bTK9/ytHSXTCe+5\n" \
|
||||
"Fw6naOGzey8ib2njtIqVYR3uJtYlnauRCE42yxwkBCy/Fosv5fGPmRcxuLP+SSP6\n" \
|
||||
"clHEMdUDrNoYCjXtjQIDAQABox0wGzAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIB\n" \
|
||||
"BjALBgkqhkiG9w0BAQsDggEBAC0ys8UOmYgvH5rrTeV6u79ocHqdQFwdmR7/4d08\n" \
|
||||
"i3asC7b70dw0ehA5vi4cq5mwBvQOGZq4wvsR4jSJW0+0hjWL1dr2M6VxmCfjdqhU\n" \
|
||||
"NQHPlY6y7lLfYQbFfUHX99ZgygJjdmmm7H8MBP4UgPb8jl6Xq53FgYykiX/qPmfb\n" \
|
||||
"pzpOFHDi+Tk67DLCvPz03UUDYNx1H0OhRimj0DWhdYGUg2DHfLQkOEYvrYG4wYB8\n" \
|
||||
"AB/0hrG51yFsuXrzhYcinTKby11Qk6PjnOQ/aZvK00Jffep/RHs8lIOWty9SarMG\n" \
|
||||
"oNSECn+6I9AgStJdo6LuP1QPyrQe3DZtAHhRJAPAoU7BSqM=\n" \
|
||||
"-----END CERTIFICATE-----";
|
||||
|
||||
// certspec (for pycert.py)
|
||||
//
|
||||
// issuer:ca-intermediate
|
||||
// subject:ca-second-intermediate
|
||||
// extension:basicConstraints:cA,
|
||||
// extension:keyUsage:cRLSign,keyCertSign
|
||||
// serialNumber:3
|
||||
const char* kCaSecondIntermediatePem = "-----BEGIN CERTIFICATE-----\n" \
|
||||
"MIIC0zCCAb2gAwIBAgIBAzALBgkqhkiG9w0BAQswGjEYMBYGA1UEAwwPY2EtaW50\n" \
|
||||
"ZXJtZWRpYXRlMCIYDzIwMTUxMTI4MDAwMDAwWhgPMjAxODAyMDUwMDAwMDBaMCEx\n" \
|
||||
"HzAdBgNVBAMMFmNhLXNlY29uZC1pbnRlcm1lZGlhdGUwggEiMA0GCSqGSIb3DQEB\n" \
|
||||
"AQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq07PVoV2wk\n" \
|
||||
"e8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D/B5p0Dgg\n" \
|
||||
"KZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuwJJKkfbmI\n" \
|
||||
"YXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyXrZZhW7fi\n" \
|
||||
"lhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWdq5EITjbL\n" \
|
||||
"HCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAGjHTAbMAwGA1Ud\n" \
|
||||
"EwQFMAMBAf8wCwYDVR0PBAQDAgEGMAsGCSqGSIb3DQEBCwOCAQEAaK6K7/0Y+PkG\n" \
|
||||
"MQJjumTlt6XUQjQ3Y6zuSOMlZ1wmJoBqWabYhJ4qXfcSMQiw+kZ+mQTFk+IdurGC\n" \
|
||||
"RHrAKwDGNRqmjnQ56qjwHNTTxhJozP09vBCgs3fIQQY/Nq/uISoQvOZmoIriFZf6\n" \
|
||||
"8czHMlj1vIC6zp4XHWdqkQ7aF4YFsTfM0kBPrm0Y6Nn0VKzWNdmaIs/X5OcR6ZAG\n" \
|
||||
"zGN9UZV+ZftcfdqI0XSVCVRAK5MeEa+twLr5PE/Nl7/Ig/tUJMWGSbcrWRZQTXQu\n" \
|
||||
"Rx7CSKcoatyMhJOd2YT4BvoijEJCxTKWMJzFe2uZAphQHUlVmE9IbUQM0T1N6RNd\n" \
|
||||
"1dH4o4UeuQ==\n" \
|
||||
"-----END CERTIFICATE-----";
|
||||
|
||||
// certspec (for pycert.py)
|
||||
//
|
||||
// issuer:ca-second-intermediate
|
||||
// subject:ee
|
||||
const char* kEePem = "-----BEGIN CERTIFICATE-----\n" \
|
||||
"MIICujCCAaSgAwIBAgIUMy8NE67P/4jkaCra7rOVVvX4+GswCwYJKoZIhvcNAQEL\n" \
|
||||
"MCExHzAdBgNVBAMMFmNhLXNlY29uZC1pbnRlcm1lZGlhdGUwIhgPMjAxNTExMjgw\n" \
|
||||
"MDAwMDBaGA8yMDE4MDIwNTAwMDAwMFowDTELMAkGA1UEAwwCZWUwggEiMA0GCSqG\n" \
|
||||
"SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6iFGoRI4W1kH9braIBjYQPTwT2erkNUq0\n" \
|
||||
"7PVoV2wke8HHJajg2B+9sZwGm24ahvJr4q9adWtqZHEIeqVap0WH9xzVJJwCfs1D\n" \
|
||||
"/B5p0DggKZOrIMNJ5Nu5TMJrbA7tFYIP8X6taRqx0wI6iypB7qdw4A8Njf1mCyuw\n" \
|
||||
"JJKkfbmIYXmQsVeQPdI7xeC4SB+oN9OIQ+8nFthVt2Zaqn4CkC86exCABiTMHGyX\n" \
|
||||
"rZZhW7filhLAdTGjDJHdtMr3/K0dJdMJ77kXDqdo4bN7LyJvaeO0ipVhHe4m1iWd\n" \
|
||||
"q5EITjbLHCQELL8Wiy/l8Y+ZFzG4s/5JI/pyUcQx1QOs2hgKNe2NAgMBAAEwCwYJ\n" \
|
||||
"KoZIhvcNAQELA4IBAQCE5V5YiFPtbb1dOCIMGC5X/6kfQkQmIfvEZIol0MRXmP4g\n" \
|
||||
"CsOPbTI+BNxYVNk5RHIlr+6e0d8TNiABem4FZK3kea4ugN8ez3IsK7ug7qdrooNA\n" \
|
||||
"MiHOvrLmAw2nQWexdDRf7OPeVj03BwELzGTOGPjAqDktTsK57OfXyFTm9nl75WQo\n" \
|
||||
"+EWX+CdV4L1o2rgABvSiMnMdycftCC73Hr/3ypADqY7nDrKpxYdrGgzAQvx3DjPv\n" \
|
||||
"b7nBKH/gXg3kzoWpeQmJYPl9Vd+DvGljS5i71oLbvCwlDX7ZswGcvb8pQ7Tni5HA\n" \
|
||||
"VYpAYLokxIDFnyVT9oCACJuJ5LvpBBrhd0+1uUPE\n" \
|
||||
"-----END CERTIFICATE-----";
|
||||
|
||||
class psm_CertList : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
|
||||
ASSERT_TRUE(prefs) << "couldn't get nsIPrefBranch";
|
||||
|
||||
// When PSM initializes, it attempts to get some localized strings.
|
||||
// As a result, Android flips out if this isn't set.
|
||||
nsresult rv = prefs->SetBoolPref("intl.locale.matchOS", true);
|
||||
ASSERT_TRUE(NS_SUCCEEDED(rv)) << "couldn't set pref 'intl.locale.matchOS'";
|
||||
|
||||
nsCOMPtr<nsIX509CertDB> certdb(do_GetService(NS_X509CERTDB_CONTRACTID));
|
||||
ASSERT_TRUE(certdb) << "couldn't get certdb";
|
||||
}
|
||||
};
|
||||
|
||||
static nsresult
|
||||
AddCertFromStringToList(const char* aPem, nsIX509CertList* aCertList)
|
||||
{
|
||||
if (!aCertList) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIX509Cert> cert;
|
||||
cert = nsNSSCertificate::ConstructFromDER(const_cast<char*>(aPem), strlen(aPem));
|
||||
if (!cert) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return aCertList->AddCert(cert);
|
||||
}
|
||||
|
||||
static int
|
||||
CountCertsInList(nsCOMPtr<nsIX509CertList>& aCertList)
|
||||
{
|
||||
int counter = 0;
|
||||
RefPtr<nsNSSCertList> certList = aCertList->GetCertList();
|
||||
certList->ForEachCertificateInChain(
|
||||
[&counter] (nsCOMPtr<nsIX509Cert> aCert, bool aHasMore, bool& aContinue) {
|
||||
counter++;
|
||||
return NS_OK;
|
||||
});
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
TEST_F(psm_CertList, TestInvalidSegmenting)
|
||||
{
|
||||
RefPtr<nsNSSCertList> certList = new nsNSSCertList();
|
||||
|
||||
nsCOMPtr<nsIX509Cert> rootCert;
|
||||
nsCOMPtr<nsIX509CertList> intCerts;
|
||||
nsCOMPtr<nsIX509Cert> eeCert;
|
||||
nsresult rv = certList->SegmentCertificateChain(rootCert, intCerts, eeCert);
|
||||
ASSERT_EQ(rv, NS_ERROR_INVALID_ARG) << "Empty lists can't be segmented";
|
||||
|
||||
rv = AddCertFromStringToList(kCaPem, certList);
|
||||
ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
|
||||
|
||||
// We should need to clear out the in-vars, but let's make sure behavior is OK
|
||||
rv = certList->SegmentCertificateChain(rootCert, intCerts, eeCert);
|
||||
ASSERT_EQ(rv, NS_ERROR_UNEXPECTED) << "Don't permit already-filled-in arguments";
|
||||
|
||||
intCerts = nullptr;
|
||||
rootCert = nullptr;
|
||||
eeCert = nullptr;
|
||||
|
||||
rv = certList->SegmentCertificateChain(rootCert, intCerts, eeCert);
|
||||
ASSERT_EQ(rv, NS_ERROR_INVALID_ARG) << "Lists of one can't be segmented";
|
||||
}
|
||||
|
||||
TEST_F(psm_CertList, TestValidSegmenting)
|
||||
{
|
||||
RefPtr<nsNSSCertList> certList = new nsNSSCertList();
|
||||
|
||||
nsresult rv = AddCertFromStringToList(kCaPem, certList);
|
||||
ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
|
||||
rv = AddCertFromStringToList(kCaIntermediatePem, certList);
|
||||
ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
|
||||
|
||||
nsCOMPtr<nsIX509Cert> rootCert;
|
||||
nsCOMPtr<nsIX509CertList> intCerts;
|
||||
nsCOMPtr<nsIX509Cert> eeCert;
|
||||
|
||||
rv = certList->SegmentCertificateChain(rootCert, intCerts, eeCert);
|
||||
ASSERT_EQ(rv, NS_OK) << "Should have segmented OK";
|
||||
ASSERT_TRUE(rootCert) << "Root cert should be filled in";
|
||||
ASSERT_TRUE(eeCert) << "End entity cert should be filled in";
|
||||
ASSERT_EQ(CountCertsInList(intCerts), 0) << "There should be no intermediates";
|
||||
|
||||
bool selfSigned;
|
||||
ASSERT_TRUE(NS_SUCCEEDED(rootCert->GetIsSelfSigned(&selfSigned))) << "Getters should work.";
|
||||
ASSERT_TRUE(selfSigned) << "Roots are self signed.";
|
||||
|
||||
nsAutoString rootCn;
|
||||
ASSERT_TRUE(NS_SUCCEEDED(rootCert->GetCommonName(rootCn))) << "Getters should work.";
|
||||
ASSERT_TRUE(rootCn.EqualsLiteral("ca")) << "Root CN should match";
|
||||
|
||||
rv = AddCertFromStringToList(kCaSecondIntermediatePem, certList);
|
||||
ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
|
||||
|
||||
intCerts = nullptr;
|
||||
rootCert = nullptr;
|
||||
eeCert = nullptr;
|
||||
rv = certList->SegmentCertificateChain(rootCert, intCerts, eeCert);
|
||||
ASSERT_EQ(rv, NS_OK) << "Should have segmented OK";
|
||||
|
||||
ASSERT_TRUE(rootCert) << "Root cert should be filled in";
|
||||
ASSERT_TRUE(eeCert) << "End entity cert should be filled in";
|
||||
ASSERT_EQ(CountCertsInList(intCerts), 1) << "There should be one intermediate";
|
||||
|
||||
rv = AddCertFromStringToList(kEePem, certList);
|
||||
ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
|
||||
|
||||
intCerts = nullptr;
|
||||
rootCert = nullptr;
|
||||
eeCert = nullptr;
|
||||
rv = certList->SegmentCertificateChain(rootCert, intCerts, eeCert);
|
||||
ASSERT_EQ(rv, NS_OK) << "Should have segmented OK";
|
||||
|
||||
ASSERT_TRUE(rootCert) << "Root cert should be filled in";
|
||||
ASSERT_TRUE(eeCert) << "End entity cert should be filled in";
|
||||
ASSERT_EQ(CountCertsInList(intCerts), 2) << "There should be two intermediates";
|
||||
|
||||
ASSERT_TRUE(NS_SUCCEEDED(rootCert->GetCommonName(rootCn))) << "Getters should work.";
|
||||
ASSERT_TRUE(rootCn.EqualsLiteral("ca")) << "Root CN should match";
|
||||
|
||||
nsAutoString eeCn;
|
||||
ASSERT_TRUE(NS_SUCCEEDED(eeCert->GetCommonName(eeCn))) << "Getters should work.";
|
||||
ASSERT_TRUE(eeCn.EqualsLiteral("ee")) << "EE CN should match";
|
||||
|
||||
rv = intCerts->GetCertList()->ForEachCertificateInChain(
|
||||
[] (nsCOMPtr<nsIX509Cert> aCert, bool aHasMore, bool& aContinue) {
|
||||
nsAutoString cn;
|
||||
nsresult rv = aCert->GetCommonName(cn);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (aHasMore) {
|
||||
if (!cn.EqualsLiteral("ca-intermediate")) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
} else {
|
||||
if (!cn.EqualsLiteral("ca-second-intermediate")) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
});
|
||||
ASSERT_EQ(rv, NS_OK) << "Should have looped OK.";
|
||||
}
|
||||
|
||||
TEST_F(psm_CertList, TestForEach)
|
||||
{
|
||||
RefPtr<nsNSSCertList> certList = new nsNSSCertList();
|
||||
|
||||
bool called = false;
|
||||
nsresult rv = certList->ForEachCertificateInChain(
|
||||
[&called] (nsCOMPtr<nsIX509Cert> aCert, bool aHasMore, bool& aContinue) {
|
||||
called = true;
|
||||
return NS_OK;
|
||||
});
|
||||
ASSERT_EQ(rv, NS_OK) << "Should have iterated OK";
|
||||
ASSERT_FALSE(called) << "There are no certificates in this chain, it shouldn't be called";
|
||||
|
||||
// Add two certificates
|
||||
rv = AddCertFromStringToList(kCaPem, certList);
|
||||
ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
|
||||
rv = AddCertFromStringToList(kCaIntermediatePem, certList);
|
||||
ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
|
||||
|
||||
int counter = 0;
|
||||
rv = certList->ForEachCertificateInChain(
|
||||
[&counter] (nsCOMPtr<nsIX509Cert> aCert, bool aHasMore, bool& aContinue) -> nsresult {
|
||||
if (!aCert) {
|
||||
GTEST_NONFATAL_FAILURE_("Unexpected arguments");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsAutoString cn;
|
||||
nsresult rv = aCert->GetCommonName(cn);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
switch(counter) {
|
||||
case 0:
|
||||
if (!aHasMore) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!cn.EqualsLiteral("ca")) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (aHasMore) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!cn.EqualsLiteral("ca-intermediate")) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
GTEST_NONFATAL_FAILURE_("Unexpected count");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
counter++;
|
||||
return NS_OK;
|
||||
});
|
||||
ASSERT_EQ(rv, NS_OK) << "Should have iterated OK";
|
||||
}
|
||||
|
||||
TEST_F(psm_CertList, TestForEachContinueSafety)
|
||||
{
|
||||
RefPtr<nsNSSCertList> certList = new nsNSSCertList();
|
||||
|
||||
// Add two certificates
|
||||
nsresult rv = AddCertFromStringToList(kCaSecondIntermediatePem, certList);
|
||||
ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
|
||||
rv = AddCertFromStringToList(kEePem, certList);
|
||||
ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
|
||||
|
||||
int counter = 0;
|
||||
rv = certList->ForEachCertificateInChain(
|
||||
[&counter] (nsCOMPtr<nsIX509Cert> aCert, bool aHasMore, bool& aContinue) {
|
||||
counter++;
|
||||
aContinue = true; // Try to keep it going
|
||||
return NS_OK;
|
||||
});
|
||||
ASSERT_EQ(counter, 2) << "There should have been only two iterations regardless!";
|
||||
ASSERT_EQ(rv, NS_OK) << "Should complete OK.";
|
||||
}
|
||||
|
||||
TEST_F(psm_CertList, TestForEachStopEarly)
|
||||
{
|
||||
RefPtr<nsNSSCertList> certList = new nsNSSCertList();
|
||||
|
||||
// Add two certificates
|
||||
nsresult rv = AddCertFromStringToList(kCaSecondIntermediatePem, certList);
|
||||
ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
|
||||
rv = AddCertFromStringToList(kEePem, certList);
|
||||
ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
|
||||
|
||||
int counter = 0;
|
||||
rv = certList->ForEachCertificateInChain(
|
||||
[&counter] (nsCOMPtr<nsIX509Cert> aCert, bool aHasMore, bool& aContinue) {
|
||||
counter++;
|
||||
aContinue = false;
|
||||
return NS_OK;
|
||||
});
|
||||
ASSERT_EQ(counter, 1) << "There should have been only the one call";
|
||||
ASSERT_EQ(rv, NS_OK) << "Should complete OK.";
|
||||
}
|
||||
|
||||
|
||||
TEST_F(psm_CertList, TestForEachStopOnError)
|
||||
{
|
||||
RefPtr<nsNSSCertList> certList = new nsNSSCertList();
|
||||
|
||||
// Add two certificates
|
||||
nsresult rv = AddCertFromStringToList(kCaSecondIntermediatePem, certList);
|
||||
ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
|
||||
rv = AddCertFromStringToList(kEePem, certList);
|
||||
ASSERT_EQ(rv, NS_OK) << "Should have loaded OK";
|
||||
|
||||
int counter = 0;
|
||||
rv = certList->ForEachCertificateInChain(
|
||||
[&counter] (nsCOMPtr<nsIX509Cert> aCert, bool aHasMore, bool& aContinue) {
|
||||
counter++;
|
||||
return NS_ERROR_FAILURE;
|
||||
});
|
||||
ASSERT_EQ(counter, 1) << "There should have been only the one call";
|
||||
ASSERT_EQ(rv, NS_ERROR_FAILURE) << "Should propagate the error.";
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
SOURCES += [
|
||||
'CertDBTest.cpp',
|
||||
'CertListTest.cpp',
|
||||
'DataStorageTest.cpp',
|
||||
'DeserializeCertTest.cpp',
|
||||
'MD4Test.cpp',
|
||||
|
|
Загрузка…
Ссылка в новой задаче