keychain_delete.c
1 /* 2 * Copyright (c) 2003-2019 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 * 23 * keychain_delete.c 24 */ 25 26 #include "keychain_delete.h" 27 #include "keychain_find.h" 28 29 #include "keychain_utilities.h" 30 #include "security_tool.h" 31 #include <unistd.h> 32 #include <Security/SecIdentity.h> 33 #include <Security/SecKeychain.h> 34 #include <Security/SecKeychainItem.h> 35 #include <Security/SecTrustSettings.h> 36 37 static int 38 do_delete(CFTypeRef keychainOrArray) 39 { 40 /* @@@ SecKeychainDelete should really take a CFTypeRef argument. */ 41 OSStatus result = SecKeychainDelete((SecKeychainRef)keychainOrArray); 42 if (result) 43 { 44 /* @@@ Add printing of keychainOrArray. */ 45 sec_perror("SecKeychainDelete", result); 46 } 47 48 return result; 49 } 50 51 static int 52 do_delete_certificate(CFTypeRef keychainOrArray, const char *name, const char *hash, 53 Boolean deleteTrust, Boolean deleteIdentity) 54 { 55 OSStatus result = noErr; 56 SecKeychainItemRef itemToDelete = NULL; 57 if (!name && !hash) { 58 return SHOW_USAGE_MESSAGE; 59 } 60 61 itemToDelete = find_unique_certificate(keychainOrArray, name, hash); 62 if (itemToDelete) { 63 OSStatus status = noErr; 64 if (deleteTrust) { 65 status = SecTrustSettingsRemoveTrustSettings((SecCertificateRef)itemToDelete, 66 kSecTrustSettingsDomainUser); 67 if (status) { 68 // if trust settings do not exist, it's not an error. 69 if (status != errSecItemNotFound) { 70 result = status; 71 sec_perror("SecTrustSettingsRemoveTrustSettings (user)", result); 72 } 73 } 74 if (geteuid() == 0) { 75 status = SecTrustSettingsRemoveTrustSettings((SecCertificateRef)itemToDelete, 76 kSecTrustSettingsDomainAdmin); 77 if (status) { 78 if (status != errSecItemNotFound) { 79 result = status; 80 sec_perror("SecTrustSettingsRemoveTrustSettings (admin)", result); 81 } 82 } 83 } 84 } 85 if (!result && deleteIdentity) { 86 SecIdentityRef identity = NULL; 87 status = SecIdentityCreateWithCertificate(keychainOrArray, 88 (SecCertificateRef)itemToDelete, 89 &identity); 90 if (status) { 91 // if the private key doesn't exist, and we succeed in deleting 92 // the certificate, overall result will still be good. 93 if (status == errSecItemNotFound) { 94 status = noErr; 95 } else { 96 result = status; 97 } 98 } else { 99 SecKeyRef keyToDelete = NULL; 100 status = SecIdentityCopyPrivateKey(identity, &keyToDelete); 101 if (status) { 102 result = status; 103 } else { 104 result = SecKeychainItemDelete((SecKeychainItemRef)keyToDelete); 105 if (result) { 106 sec_perror("SecKeychainItemDelete", result); 107 } 108 } 109 safe_CFRelease(&keyToDelete); 110 } 111 safe_CFRelease(&identity); 112 113 if (status) { 114 fprintf(stderr, "Unable to obtain private key reference for \"%s\" (error %d)", 115 (name) ? name : (hash) ? hash : "", (int) status); 116 } 117 } 118 if (!result) { 119 result = SecKeychainItemDelete(itemToDelete); 120 if (result) { 121 sec_perror("SecKeychainItemDelete", result); 122 goto cleanup; 123 } 124 } 125 } else { 126 result = 1; 127 fprintf(stderr, "Unable to delete certificate matching \"%s\"", 128 (name) ? name : (hash) ? hash : ""); 129 } 130 131 cleanup: 132 safe_CFRelease(&itemToDelete); 133 134 return result; 135 } 136 137 static int 138 keychain_delete_cert_common(int argc, char * const *argv, Boolean delete_identity) 139 { 140 CFTypeRef keychainOrArray = NULL; 141 char *name = NULL; 142 char *hash = NULL; 143 Boolean delete_trust = FALSE; 144 int ch, result = 0; 145 146 while ((ch = getopt(argc, argv, "hc:Z:t")) != -1) 147 { 148 switch (ch) 149 { 150 case 'c': 151 name = optarg; 152 break; 153 case 'Z': 154 hash = optarg; 155 break; 156 case 't': 157 delete_trust = TRUE; 158 break; 159 case '?': 160 default: 161 result = 2; /* @@@ Return 2 triggers usage message. */ 162 goto cleanup; 163 } 164 } 165 166 argc -= optind; 167 argv += optind; 168 169 keychainOrArray = keychain_create_array(argc, argv); 170 171 result = do_delete_certificate(keychainOrArray, name, hash, delete_trust, delete_identity); 172 173 cleanup: 174 safe_CFRelease(&keychainOrArray); 175 176 return result; 177 } 178 179 int 180 keychain_delete_certificate(int argc, char * const *argv) 181 { 182 return keychain_delete_cert_common(argc, argv, FALSE); 183 } 184 185 int 186 keychain_delete_identity(int argc, char * const *argv) 187 { 188 return keychain_delete_cert_common(argc, argv, TRUE); 189 } 190 191 int 192 keychain_delete(int argc, char * const *argv) 193 { 194 CFTypeRef keychainOrArray = NULL; 195 int ch, result = 0; 196 197 while ((ch = getopt(argc, argv, "h")) != -1) 198 { 199 switch (ch) 200 { 201 case '?': 202 default: 203 return SHOW_USAGE_MESSAGE; 204 } 205 } 206 207 argc -= optind; 208 argv += optind; 209 210 keychainOrArray = keychain_create_array(argc, argv); 211 212 result = do_delete(keychainOrArray); 213 if (keychainOrArray) 214 CFRelease(keychainOrArray); 215 216 return result; 217 }