Пример #1
0
/* Reads certificates from the list of known locations into store.  Stops when
 * any location contains any certificates, to prevent spending unnecessary time
 * adding redundant certificates, e.g. when both a certificate bundle and
 * individual certificates exist in the same directory.
 */
static void read_trusted_roots_from_known_locations(HCERTSTORE store)
{
    HCERTSTORE from = CertOpenStore(CERT_STORE_PROV_MEMORY,
     X509_ASN_ENCODING, 0, CERT_STORE_CREATE_NEW_FLAG, NULL);

    if (from)
    {
        DWORD i;
        BOOL ret = FALSE;

#ifdef HAVE_SECURITY_SECURITY_H
        OSStatus status;
        CFArrayRef rootCerts;

        status = SecTrustCopyAnchorCertificates(&rootCerts);
        if (status == noErr)
        {
            int i;
            for (i = 0; i < CFArrayGetCount(rootCerts); i++)
            {
                SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(rootCerts, i);
                CFDataRef certData;
                if ((status = SecKeychainItemExport(cert, kSecFormatX509Cert, 0, NULL, &certData)) == noErr)
                {
                    if (CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
                            CFDataGetBytePtr(certData), CFDataGetLength(certData),
                            CERT_STORE_ADD_NEW, NULL))
                        ret = TRUE;
                    else
                        WARN("adding root cert %d failed: %08x\n", i, GetLastError());
                    CFRelease(certData);
                }
                else
                    WARN("could not export certificate %d to X509 format: 0x%08x\n", i, (unsigned int)status);
            }
            CFRelease(rootCerts);
        }
#endif

        for (i = 0; !ret &&
         i < sizeof(CRYPT_knownLocations) / sizeof(CRYPT_knownLocations[0]);
         i++)
            ret = import_certs_from_path(CRYPT_knownLocations[i], from, TRUE);
        check_and_store_certs(from, store);
    }
    CertCloseStore(from, 0);
}
Пример #2
0
static int 
keychain_iter_start(hx509_context context,
		    hx509_certs certs, void *data, void **cursor)
{
    struct ks_keychain *ctx = data;
    struct iter *iter;

    iter = calloc(1, sizeof(*iter));
    if (iter == NULL) {
	hx509_set_error_string(context, 0, ENOMEM, "out of memory");
	return ENOMEM;
    }

    if (ctx->anchors) {
        CFArrayRef anchors;
	int ret;
	int i;

	ret = hx509_certs_init(context, "MEMORY:ks-file-create", 
			       0, NULL, &iter->certs);
	if (ret) {
	    free(iter);
	    return ret;
	}

	ret = SecTrustCopyAnchorCertificates(&anchors);
	if (ret != 0) {
	    hx509_certs_free(&iter->certs);
	    free(iter);
	    hx509_set_error_string(context, 0, ENOMEM, 
				   "Can't get trust anchors from Keychain");
	    return ENOMEM;
	}
	for (i = 0; i < CFArrayGetCount(anchors); i++) {
	    SecCertificateRef cr; 
	    hx509_cert cert;
	    CSSM_DATA cssm;

	    cr = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, i);

	    SecCertificateGetData(cr, &cssm);

	    ret = hx509_cert_init_data(context, cssm.Data, cssm.Length, &cert);
	    if (ret)
		continue;

	    ret = hx509_certs_add(context, iter->certs, cert);
	    hx509_cert_free(cert);
	}
	CFRelease(anchors);
    }

    if (iter->certs) {
	int ret;
	ret = hx509_certs_start_seq(context, iter->certs, &iter->cursor);
	if (ret) {
	    hx509_certs_free(&iter->certs);
	    free(iter);
	    return ret;
	}
    } else {
	OSStatus ret;

	ret = SecKeychainSearchCreateFromAttributes(ctx->keychain,
						    kSecCertificateItemClass,
						    NULL,
						    &iter->searchRef);
	if (ret) {
	    free(iter);
	    hx509_set_error_string(context, 0, ret, 
				   "Failed to start search for attributes");
	    return ENOMEM;
	}
    }

    *cursor = iter;
    return 0;
}
/*
 * Given a SecIdentityRef, do our best to construct a complete, ordered, and 
 * verified cert chain, returning the result in a CFArrayRef. The result is 
 * suitable for use when calling SSLSetCertificate().
 */
