I've just found out that the source code for Security is available and reading it, it occurs to me that the online documentation for SecTrustCopyAnchorCertificates has been erroneously copy-pasted from SecTrustCopyCustomAnchorCertificates. In fact, it seems SecTrustCopyAnchorCertificates must not depend on any global state besides the certificates stored in system's roots, meaning that it is the function I was looking for.
Post
Replies
Boosts
Views
Activity
[quote='816365022, DTS Engineer, /thread/769774?answerId=816365022#816365022']
If you want to do your own trust evaluation, a trust object is the best path forward because it does all the standard stuff that users expect to just work.
[/quote]
Unfortunately for what we need this approach doesn't suffice, as we don't get the information about the way certificates in the chain get verified, whether if it's through an OCSP response or with a CRL exclusion, which is necessary for next steps after we verify the certificate. We already have the necessary functionality internally that we rely on, and I'm simply porting it over to MacOS.
As for SecTrustSetAnchorCertificates the documentation mentions that it uses the certificates set by the function if it was called, otherwise it "uses a default set provided by the system". And, in fact, if I run a simple program that only calls the CopyAnchor it does what I expect and returns the array of all root certificates.
One caveat for me is that this seems to depend on global state and if a caller or callee at some point set their own anchor certificates for use with this API, we'll just get those in return. There is a mention that I can pass nil to the second argument of SetAnchor to restore the default set of anchor certificates, but it also takes in a SecIdentity object which for my purposes I do not have and cannot create, at least not within the context of where I'm writing the code.
I could generate a key for myself and create a self-signed certificate for the purpose of resetting the anchors and then disposing of the dummy certificate afterwards, but now I feel like I'm building a battering ram to open a fence.
Oh, hey, doesn't SecTrustCopyAnchorCertificates provide the functionality I described? It doesn't seem to be deprecated?
Alright thank you very much, I'll try to hack my way through and keep this open for now just in case.
This is MacOS, ideally I'd like to be able to support both Intel and ARM versions, though I assume that they should be the same?
Okay I've made some progress, to better understand the structure and the data that is stored within the keychain I tried debugPrinting out all the attributes within the identity, however it seems like only the kSecClassCertificate related attributes are present, and none of the kSecClassKey, even though I can retrieve the private key:
let query: [String: Any] = [kSecClass as String: kSecClassIdentity,
kSecMatchLimit as String: kSecMatchLimitAll,
kSecReturnAttributes as String: true,
kSecReturnRef as String: true,
];
var item: CFTypeRef?;
let status = SecItemCopyMatching(query as CFDictionary, &item);
debugPrint(status);
let output = item as! [[String: Any]];
for entry in output
{
do {
debugPrint("Certificate attributes:");
let label = entry[kSecAttrLabel as String];
debugPrint("Label: ", label!);
let certType: CSSM_CERT_TYPE = entry[kSecAttrCertificateType as String] as! CSSM_CERT_TYPE;
debugPrint("Cert item type: ", certType);
let issuer = entry[kSecAttrIssuer as String];
debugPrint("Issuer: ", String(data: issuer! as! Data, encoding: .utf8)!);
let serialNumber = entry[kSecAttrSerialNumber as String];
debugPrint("Serial number: ", serialNumber!);
var cert: SecCertificate?;
SecIdentityCopyCertificate(entry[kSecValueRef as String] as! SecIdentity, &cert);
debugPrint("Certificate: ", cert!);
debugPrint();
}
do {
debugPrint("Key attributes:");
let keyClass = entry[kSecAttrKeyClass as String];
debugPrint("Key class: ", keyClass);
let keyType = entry[kSecAttrKeyType as String];
debugPrint("Key type: ", keyType);
let applicationLabel = entry[kSecAttrApplicationLabel as String];
debugPrint("Application label: ", applicationLabel);
let applicationTag = entry[kSecAttrApplicationTag as String];
debugPrint("Application tag: ", applicationTag);
let sizeInBits = entry[kSecAttrKeySizeInBits as String];
debugPrint("Size in bits: ", sizeInBits);
let effectiveKeySize = entry[kSecAttrEffectiveKeySize as String];
debugPrint("Effective key size: ", effectiveKeySize);
var pkey: SecKey?;
SecIdentityCopyPrivateKey(entry[kSecValueRef as String] as! SecIdentity, &pkey);
debugPrint("Private key: ", pkey!);
debugPrint();
}
}
[quote='814638022, DTS Engineer, /thread/768855?answerId=814638022#814638022']
If so, the SecItem API has a specific class for that, kSecClassIdentity. This works in terms of SecIdentity objects.
[/quote]
Ah, thank you, that's exactly what I was looking for.