/ OSX / libsecurity_keychain / lib / TrustStore.cpp
TrustStore.cpp
  1  /*
  2   * Copyright (c) 2002-2004,2011-2014 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  
 24  //
 25  // TrustStore.h - Abstract interface to permanent user trust assignments
 26  //
 27  #include <security_keychain/TrustStore.h>
 28  #include <security_keychain/Globals.h>
 29  #include <security_keychain/Certificate.h>
 30  #include <security_keychain/KCCursor.h>
 31  #include <security_keychain/SecCFTypes.h>
 32  #include <security_cdsa_utilities/Schema.h>
 33  #include <Security/SecTrustSettingsPriv.h>
 34  
 35  namespace Security {
 36  namespace KeychainCore {
 37  
 38  
 39  //
 40  // Make and break: trivial
 41  //
 42  TrustStore::TrustStore(Allocator &alloc)
 43  	: allocator(alloc), mRootsValid(false), mRootBytes(allocator), mMutex(Mutex::recursive)
 44  {
 45  }
 46  
 47  TrustStore::~TrustStore()
 48  { }
 49  
 50  //
 51  // Retrieve the trust setting for a (certificate, policy) pair.
 52  //
 53  SecTrustUserSetting TrustStore::find(Certificate *cert, Policy *policy,
 54  	StorageManager::KeychainList &keychainList)
 55  {
 56  	StLock<Mutex> _(mMutex);
 57  
 58  	if (Item item = findItem(cert, policy, keychainList)) {
 59  		// Make sure that the certificate is available in some keychain,
 60  		// to provide a basis for editing the trust setting that we're returning.
 61  		if (cert->keychain() == NULL) {
 62  			if (cert->findInKeychain(keychainList) == NULL) {
 63  				Keychain defaultKeychain = Keychain::optional(NULL);
 64  				if (Keychain location = item->keychain()) {
 65  					try {
 66  						cert->copyTo(location);	// add cert to the trust item's keychain
 67  					} catch (...) {
 68  						secinfo("trusteval", "failed to add certificate %p to keychain \"%s\"",
 69  							cert, location->name());
 70  						try {
 71  							if (&*location != &*defaultKeychain)
 72  								cert->copyTo(defaultKeychain);	// try the default (if it's not the same)
 73  						} catch (...) {
 74  							// unable to add the certificate
 75  							secinfo("trusteval", "failed to add certificate %p to keychain \"%s\"",
 76  								cert, defaultKeychain->name());
 77  						}
 78  					}
 79  				}
 80  			}
 81  		}
 82  		CssmDataContainer data;
 83  		item->getData(data);
 84  		if (data.length() != sizeof(TrustData))
 85  			MacOSError::throwMe(errSecInvalidTrustSetting);
 86  		TrustData &trust = *data.interpretedAs<TrustData>();
 87  		if (trust.version != UserTrustItem::currentVersion)
 88  			MacOSError::throwMe(errSecInvalidTrustSetting);
 89  		return trust.trust;
 90  	} else {
 91  		return kSecTrustResultUnspecified;
 92  	}
 93  }
 94  
 95  
 96  //
 97  // Set an individual trust element
 98  //
 99  void TrustStore::assign(Certificate *cert, Policy *policy, SecTrustUserSetting trust)
100  {
101  	StLock<Mutex> _(mMutex);
102  
103  	TrustData trustData = { UserTrustItem::currentVersion, trust };
104  	Keychain defaultKeychain = Keychain::optional(NULL);
105  	Keychain trustLocation = defaultKeychain;	// default keychain, unless trust entry found
106  	StorageManager::KeychainList searchList;
107  	globals().storageManager.getSearchList(searchList);
108  
109  	if (Item item = findItem(cert, policy, searchList)) {
110  		// user has a trust setting in a keychain - modify that
111  		trustLocation = item->keychain();
112  		if (trust == kSecTrustResultUnspecified)
113  			item->keychain()->deleteItem(item);
114  		else
115  			item->modifyContent(NULL, sizeof(trustData), &trustData);
116  	} else {
117  		// no trust entry: make one
118  		if (trust != kSecTrustResultUnspecified) {
119  			Item item = new UserTrustItem(cert, policy, trustData);
120  			if (Keychain location = cert->keychain()) {
121  				try {
122  					location->add(item);				// try the cert's keychain first
123  					trustLocation = location;
124  				} catch (...) {
125  					if (&*location != &*defaultKeychain)
126  						defaultKeychain->add(item);		// try the default (if it's not the same)
127  				}
128  			} else {
129  				defaultKeychain->add(item);				// raw cert - use default keychain
130  			}
131  		}
132  	}
133  
134  	// Make sure that the certificate is available in some keychain,
135  	// to provide a basis for editing the trust setting that we're assigning.
136  	if (cert->keychain() == NULL) {
137  		if (cert->findInKeychain(searchList) == NULL) {
138  			try {
139  				cert->copyTo(trustLocation);	// add cert to the trust item's keychain
140  			} catch (...) {
141  				secinfo("trusteval", "failed to add certificate %p to keychain \"%s\"",
142  					cert, trustLocation->name());
143  				try {
144  					if (&*trustLocation != &*defaultKeychain)
145  						cert->copyTo(defaultKeychain);	// try the default (if it's not the same)
146  				} catch (...) {
147  					// unable to add the certificate
148  					secinfo("trusteval", "failed to add certificate %p to keychain \"%s\"",
149  						cert, defaultKeychain->name());
150  				}
151  			}
152  		}
153  	}
154  }
155  
156  
157  //
158  // Search the user's configured keychains for a trust setting.
159  // If found, return it (as a TrustItem). Otherwise, return NULL.
160  // Note that this function throws if a "real" error is encountered.
161  //
162  Item TrustStore::findItem(Certificate *cert, Policy *policy,
163  	StorageManager::KeychainList &keychainList)
164  {
165  	// As of OS X 10.5, user trust records are no longer stored in keychains.
166  	// SecTrustSetUserTrust was replaced with SecTrustSettingsSetTrustSettings,
167  	// which stores per-user trust in a separate root-owned file. This method,
168  	// however, would continue to find old trust records created prior to 10.5.
169  	// Since those are increasingly unlikely to exist (and cannot be edited),
170  	// we no longer need or want to look for them anymore.
171  	return ((ItemImpl*)NULL);
172  
173  #if 0
174  	StLock<Mutex> _(mMutex);
175  
176  	try {
177  		SecKeychainAttribute attrs[2];
178  		CssmAutoData certIndex(Allocator::standard());
179  		UserTrustItem::makeCertIndex(cert, certIndex);
180  		attrs[0].tag = kSecTrustCertAttr;
181  		attrs[0].length = (UInt32)certIndex.length();
182  		attrs[0].data = certIndex.data();
183  		const CssmOid &policyOid = policy->oid();
184  		attrs[1].tag = kSecTrustPolicyAttr;
185  		attrs[1].length = (UInt32)policyOid.length();
186  		attrs[1].data = policyOid.data();
187  		SecKeychainAttributeList attrList = { 2, attrs };
188  		KCCursor cursor(keychainList, CSSM_DL_DB_RECORD_USER_TRUST, &attrList);
189  		Item item;
190  		if (cursor->next(item))
191  			return item;
192  	}
193  	catch (const CommonError &error) {}
194  
195  	return ((ItemImpl*)NULL);	// no trust schema, no records, no error
196  #endif
197  }
198  
199  void TrustStore::getCssmRootCertificates(CertGroup &rootCerts)
200  {
201  	StLock<Mutex> _(mMutex);
202  
203  	if (!mRootsValid)
204  		loadRootCertificates();
205  	rootCerts = CertGroup(CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_BER, CSSM_CERTGROUP_DATA);
206  	rootCerts.blobCerts() = &mRoots[0];
207  	rootCerts.count() = (uint32)mRoots.size();
208  }
209  
210  //
211  // Load root (anchor) certificates from disk
212  //
213  void TrustStore::loadRootCertificates()
214  {
215  	StLock<Mutex> _(mMutex);
216  
217  	CFRef<CFArrayRef> anchors;
218  	OSStatus ortn;
219  
220  	/*
221  	 * Get the current set of all positively trusted anchors.
222  	 */
223  	ortn = SecTrustSettingsCopyUnrestrictedRoots(
224  		true, true, true,		/* all domains */
225  		anchors.take());
226  	if(ortn) {
227  		MacOSError::throwMe(ortn);
228  	}
229  
230  	// how many data bytes do we need?
231  	size_t size = 0;
232  	CFIndex numCerts = CFArrayGetCount(anchors);
233  	CSSM_RETURN crtn;
234  	for(CFIndex dex=0; dex<numCerts; dex++) {
235  		SecCertificateRef certRef = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, dex);
236  		CSSM_DATA certData;
237  		crtn = SecCertificateGetData(certRef, &certData);
238  		if(crtn) {
239  			CssmError::throwMe(crtn);
240  		}
241  		size += certData.Length;
242  	}
243  	mRootBytes.length(size);
244  
245  	// fill CssmData vector while copying data bytes together
246  	mRoots.clear();
247  	uint8 *base = mRootBytes.data<uint8>();
248  	for(CFIndex dex=0; dex<numCerts; dex++) {
249  		SecCertificateRef certRef = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, dex);
250  		CSSM_DATA certData;
251  		SecCertificateGetData(certRef, &certData);
252  		memcpy(base, certData.Data, certData.Length);
253  		mRoots.push_back(CssmData(base, certData.Length));
254  		base += certData.Length;
255  	}
256  
257  	secinfo("anchors", "%ld anchors loaded", (long)numCerts);
258  
259  	mRootsValid = true;			// ready to roll
260  }
261  
262  } // end namespace KeychainCore
263  } // end namespace Security