OSStatus sslCompleteCertChain(
	SecIdentityRef 		identity, 
	SecCertificateRef	trustedAnchor,	// optional additional trusted anchor
	bool 				includeRoot, 	// include the root in outArray
	CFArrayRef			*outArray)		// created and RETURNED
{
	CFMutableArrayRef 			certArray;
	SecTrustRef					secTrust = NULL;
	SecPolicyRef				policy = NULL;
	SecPolicySearchRef			policySearch = NULL;
	SecTrustResultType			secTrustResult;
	CSSM_TP_APPLE_EVIDENCE_INFO *dummyEv;			// not used
	CFArrayRef					certChain = NULL;   // constructed chain
	CFIndex 					numResCerts;
	
	certArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
	CFArrayAppendValue(certArray, identity);
	
	/*
	 * Case 1: identity is a root; we're done. Note that this case
	 * overrides the includeRoot argument.
	 */
	SecCertificateRef certRef;
	OSStatus ortn = SecIdentityCopyCertificate(identity, &certRef);
	if(ortn) {
		/* should never happen */
		cssmPerror("SecIdentityCopyCertificate", ortn);
		return ortn;
	}
	bool isRoot = isCertRefRoot(certRef);
	if(isRoot) {
		*outArray = certArray;
		CFRelease(certRef);
		return errSecSuccess;
	}
	
	/* 
	 * Now use SecTrust to get a complete cert chain, using all of the 
	 * user's keychains to look for intermediate certs.
	 * NOTE this does NOT handle root certs which are not in the system
	 * root cert DB. (The above case, where the identity is a root cert, does.)
	 */
	CFMutableArrayRef subjCerts = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks);
	CFArraySetValueAtIndex(subjCerts, 0, certRef);
			
	/* the array owns the subject cert ref now */
	CFRelease(certRef);
	
	/* Get a SecPolicyRef for generic X509 cert chain verification */
	ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3,
		&CSSMOID_APPLE_X509_BASIC,
		NULL,				// value
		&policySearch);
	if(ortn) {
		cssmPerror("SecPolicySearchCreate", ortn);
		goto errOut;
	}
	ortn = SecPolicySearchCopyNext(policySearch, &policy);
	if(ortn) {
		cssmPerror("SecPolicySearchCopyNext", ortn);
		goto errOut;
	}

	/* build a SecTrustRef for specified policy and certs */
	ortn = SecTrustCreateWithCertificates(subjCerts,
		policy, &secTrust);
	if(ortn) {
		cssmPerror("SecTrustCreateWithCertificates", ortn);
		goto errOut;
	}
	
	if(trustedAnchor) {
		/* 
		 * Tell SecTrust to trust this one in addition to the current
		 * trusted system-wide anchors.
		 */
		CFMutableArrayRef newAnchors;
		CFArrayRef currAnchors;
		
		ortn = SecTrustCopyAnchorCertificates(&currAnchors);
		if(ortn) {
			/* should never happen */
			cssmPerror("SecTrustCopyAnchorCertificates", ortn);
			goto errOut;
		}
		newAnchors = CFArrayCreateMutableCopy(NULL,
			CFArrayGetCount(currAnchors) + 1,
			currAnchors);
		CFRelease(currAnchors);
		CFArrayAppendValue(newAnchors, trustedAnchor);
		ortn = SecTrustSetAnchorCertificates(secTrust, newAnchors);
		CFRelease(newAnchors);
		if(ortn) {
			cssmPerror("SecTrustSetAnchorCertificates", ortn);
			goto errOut;
		}
	}
	/* evaluate: GO */
	ortn = SecTrustEvaluate(secTrust, &secTrustResult);
	if(ortn) {
		cssmPerror("SecTrustEvaluate", ortn);
		goto errOut;
	}
	switch(secTrustResult) {
		case kSecTrustResultUnspecified:
			/* cert chain valid, no special UserTrust assignments */
		case kSecTrustResultProceed:
			/* cert chain valid AND user explicitly trusts this */
			break;
		default:
			/*
			 * Cert chain construction failed. 
			 * Just go with the single subject cert we were given.
			 */
			printf("***Warning: could not construct completed cert chain\n");
			ortn = errSecSuccess;
			goto errOut;
	}

	/* get resulting constructed cert chain */
	ortn = SecTrustGetResult(secTrust, &secTrustResult, &certChain, &dummyEv);
	if(ortn) {
		cssmPerror("SecTrustEvaluate", ortn);
		goto errOut;
	}
	
	/*
	 * Copy certs from constructed chain to our result array, skipping 
	 * the leaf (which is already there, as a SecIdentityRef) and possibly
	 * a root.
	 */
	numResCerts = CFArrayGetCount(certChain);
	if(numResCerts < 2) {
		/*
		 * Can't happen: if subject was a root, we'd already have returned. 
		 * If chain doesn't verify to a root, we'd have bailed after
		 * SecTrustEvaluate().
		 */
		printf("***sslCompleteCertChain screwup: numResCerts %d\n", 
			(int)numResCerts);
		ortn = errSecSuccess;
		goto errOut;
	}
	if(!includeRoot) {
		/* skip the last (root) cert) */
		numResCerts--;
	}
	for(CFIndex dex=1; dex<numResCerts; dex++) {
		certRef = (SecCertificateRef)CFArrayGetValueAtIndex(certChain, dex);
		CFArrayAppendValue(certArray, certRef);
	}
