[[[ Support storing SSL client certificate passphrases in OSX Keychain. * subversion/libsvn_subr/cmdline.c (svn_cmdline_set_up_auth_baton): Add OSX Keychain SSL client certificate passphrase provider to the providers array. * subversion/libsvn_subr/macos_keychain.c (keychain_password_set, keychain_password_get): Added NULL check for username. (keychain_ssl_client_cert_pw_first_creds, keychain_ssl_client_cert_pw_save_creds, svn_auth_get_keychain_ssl_client_cert_pw_provider): New functions. (keychain_ssl_client_cert_pw_provider): New object. * subversion/libsvn_subr/ssl_client_cert_pw_providers.c (svn_auth__ssl_client_cert_pw_file_save_creds_helper): Add OSX Keychain SSL client certificate passphrase provider to the list of providers which store passphrases encrypted. * subversion/include/svn_auth.h (svn_auth_get_keychain_ssl_client_cert_pw_provider): New function. ]]] Index: subversion/libsvn_subr/cmdline.c =================================================================== --- subversion/libsvn_subr/cmdline.c (revision 32800) +++ subversion/libsvn_subr/cmdline.c (working copy) @@ -510,6 +510,9 @@ #ifdef SVN_HAVE_KEYCHAIN_SERVICES svn_auth_get_keychain_simple_provider(&provider, pool); APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; + + svn_auth_get_keychain_ssl_client_cert_pw_provider(&provider, pool); + APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider; #endif continue; } Index: subversion/libsvn_subr/macos_keychain.c =================================================================== --- subversion/libsvn_subr/macos_keychain.c (revision 32800) +++ subversion/libsvn_subr/macos_keychain.c (working copy) @@ -75,13 +75,17 @@ SecKeychainSetUserInteractionAllowed(FALSE); status = SecKeychainFindGenericPassword(NULL, strlen(realmstring), - realmstring, strlen(username), + realmstring, username == NULL + ? 0 + : strlen(username), username, 0, NULL, &item); if (status) { if (status == errSecItemNotFound) status = SecKeychainAddGenericPassword(NULL, strlen(realmstring), - realmstring, strlen(username), + realmstring, username == NULL + ? 0 + : strlen(username), username, strlen(password), password, NULL); } @@ -117,7 +121,9 @@ SecKeychainSetUserInteractionAllowed(FALSE); status = SecKeychainFindGenericPassword(NULL, strlen(realmstring), - realmstring, strlen(username), + realmstring, username == NULL + ? 0 + : strlen(username), username, &length, &data, NULL); if (non_interactive) @@ -175,6 +181,52 @@ keychain_simple_save_creds }; +/* Get cached encrypted credentials from the ssl client cert password + provider's cache. */ +static svn_error_t * +keychain_ssl_client_cert_pw_first_creds(void **credentials, + void **iter_baton, + void *provider_baton, + apr_hash_t *parameters, + const char *realmstring, + apr_pool_t *pool) +{ + return svn_auth__ssl_client_cert_pw_file_first_creds_helper + (credentials, + iter_baton, provider_baton, + parameters, realmstring, + keychain_password_get, + SVN_AUTH__KEYCHAIN_PASSWORD_TYPE, + pool); +} + +/* Save encrypted credentials to the ssl client cert password provider's + cache. */ +static svn_error_t * +keychain_ssl_client_cert_pw_save_creds(svn_boolean_t *saved, + void *credentials, + void *provider_baton, + apr_hash_t *parameters, + const char *realmstring, + apr_pool_t *pool) +{ + return svn_auth__ssl_client_cert_pw_file_save_creds_helper + (saved, credentials, + provider_baton, parameters, + realmstring, + keychain_password_set, + SVN_AUTH__KEYCHAIN_PASSWORD_TYPE, + pool); +} + +static const svn_auth_provider_t keychain_ssl_client_cert_pw_provider = { + SVN_AUTH_CRED_SSL_CLIENT_CERT_PW, + keychain_ssl_client_cert_pw_first_creds, + NULL, + keychain_ssl_client_cert_pw_save_creds +}; + + /* Public API */ void svn_auth_get_keychain_simple_provider(svn_auth_provider_object_t **provider, @@ -186,4 +238,14 @@ *provider = po; } +void +svn_auth_get_keychain_ssl_client_cert_pw_provider + (svn_auth_provider_object_t **provider, + apr_pool_t *pool) +{ + svn_auth_provider_object_t *po = apr_pcalloc(pool, sizeof(*po)); + + po->vtable = &keychain_ssl_client_cert_pw_provider; + *provider = po; +} #endif /* SVN_HAVE_KEYCHAIN_SERVICES */ Index: subversion/libsvn_subr/ssl_client_cert_pw_providers.c =================================================================== --- subversion/libsvn_subr/ssl_client_cert_pw_providers.c (revision 32800) +++ subversion/libsvn_subr/ssl_client_cert_pw_providers.c (working copy) @@ -207,7 +207,8 @@ ahead and store it to disk. Else determine whether saving in plaintext is OK. */ if (strcmp(passtype, SVN_AUTH__KWALLET_PASSWORD_TYPE) == 0 - || strcmp(passtype, SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE) == 0) + || strcmp(passtype, SVN_AUTH__GNOME_KEYRING_PASSWORD_TYPE) == 0 + || strcmp(passtype, SVN_AUTH__KEYCHAIN_PASSWORD_TYPE) == 0) { may_save_passphrase = TRUE; } Index: subversion/include/svn_auth.h =================================================================== --- subversion/include/svn_auth.h (revision 32800) +++ subversion/include/svn_auth.h (working copy) @@ -825,6 +825,23 @@ void svn_auth_get_keychain_simple_provider(svn_auth_provider_object_t **provider, apr_pool_t *pool); + +/** + * Create and return @a *provider, an authentication provider of type @c + * svn_auth_cred_ssl_client_cert_pw_t that gets/sets information from the + * user's ~/.subversion configuration directory. Allocate @a *provider in + * @a pool. + * + * This is like svn_client_get_ssl_client_cert_pw_file_provider(), except + * that the password is stored in the Mac OS KeyChain. + * + * @since New in 1.6 + * @note This function is only available on Mac OS 10.2 and higher. + */ +void +svn_auth_get_keychain_ssl_client_cert_pw_provider + (svn_auth_provider_object_t **provider, + apr_pool_t *pool); #endif /* DARWIN || DOXYGEN */