]> git.saurik.com Git - apple/security.git/blobdiff - SecurityTool/macOS/keychain_delete.c
Security-59306.11.20.tar.gz
[apple/security.git] / SecurityTool / macOS / keychain_delete.c
diff --git a/SecurityTool/macOS/keychain_delete.c b/SecurityTool/macOS/keychain_delete.c
new file mode 100644 (file)
index 0000000..670bcc6
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2003-2019 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ *
+ * keychain_delete.c
+ */
+
+#include "keychain_delete.h"
+#include "keychain_find.h"
+
+#include "keychain_utilities.h"
+#include "security_tool.h"
+#include <unistd.h>
+#include <Security/SecIdentity.h>
+#include <Security/SecKeychain.h>
+#include <Security/SecKeychainItem.h>
+#include <Security/SecTrustSettings.h>
+
+static int
+do_delete(CFTypeRef keychainOrArray)
+{
+       /* @@@ SecKeychainDelete should really take a CFTypeRef argument. */
+       OSStatus result = SecKeychainDelete((SecKeychainRef)keychainOrArray);
+       if (result)
+       {
+               /* @@@ Add printing of keychainOrArray. */
+               sec_perror("SecKeychainDelete", result);
+       }
+
+       return result;
+}
+
+static int
+do_delete_certificate(CFTypeRef keychainOrArray, const char *name, const char *hash,
+                      Boolean deleteTrust, Boolean deleteIdentity)
+{
+    OSStatus result = noErr;
+    SecKeychainItemRef itemToDelete = NULL;
+    if (!name && !hash) {
+        return SHOW_USAGE_MESSAGE;
+    }
+
+    itemToDelete = find_unique_certificate(keychainOrArray, name, hash);
+    if (itemToDelete) {
+        OSStatus status = noErr;
+        if (deleteTrust) {
+            status = SecTrustSettingsRemoveTrustSettings((SecCertificateRef)itemToDelete,
+                                                         kSecTrustSettingsDomainUser);
+            if (status) {
+                // if trust settings do not exist, it's not an error.
+                if (status != errSecItemNotFound) {
+                    result = status;
+                    sec_perror("SecTrustSettingsRemoveTrustSettings (user)", result);
+                }
+            }
+            if (geteuid() == 0) {
+                status = SecTrustSettingsRemoveTrustSettings((SecCertificateRef)itemToDelete,
+                                                             kSecTrustSettingsDomainAdmin);
+                if (status) {
+                    if (status != errSecItemNotFound) {
+                        result = status;
+                        sec_perror("SecTrustSettingsRemoveTrustSettings (admin)", result);
+                    }
+                }
+            }
+        }
+        if (!result && deleteIdentity) {
+            SecIdentityRef identity = NULL;
+            status = SecIdentityCreateWithCertificate(keychainOrArray,
+                                                      (SecCertificateRef)itemToDelete,
+                                                      &identity);
+            if (status) {
+                // if the private key doesn't exist, and we succeed in deleting
+                // the certificate, overall result will still be good.
+                if (status == errSecItemNotFound) {
+                    status = noErr;
+                } else {
+                    result = status;
+                }
+            } else {
+                SecKeyRef keyToDelete = NULL;
+                status = SecIdentityCopyPrivateKey(identity, &keyToDelete);
+                if (status) {
+                    result = status;
+                } else {
+                    result = SecKeychainItemDelete((SecKeychainItemRef)keyToDelete);
+                    if (result) {
+                        sec_perror("SecKeychainItemDelete", result);
+                    }
+                }
+                safe_CFRelease(&keyToDelete);
+            }
+            safe_CFRelease(&identity);
+
+            if (status) {
+                fprintf(stderr, "Unable to obtain private key reference for \"%s\" (error %d)",
+                        (name) ? name : (hash) ? hash : "", (int) status);
+            }
+        }
+        if (!result) {
+            result = SecKeychainItemDelete(itemToDelete);
+            if (result) {
+                sec_perror("SecKeychainItemDelete", result);
+                goto cleanup;
+            }
+        }
+    } else {
+        result = 1;
+        fprintf(stderr, "Unable to delete certificate matching \"%s\"",
+                (name) ? name : (hash) ? hash : "");
+    }
+
+cleanup:
+    safe_CFRelease(&itemToDelete);
+
+    return result;
+}
+
+static int
+keychain_delete_cert_common(int argc, char * const *argv, Boolean delete_identity)
+{
+       CFTypeRef keychainOrArray = NULL;
+       char *name = NULL;
+       char *hash = NULL;
+       Boolean delete_trust = FALSE;
+       int ch, result = 0;
+
+       while ((ch = getopt(argc, argv, "hc:Z:t")) != -1)
+       {
+               switch  (ch)
+               {
+                       case 'c':
+                               name = optarg;
+                               break;
+                       case 'Z':
+                               hash = optarg;
+                               break;
+                       case 't':
+                               delete_trust = TRUE;
+                               break;
+                       case '?':
+                       default:
+                               result = 2; /* @@@ Return 2 triggers usage message. */
+                               goto cleanup;
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       keychainOrArray = keychain_create_array(argc, argv);
+
+       result = do_delete_certificate(keychainOrArray, name, hash, delete_trust, delete_identity);
+
+cleanup:
+       safe_CFRelease(&keychainOrArray);
+
+       return result;
+}
+
+int
+keychain_delete_certificate(int argc, char * const *argv)
+{
+    return keychain_delete_cert_common(argc, argv, FALSE);
+}
+
+int
+keychain_delete_identity(int argc, char * const *argv)
+{
+    return keychain_delete_cert_common(argc, argv, TRUE);
+}
+
+int
+keychain_delete(int argc, char * const *argv)
+{
+       CFTypeRef keychainOrArray = NULL;
+       int ch, result = 0;
+
+       while ((ch = getopt(argc, argv, "h")) != -1)
+       {
+               switch  (ch)
+               {
+               case '?':
+               default:
+                       return SHOW_USAGE_MESSAGE;
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+
+       keychainOrArray = keychain_create_array(argc, argv);
+
+       result = do_delete(keychainOrArray);
+       if (keychainOrArray)
+               CFRelease(keychainOrArray);
+
+       return result;
+}