-
-#if 0
-// MARK: -
-// MARK: SecTrustNode
-/********************************************************
- **************** SecTrustNode object *******************
- ********************************************************/
-typedef uint8_t SecFetchingState;
-enum {
- kSecFetchingStatePassedIn = 0,
- kSecFetchingStateLocal,
- kSecFetchingStateFromURL,
- kSecFetchingStateDone,
-};
-
-typedef uint8_t SecTrustState;
-enum {
- kSecTrustStateUnknown = 0,
- kSecTrustStateNotSigner,
- kSecTrustStateValidSigner,
-};
-
-typedef struct __SecTrustNode *SecTrustNodeRef;
-struct __SecTrustNode {
- SecTrustNodeRef _child;
- SecCertificateRef _certificate;
-
- /* Cached information about _certificate */
- bool _isAnchor;
- bool _isSelfSigned;
-
- /* Set of all certificates we have ever considered as a parent. We use
- this to avoid having to recheck certs when we go to the next phase. */
- CFMutableSet _certificates;
-
- /* Parents that are still partial chains we haven't yet considered. */
- CFMutableSet _partials;
- /* Parents that are still partial chains we have rejected. We reconsider
- these if we get to the final phase and we still haven't found a valid
- candidate. */
- CFMutableSet _rejected_partials;
-
- /* Parents that are complete chains we haven't yet considered. */
- CFMutableSet _candidates;
- /* Parents that are complete chains we have rejected. */
- CFMutableSet _rejected_candidates;
-
- /* State of candidate fetching. */
- SecFetchingState _fetchingState;
-
- /* Trust state of _candidates[_candidateIndex] */
- SecTrustState _trustState;
-};
-typedef struct __SecTrustNode SecTrustNode;
-
-/* Forward declarations of static functions. */
-static CFStringRef SecTrustNodeDescribe(CFTypeRef cf);
-static void SecTrustNodeDestroy(CFTypeRef cf);
-
-/* Static functions. */
-static CFStringRef SecTrustNodeCopyDescription(CFTypeRef cf) {
- SecTrustNodeRef node = (SecTrustNodeRef)cf;
- return CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
- CFSTR("<SecTrustNodeRef: %p>"), node);
-}
-
-static void SecTrustNodeDestroy(CFTypeRef cf) {
- SecTrustNodeRef trust = (SecTrustNodeRef)cf;
- if (trust->_child) {
- free(trust->_child);
- }
- if (trust->_certificate) {
- free(trust->_certificate);
- }
- if (trust->_candidates) {
- CFRelease(trust->_candidates);
- }
-}
-
-/* SecTrustNode API functions. */
-CFGiblisFor(SecTrustNode)
-
-SecTrustNodeRef SecTrustNodeCreate(SecTrustRef trust,
- SecCertificateRef certificate, SecTrustNodeRef child) {
- CFAllocatorRef allocator = kCFAllocatorDefault;
- check(trust);
- check(certificate);
-
- CFIndex size = sizeof(struct __SecTrustNode);
- SecTrustNodeRef result = (SecTrustNodeRef)_CFRuntimeCreateInstance(
- allocator, SecTrustNodeGetTypeID(), size - sizeof(CFRuntimeBase), 0);
- if (!result)
- return NULL;
-
- memset((char*)result + sizeof(result->_base), 0,
- sizeof(*result) - sizeof(result->_base));
- if (child) {
- CFRetain(child);
- result->_child = child;
- }
- CFRetain(certificate);
- result->_certificate = certificate;
- result->_isAnchor = SecTrustCertificateIsAnchor(certificate);
-
- return result;
-}
-
-SecCertificateRef SecTrustGetCertificate(SecTrustNodeRef node) {
- check(node);
- return node->_certificate;
-}
-
-CFArrayRef SecTrustNodeCopyProperties(SecTrustNodeRef node,
- SecTrustRef trust) {
- check(node);
- check(trust);
- CFMutableArrayRef summary = SecCertificateCopySummaryProperties(
- node->_certificate, SecTrustGetVerifyTime(trust));
- /* FIXME Add more details in the failure case. */
- return summary;
-}
-
-/* Attempt to verify this node's signature chain down to the child. */
-SecTrustState SecTrustNodeVerifySignatureChain(SecTrustNodeRef node) {
- /* FIXME */
- return kSecTrustStateUnknown;
-}
-
-
-/* See if the next candidate works. */
-SecTrustNodeRef SecTrustNodeCopyNextCandidate(SecTrustNodeRef node,
- SecTrustRef trust, SecFetchingState fetchingState) {
- check(node);
- check(trust);
-
- CFAbsoluteTime verifyTime = SecTrustGetVerifyTime(trust);
-
- for (;;) {
- /* If we have any unconsidered candidates left check those first. */
- while (node->_candidateIndex < CFArrayGetCount(node->_candidates)) {
- SecCertificateRef candidate = (SecCertificateRef)
- CFArrayGetValueAtIndex(node->_candidates, node->_candidateIndex);
- if (node->_fetchingState != kSecFetchingStateDone) {
- /* If we still have potential sources to fetch other candidates
- from we ignore expired candidates. */
- if (!SecCertificateIsValidOn(candidate, verifyTime)) {
- node->_candidateIndex++;
- continue;
- }
- }
-
- SecTrustNodeRef parent = SecTrustNodeCreate(candidate, node);
- CFArrayRemoveValueAtIndex(node->_candidates, node->_candidateIndex);
- if (SecTrustNodeVerifySignatureChain(parent) ==
- kSecTrustStateNotSigner) {
- /* This candidate parent is not a valid signer of its
- child. */
- CFRelease(parent);
- /* If another signature failed further down the chain we need
- to backtrack down to whatever child is still a valid
- candidate and has additional candidates to consider.
- @@@ We really want to make the fetchingState a global of
- SecTrust itself as well and not have any node go beyond the
- current state of SecTrust if there are other (read cheap)
- options to consider. */
- continue;
- }
- return parent;
- }
-
- /* We've run out of candidates in our current state so let's try to
- find some more. Note we fetch candidates in increasing order of
- cost in the hope we won't ever get to the more expensive fetching
- methods. */
- SecCertificateRef certificate = node->_certificate;
- switch (node->_fetchingState) {
- case kSecFetchingStatePassedIn:
- /* Get the list of candidates from SecTrust. */
- CFDataRef akid = SecCertificateGetAuthorityKeyID(certificate);
- if (akid) {
- SecTrustAppendCandidatesWithAuthorityKeyID(akid, node->_candidates);
- } else {
- CFDataRef issuer =
- SecCertificateGetNormalizedIssuerContent(certificate);
- SecTrustAppendCandidatesWithSubject(issuer, node->_candidates);
- }
- node->_fetchingState = kSecFetchingStateLocal;
- break;
- case kSecFetchingStateLocal:
- /* Lookup candidates in the local database. */
- node->_fetchingState = kSecFetchingStateFromURL;
- break;
- case kSecFetchingStateFromURL:
- node->_fetchingState = kSecFetchingStateCheckExpired;
- break;
- case kSecFetchingStateCheckExpired:
- /* Time to start considering expired candidates as well. */
- node->_candidateIndex = 0;
- node->_fetchingState = kSecFetchingStateDone;
- break;
- case kSecFetchingStateDone;
- return NULL;
- }
- }
-
- CFAllocatorRef allocator = CFGetAllocator(node);
-
- /* A trust node has a number of states.
- 1) Look for issuing certificates by asking SecTrust about known
- parent certificates.
- 2) Look for issuing certificates in certificate databases (keychains)
- 3) Look for issuing certificates by going out to the web if the nodes
- certificate has a issuer location URL.
- 4) Look through expired or not yet valid candidates we have put aside.
-
- We go though the stages 1 though 3 looking for candidate issuer
- certificates. If a candidate certificate is not valid at verifyTime
- we put it in a to be examined later queue. If a candidate certificate
- is valid we verify if it actually signed our certificate (if possible).
- If not we discard it and continue on to the next candidate certificate.
- If it is we return a new SecTrustNodeRef for that certificate. */
-
- CFMutableArrayRef issuers = CFArrayCreateMutable(allocator, 0,
- &kCFTypeArrayCallBacks);
-
- /* Find a node's parent. */
- certificate = node->_certificate;
- CFDataRef akid = SecCertificateGetAuthorityKeyID(certificate);
- CFTypeRef candidates = NULL;
- if (akid) {
- candidates = (CFTypeRef)CFDictionaryGetValueForKey(skidDict, akid);
- if (candidates) {
- addValidIssuersFrom(issuers, certificate, candidates, true);
- }
- }
- if (!candidates) {
- CFDataRef issuer =
- SecCertificateGetNormalizedIssuerContent(certificate);
- candidates = (CFTypeRef)
- CFDictionaryGetValueForKey(subjectDict, issuer);
- addValidIssuersFrom(issuers, certificate, candidates, false);
- }
-
- if (CFArrayGetCount(issuers) == 0) {
- /* O no! we can't find an issuer for this certificate. Let's see
- if we can find one in the local database. */
- }
-
- return errSecSuccess;
-}
-
-CFArrayRef SecTrustNodeCopyNextChain(SecTrustNodeRef node,
- SecTrustRef trust) {
- /* Return the next full chain that isn't a reject unless we are in
- a state where we consider returning rejects. */
-
- switch (node->_fetchingState) {
- case kSecFetchingStatePassedIn:
- /* Get the list of candidates from SecTrust. */
- CFDataRef akid = SecCertificateGetAuthorityKeyID(certificate);
- if (akid) {
- SecTrustAppendCandidatesWithAuthorityKeyID(akid, node->_candidates);
- } else {
- CFDataRef issuer =
- SecCertificateGetNormalizedIssuerContent(certificate);
- SecTrustAppendCandidatesWithSubject(issuer, node->_candidates);
- }
- node->_fetchingState = kSecFetchingStateLocal;
- break;
- case kSecFetchingStateLocal:
- /* Lookup candidates in the local database. */
- node->_fetchingState = kSecFetchingStateFromURL;
- break;
- case kSecFetchingStateFromURL:
- node->_fetchingState = kSecFetchingStateCheckExpired;
- break;
- case kSecFetchingStateCheckExpired:
- /* Time to start considering expired candidates as well. */
- node->_candidateIndex = 0;
- node->_fetchingState = kSecFetchingStateDone;
- break;
- case kSecFetchingStateDone;
- return NULL;
- }
-}
-
-class Source {
- Iterator parentIterator(Cert);
-};
-
-class NodeCache {
- Set nodes;
-
- static bool unique(Node node) {
- if (nodes.contains(node))
- return false;
- nodes.add(node);
- return true;
- }
-
- static bool isAnchor(Cert cert);
-};
-
-class Node {
- Cert cert;
- Node child;
- int nextSource;
- Iterator parentIterator; /* For current source of parents. */
-
- Node(Cert inCert) : child(nil), cert(inCert), nextSource(0) {}
- Node(Node inChild, Cert inCert) : child(inChild), cert(inCert),
- nextSource(0) {}
-
- CertPath certPath() {
- CertPath path;
- Node node = this;
- while (node) {
- path.add(node.cert);
- node = node.child;
- }
- return path;
- }
-
- void contains(Cert cert) {
- Node node = this;
- while (node) {
- if (cert == node.cert)
- return true;
- node = node.child;
- }
- return false;
- }
-
- Node nextParent(Array currentSources) {
- for (;;) {
- if (!nextSource ||
- parentIterator == currentSources[nextSource - 1].end()) {
- if (nextSource == currentSources.count) {
- /* We ran out of parent sources. */
- return nil;
- }
- parentIterator = currentSources[nextSource++].begin();
- }
- Certificate cert = *parentIterator++;
- /* Check for cycles and self signed chains. */
- if (!contains(cert)) {
- Node node = Node(this, parent);
- if (!NodeCache.unique(node))
- return node;
- }
- }
- }
-};
-
-
-class PathBuilder {
- List nodes;
- List rejects;
- Array currentSources;
- Iterator nit;
- Array allSources;
- Iterator sourceIT;
- CertPath chain;
-
- PathBuilder(Cert cert) {
- nodes.append(Node(cert));
- nit = nodes.begin();
- sourceIT = allSources.begin();
- }
-
- nextAnchoredPath() {
- if (nit == nodes.end()) {
- /* We should add another source to the list of sources to
- search. */
- if (sourceIT == allSources.end()) {
- /* No more sources to add. */
- }
- currentSources += *sourceIT++;
- /* Resort nodes by size. */
- Nodes.sortBySize();
- nit = nodes.begin();
- /* Set the source list for all nodes. */
-
- }
- while (Node node = *nit) {
- Node candidate = node.nextParent(currentSources);
- if (!candidate) {
- /* The current node has no more candidate parents so move
- along. */
- nit++;
- continue;
- }
-
- if (candidate.isAnchored) {
- candidates.append(candidate);
- } else
- nodes.insert(candidate, nit);
- }
- }
-
- findValidPath() {
- while (Node node = nextAnchoredPath()) {
- if (node.isValid()) {
- chain = node.certPath;
- break;
- }
- rejects.append(node);
- }
- }
-}
-
-
-#endif