errOut:
	/* clean up */
	if(secTrust) {
		CFRelease(secTrust);
	}
	if(subjCerts) {
		CFRelease(subjCerts);
	}
	if(policy) {
		CFRelease(policy);
	}
	if(policySearch) {
		CFRelease(policySearch);
	}
	*outArray = certArray;
	return ortn;
}
static int
keychain_iter_start(hx509_context context,
		    hx509_certs certs, void *data, void **cursor)
{
#ifndef __APPLE_TARGET_EMBEDDED__
    struct ks_keychain *ctx = data;
#endif
    struct iter *iter;

    iter = calloc(1, sizeof(*iter));
    if (iter == NULL) {
	hx509_set_error_string(context, 0, ENOMEM, "out of memory");
	return ENOMEM;
    }

#ifndef __APPLE_TARGET_EMBEDDED__
    if (ctx->anchors) {
        CFArrayRef anchors;
	int ret;
	int i;

	ret = hx509_certs_init(context, "MEMORY:ks-file-create",
			       0, NULL, &iter->certs);
	if (ret) {
	    free(iter);
	    return ret;
	}

	ret = SecTrustCopyAnchorCertificates(&anchors);
	if (ret != 0) {
	    hx509_certs_free(&iter->certs);
	    free(iter);
	    hx509_set_error_string(context, 0, ENOMEM,
				   "Can't get trust anchors from Keychain");
	    return ENOMEM;
	}
	for (i = 0; i < CFArrayGetCount(anchors); i++) {
	    SecCertificateRef cr;
	    hx509_cert cert;
	    CFDataRef dataref;

	    cr = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, i);

	    dataref = SecCertificateCopyData(cr);
	    if (dataref == NULL)
		continue;

	    ret = hx509_cert_init_data(context, CFDataGetBytePtr(dataref), CFDataGetLength(dataref), &cert);
	    CFRelease(dataref);
	    if (ret)
		continue;

	    ret = hx509_certs_add(context, iter->certs, cert);
	    hx509_cert_free(cert);
	}
	CFRelease(anchors);
	if (ret != 0) {
	    hx509_certs_free(&iter->certs);
	    free(iter);
	    hx509_set_error_string(context, 0, ret,
				   "Failed to add cert");
	    return ret;
	}
    }

    if (iter->certs) {
	int ret;
	ret = hx509_certs_start_seq(context, iter->certs, &iter->cursor);
	if (ret) {
	    hx509_certs_free(&iter->certs);
	    free(iter);
	    return ret;
	}
    } else
