/ SecurityTool / macOS / keychain_delete.c
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  }