Bug 1434936 - Add method nsNSSCertList::GetRootCertificate r=keeler r=fkiefer

This adds another utility method to nsNSSCertList to perform CERT_LIST_TAIL on
the underlying certificate list and return the last entry -- e.g., the root.
This is a convenience method to let other parts of the certificate verifier
continue to work with the higher-level nsNSSCertificate objects instead of
having to convert them.

MozReview-Commit-ID: EEi9L5Iepc6

--HG--
extra : rebase_source : 2836767a7186f65debf338f8d1f2a981636ed29b
extra : histedit_source : 5b87ec6c522ac1b84d91052e21184f3c03d9ea52
This commit is contained in:
J.C. Jones 2018-01-31 17:14:40 -07:00
parent 3315d3a267
commit 6395c26d4a
3 changed files with 98 additions and 2 deletions

View File

@ -1275,6 +1275,28 @@ nsNSSCertList::SegmentCertificateChain(/* out */ nsCOMPtr<nsIX509Cert>& aRoot,
return NS_OK;
}
nsresult
nsNSSCertList::GetRootCertificate(/* out */ nsCOMPtr<nsIX509Cert>& aRoot)
{
if (aRoot) {
return NS_ERROR_UNEXPECTED;
}
CERTCertListNode* rootNode = CERT_LIST_TAIL(mCertList);
if (!rootNode) {
return NS_ERROR_UNEXPECTED;
}
if (CERT_LIST_END(rootNode, mCertList)) {
// Empty list, leave aRoot empty
return NS_OK;
}
// Duplicates the certificate
aRoot = nsNSSCertificate::Create(rootNode->cert);
if (!aRoot) {
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
NS_IMPL_ISUPPORTS(nsNSSCertListEnumerator, nsISimpleEnumerator)
nsNSSCertListEnumerator::nsNSSCertListEnumerator(

View File

@ -106,6 +106,11 @@ public:
/* out */ nsCOMPtr<nsIX509CertList>& aIntermediates,
/* out */ nsCOMPtr<nsIX509Cert>& aEndEntity);
// Obtain the root certificate of a certificate chain. This method does so
// blindly, as SegmentCertificateChain; the same restrictions apply. On an
// empty list, leaves aRoot empty and returns OK.
nsresult GetRootCertificate(/* out */ nsCOMPtr<nsIX509Cert>& aRoot);
private:
virtual ~nsNSSCertList() {}

View File

@ -374,7 +374,6 @@ TEST_F(psm_CertList, TestForEachStopEarly)
ASSERT_EQ(rv, NS_OK) << "Should complete OK.";
}
TEST_F(psm_CertList, TestForEachStopOnError)
{
RefPtr<nsNSSCertList> certList = new nsNSSCertList();
@ -393,4 +392,74 @@ TEST_F(psm_CertList, TestForEachStopOnError)
});
ASSERT_EQ(counter, 1) << "There should have been only the one call";
ASSERT_EQ(rv, NS_ERROR_FAILURE) << "Should propagate the error.";
}
}
TEST_F(psm_CertList, TestGetRootCertificateChainTwo)
{
RefPtr<nsNSSCertList> certList = new nsNSSCertList();
nsresult rv = AddCertFromStringToList(kCaIntermediatePem, certList);
ASSERT_EQ(NS_OK, rv) << "Should have loaded OK";
rv = AddCertFromStringToList(kCaPem, certList);
ASSERT_EQ(NS_OK, rv) << "Should have loaded OK";
nsCOMPtr<nsIX509Cert> rootCert;
rv = certList->GetRootCertificate(rootCert);
EXPECT_EQ(NS_OK, rv) << "Should have fetched the root OK";
ASSERT_TRUE(rootCert) << "Root cert should be filled in";
bool selfSigned;
EXPECT_TRUE(NS_SUCCEEDED(rootCert->GetIsSelfSigned(&selfSigned))) << "Getters should work.";
EXPECT_TRUE(selfSigned) << "Roots are self signed";
nsAutoString rootCn;
EXPECT_TRUE(NS_SUCCEEDED(rootCert->GetCommonName(rootCn))) << "Getters should work.";
EXPECT_TRUE(rootCn.EqualsLiteral("ca")) << "Root CN should match";
// Re-fetch and ensure we get the same certificate.
nsCOMPtr<nsIX509Cert> rootCertRepeat;
rv = certList->GetRootCertificate(rootCertRepeat);
EXPECT_EQ(NS_OK, rv) << "Should have fetched the root OK the second time";
ASSERT_TRUE(rootCertRepeat) << "Root cert should still be filled in";
nsAutoString rootRepeatCn;
EXPECT_TRUE(NS_SUCCEEDED(rootCertRepeat->GetCommonName(rootRepeatCn))) << "Getters should work.";
EXPECT_TRUE(rootRepeatCn.EqualsLiteral("ca")) << "Root CN should still match";
}
TEST_F(psm_CertList, TestGetRootCertificateChainFour)
{
RefPtr<nsNSSCertList> certList = new nsNSSCertList();
nsresult rv = AddCertFromStringToList(kEePem, certList);
ASSERT_EQ(NS_OK, rv) << "Should have loaded OK";
rv = AddCertFromStringToList(kCaSecondIntermediatePem, certList);
ASSERT_EQ(NS_OK, rv) << "Should have loaded OK";
rv = AddCertFromStringToList(kCaIntermediatePem, certList);
ASSERT_EQ(NS_OK, rv) << "Should have loaded OK";
rv = AddCertFromStringToList(kCaPem, certList);
ASSERT_EQ(NS_OK, rv) << "Should have loaded OK";
nsCOMPtr<nsIX509Cert> rootCert;
rv = certList->GetRootCertificate(rootCert);
EXPECT_EQ(NS_OK, rv) << "Should have again fetched the root OK";
ASSERT_TRUE(rootCert) << "Root cert should be filled in";
bool selfSigned;
EXPECT_TRUE(NS_SUCCEEDED(rootCert->GetIsSelfSigned(&selfSigned))) << "Getters should work.";
EXPECT_TRUE(selfSigned) << "Roots are self signed";
nsAutoString rootCn;
EXPECT_TRUE(NS_SUCCEEDED(rootCert->GetCommonName(rootCn))) << "Getters should work.";
EXPECT_TRUE(rootCn.EqualsLiteral("ca")) << "Root CN should match";
}
TEST_F(psm_CertList, TestGetRootCertificateChainEmpty)
{
RefPtr<nsNSSCertList> certList = new nsNSSCertList();
nsCOMPtr<nsIX509Cert> rootCert;
nsresult rv = certList->GetRootCertificate(rootCert);
EXPECT_EQ(NS_OK, rv) << "Should have again fetched the root OK";
EXPECT_FALSE(rootCert) << "Root cert should be empty";
}