#endif
    {
	OSStatus ret;
	const void *keys[] = {
	    kSecClass,
	    kSecReturnRef,
	    kSecMatchLimit
	};
	const void *values[] = {
	    kSecClassCertificate,
	    kCFBooleanTrue,
	    kSecMatchLimitAll
	};

	CFDictionaryRef secQuery;

	secQuery = CFDictionaryCreate(NULL, keys, values,
				      sizeof(keys) / sizeof(*keys),
				      &kCFTypeDictionaryKeyCallBacks,
				      &kCFTypeDictionaryValueCallBacks);
	
	ret = SecItemCopyMatching(secQuery, (CFTypeRef *)&iter->search);
	CFRelease(secQuery);
	if (ret) {
	    free(iter);
	    return ENOMEM;
	}
    }

    *cursor = iter;
    return 0;
}
Пример #5
0
static int importKeychainToX509_STORE(X509_STORE* verifyStore, char* err, size_t err_len) {
    int status = 1;
    CFArrayRef result = NULL;
    OSStatus osStatus;

    // This copies all the certificates trusted by the system (regardless of what
    // keychain they're
    // attached to) into a CFArray.
    if ((osStatus = SecTrustCopyAnchorCertificates(&result)) != 0) {
        CFStringRef statusString = SecCopyErrorMessageString(osStatus, NULL);
        snprintf(err,
                 err_len,
                 "Error enumerating certificates: %s",
                 CFStringGetCStringPtr(statusString, kCFStringEncodingASCII));
        CFRelease(statusString);
        status = 0;
        goto CLEANUP;
    }

    CFDataRef rawData = NULL;
    X509* x509Cert = NULL;

    for (CFIndex i = 0; i < CFArrayGetCount(result); i++) {
        SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(result, i);

        rawData = SecCertificateCopyData(cert);
        if (!rawData) {
            snprintf(err, err_len, "Error enumerating certificates");
            status = 0;
            goto CLEANUP;
        }
        const uint8_t* rawDataPtr = CFDataGetBytePtr(rawData);

        // Parse an openssl X509 object from each returned certificate
        x509Cert = d2i_X509(NULL, &rawDataPtr, CFDataGetLength(rawData));
        if (!x509Cert) {
            snprintf(err,
                     err_len,
                     "Error parsing X509 certificate from system keychain: %s",
                     ERR_reason_error_string(ERR_peek_last_error()));
            status = 0;
            goto CLEANUP;
        }

        // Add the parsed X509 object to the X509_STORE verification store
        if (X509_STORE_add_cert(verifyStore, x509Cert) != 1) {
            int check_error_status = checkX509_STORE_error(err, err_len);
            if (!check_error_status) {
                status = check_error_status;
                goto CLEANUP;
            }
        }
        CFRelease(rawData);
        rawData = NULL;
        X509_free(x509Cert);
        x509Cert = NULL;
    }

CLEANUP:
    if (result != NULL) {
        CFRelease(result);
    }
    if (rawData != NULL) {
        CFRelease(rawData);
    }
    if (x509Cert != NULL) {
        X509_free(x509Cert);
    }
    return status;
}
Пример #6
0
/* Reads certificates from the list of known locations into store.  Stops when
 * any location contains any certificates, to prevent spending unnecessary time
 * adding redundant certificates, e.g. when both a certificate bundle and
 * individual certificates exist in the same directory.
 */
static void read_trusted_roots_from_known_locations(HCERTSTORE store)
{
    HCERTSTORE from = CertOpenStore(CERT_STORE_PROV_MEMORY,
     X509_ASN_ENCODING, 0, CERT_STORE_CREATE_NEW_FLAG, NULL);

    if (from)
    {
        DWORD i;
        BOOL ret = FALSE;

#ifdef __APPLE__
        OSStatus status;
        CFArrayRef rootCerts;
        KeychainExportFunc exportFunc = NULL;

#ifdef HAVE_DLFCN_H
        /* SecKeychainItemExport is deprecated on OS X 10.7, replaced by SecItemExport.
         * Since their parameters match, we can simply get the function pointer.
         */
        exportFunc = dlsym(RTLD_DEFAULT, "SecItemExport");
        if (exportFunc == NULL)
        {
            exportFunc = dlsym(RTLD_DEFAULT, "SecKeychainItemExport");
            if (exportFunc == NULL)
                WARN("unable to load a keychain export function: root certificates not loaded from Keychain\n");
            else
                TRACE("using SecKeychainItemExport()\n");
        }
        else
            TRACE("using SecItemExport()\n");
#else
        exportFunc = SecKeychainItemExport;
#endif

        status = SecTrustCopyAnchorCertificates(&rootCerts);
        if (status == noErr && exportFunc != NULL)
        {
            int i;
            for (i = 0; i < CFArrayGetCount(rootCerts); i++)
            {
                SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(rootCerts, i);
                CFDataRef certData;
                if ((status = exportFunc(cert, kSecFormatX509Cert, 0, NULL, &certData)) == noErr)
                {
                    if (CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING,
                            CFDataGetBytePtr(certData), CFDataGetLength(certData),
                            CERT_STORE_ADD_NEW, NULL))
                        ret = TRUE;
                    else
                        WARN("adding root cert %d failed: %08x\n", i, GetLastError());
                    CFRelease(certData);
                }
                else
                    WARN("could not export certificate %d to X509 format: 0x%08x\n", i, (unsigned int)status);
            }
            CFRelease(rootCerts);
        }
#endif

        for (i = 0; !ret &&
         i < sizeof(CRYPT_knownLocations) / sizeof(CRYPT_knownLocations[0]);
         i++)
            ret = import_certs_from_path(CRYPT_knownLocations[i], from, TRUE);
        check_and_store_certs(from, store);
    }
    CertCloseStore(from, 0);
}