Hi,
In the app I’m working on, we rely on SecKeychainUnlock to verify that a password can be used to unlock the login keychain. When macOS 26.4 rolled out, we started getting bug reports that led me to a discovery that makes me think SecKeychainUnlock behavior was changed. I’m going to illustrate my findings with a sample code:
#include <pwd.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <Security/SecKeychain.h>
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
int
main(void)
{
char password[100];
printf("password: ");
scanf("%s", password);
struct passwd *home = getpwuid(getuid());
if (!(home && home->pw_dir))
return 1;
char path[1024];
strcat(path, home->pw_dir);
strcat(path, "/Library/Keychains/login.keychain-db");
SecKeychainRef keychain = NULL;
OSStatus result = SecKeychainOpen(path, &keychain);
if (result != errSecSuccess) {
fprintf(stderr, "SecKeychainOpen failed (error %d)\n", result);
return 1;
}
SecKeychainStatus status = 0;
result = SecKeychainGetStatus(keychain, &status);
if (result != errSecSuccess) {
fprintf(stderr, "SecKeychainGetStatus failed (error %d)\n", result);
return 1;
}
if (status & kSecUnlockStateStatus) {
printf("keychain is unlocked, will try to lock first\n");
result = SecKeychainLock(keychain);
if (result != errSecSuccess) {
fprintf(stderr, "SecKeychainLock failed (error %d)\n", result);
return 1;
}
printf("SecKeychainLock succeeded\n");
} else {
printf("keychain is locked\n");
}
result = SecKeychainUnlock(keychain, strlen(password), password, TRUE);
if (result == errSecSuccess) {
printf("SecKeychainUnlock succeeded\n");
printf("password '%s' appears to be valid\n", password);
} else {
printf("SecKeychainUnlock failed (error %d)\n", result);
printf("password '%s' appears to be invalid\n", password);
}
return 0;
}
Here are the outputs of this program on a machine running macOS 26.3 when provided with a correct password deadbeef and with an incorrect password foobar:
testuser1@tahoe1 kcdebug % ./kcdebug
password: deadbeef
keychain is unlocked, will try to lock first
SecKeychainLock succeeded
SecKeychainUnlock succeeded
password 'deadbeef' appears to be valid
testuser1@tahoe1 kcdebug % ./kcdebug
password: foobar
keychain is unlocked, will try to lock first
SecKeychainLock succeeded
SecKeychainUnlock failed (error -25293)
password 'foobar' appears to be invalid
And here are the outputs of this program on a machine running macOS 26.4:
testuser1@tahoe2 kcdebug % ./kcdebug
password: deadbeef
keychain is unlocked, will try to lock first
SecKeychainLock succeeded
SecKeychainUnlock succeeded
password 'deadbeef' appears to be valid
testuser1@tahoe2 kcdebug % ./kcdebug
password: foobar
keychain is unlocked, will try to lock first
SecKeychainLock succeeded
SecKeychainUnlock succeeded
password 'foobar' appears to be valid
I’m prepared to send a feedback with Feedback Assistant, but I would like to get a confirmation that this is indeed a bug and not an intended change in behavior. I would also like to know what are my options now. SecKeychainUnlock is just a means to an end; what I really need is the ability to keep the keychain password in sync with the user password when the latter is changed by our program.
Thanks in advance.