mozilla::pkix was originally implemented as part of mozilla-central (i.e. gecko) but has since been moved into NSS. However, it is not part of NSS' stable C API. As a library, mozilla::pkix uses the notion of a "trust domain" provided by the application to build a trusted chain from an end-entity certificate to a root. The trust domain is responsible for saying what trust level a certificate has, finding potential issuers of a certificate, and checking the revocation for a certificate. A certificate can be a trust anchor, it can inherit its trust, or it can be [[CA/Maintenance_and_Enforcement#Actively_Distrusting_a_Certificate|actively distrusted]]. Given an end-entity certificate and a trust domain, the library will perform issuer-independent checks on that certificate (e.g. expiration, appropriate key usages), get a list of potential issuers, and perform a [https://en.wikipedia.org/wiki/Depth-first_search depth-first traversal]. If it encounters a distrusted certificate, it abandons searching that path. If it finds a trust anchor, it queries the trust domain again to see if that path is acceptable (this is where gecko implements checks that are specific to the platform and not the abstract problem of building a trusted certificate chain). If so, the end-entity certificate has successfully been verified.
Because mozilla::pkix uses a depth-first strategy rather than a [https://en.wikipedia.org/wiki/Breadth-first_search breadth-first] one, it is not guaranteed to find the shortest path from an end-entity certificate to a trust anchor. However, as a heuristic, the trust domain implemented by the platform prefers trust anchors at each step. That is, when mozilla::pkix asks for an issuer certificate, the trust domain will first try any available trust anchors before trying non-trust anchors.
For example, suppose an end-entity certificate E were signed by intermediate I that was signed by root R. Further suppose that R were cross-signed by another root T, producing intermediate certificate R'. Two valid paths are E -> I -> R and E -> I -> R' -> T. At the step where mozilla::pkix is trying to find an issuer for I, the trust domain finds both R and R' as potential issuers. However, only R is a trust anchor - R' is not. So, the trust domain has mozilla::pkix try that one first. It successfully verifies, so the library returns the result E -> I -> R. If at some later point R were distrusted, that chain would not verify successfully. mozilla::pkix would then ask the trust domain for another potential issuer of I, and the trust domain would provide R'. R' is not a trust anchor either, so mozilla::pkix asks for potential issuers of that certificate. The trust domain provides T, and mozilla::pkix verifies the chain, resulting in E -> I -> R' -> T.
Extended Validation changes the situation somewhat in that when mozilla::pkix is verifying an EV certificate, it must do so for a particular policy OID, and only certain roots are trusted for particular policy OIDs. Other than that, path building proceeds as before. So, using the example from before, suppose R were a trust anchor but not for a particular EV OID. Further suppose that T is also a trust anchor but is trusted for a particular EV OID. When evaluating the potential chain E -> I -> R, the trust domain determines that R is not a trust anchor for the policy being verified for, so mozilla::pkix keeps searching. It finds potential chain E -> I -> R' -> T, where T is trusted for that EV OID, and thus it verifies and returns that chain.
Note that Firefox does not do AIA chasing. That is, it does not use information embedded in certificates to remotely fetch potential issuer certificates. So, if a server does not include the appropriate intermediate certificates in the TLS handshake, Firefox may not be able to verify its certificate. Firefox does currently cache intermediates from previous successful verifications, however, so if a necessary intermediate is available in the cache, then the verification may succeed.
Unlike the other NSS libraries, mozilla::pkix is written in C++ and can take advantage of more modern language features.