/ OSX / libsecurity_keychain / lib / TrustItem.cpp
TrustItem.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/TrustItem.h>
 28  #include <security_cdsa_utilities/Schema.h>
 29  #include <security_keychain/SecCFTypes.h>
 30  
 31  #include <security_asn1/secasn1.h>
 32  #include <security_asn1/SecNssCoder.h>
 33  #include <Security/oidscert.h>
 34  
 35  
 36  namespace Security {
 37  namespace KeychainCore {
 38  
 39  
 40  //
 41  // Construct a UserTrustItem from attributes and initial content
 42  //
 43  UserTrustItem::UserTrustItem(Certificate *cert, Policy *policy, const TrustData &trustData) :
 44  	ItemImpl((SecItemClass)CSSM_DL_DB_RECORD_USER_TRUST,
 45  		reinterpret_cast<SecKeychainAttributeList *>(NULL),
 46  		UInt32(sizeof(trustData)),
 47  		reinterpret_cast<const void *>(&trustData)),
 48  	mCertificate(cert), mPolicy(policy)
 49  {
 50  	secinfo("usertrust", "%p create(%p,%p) = %d",
 51  		this, cert, policy, SecTrustUserSetting(trustData.trust));
 52  }
 53  
 54  
 55  //
 56  // Destroy it
 57  //
 58  UserTrustItem::~UserTrustItem() 
 59  {
 60  	secinfo("usertrust", "%p destroyed", this);
 61  }
 62  
 63  
 64  //
 65  // Retrieve the trust value from a UserTrustItem
 66  //
 67  UserTrustItem::TrustData UserTrustItem::trust()
 68  {
 69  	StLock<Mutex>_(mMutex);
 70  	CssmDataContainer data;
 71  	getData(data);
 72  	if (data.length() != sizeof(TrustData))
 73  		MacOSError::throwMe(errSecInvalidTrustSetting);
 74  	return *data.interpretedAs<TrustData>();
 75  }
 76  
 77  
 78  //
 79  // Add item to keychain
 80  //
 81  PrimaryKey UserTrustItem::add(Keychain &keychain)
 82  {
 83  	StLock<Mutex>_(mMutex);
 84  	// If we already have a Keychain we can't be added.
 85  	if (mKeychain)
 86  		MacOSError::throwMe(errSecDuplicateItem);
 87  
 88  	populateAttributes();
 89  
 90  	CSSM_DB_RECORDTYPE recordType = mDbAttributes->recordType();
 91  
 92  	Db db(keychain->database());
 93  	// add the item to the (regular) db
 94  	try
 95  	{
 96  		mUniqueId = db->insert(recordType, mDbAttributes.get(), mData.get());
 97  		secinfo("usertrust", "%p inserted", this);
 98  	}
 99  	catch (const CssmError &e)
100  	{
101  		if (e.osStatus() != CSSMERR_DL_INVALID_RECORDTYPE)
102  			throw;
103  
104  		// Create the trust relation and try again.
105  		secinfo("usertrust", "adding schema relation for user trusts");
106  		db->createRelation(CSSM_DL_DB_RECORD_USER_TRUST, "CSSM_DL_DB_RECORD_USER_TRUST",
107  			Schema::UserTrustSchemaAttributeCount,
108  			Schema::UserTrustSchemaAttributeList,
109  			Schema::UserTrustSchemaIndexCount,
110  			Schema::UserTrustSchemaIndexList);
111  		keychain->keychainSchema()->didCreateRelation(
112  			CSSM_DL_DB_RECORD_USER_TRUST,
113  			"CSSM_DL_DB_RECORD_USER_TRUST",
114  			Schema::UserTrustSchemaAttributeCount,
115  			Schema::UserTrustSchemaAttributeList,
116  			Schema::UserTrustSchemaIndexCount,
117  			Schema::UserTrustSchemaIndexList);
118  
119  		mUniqueId = db->insert(recordType, mDbAttributes.get(), mData.get());
120  		secinfo("usertrust", "%p inserted now", this);
121  	}
122  
123  	mPrimaryKey = keychain->makePrimaryKey(recordType, mUniqueId);
124      mKeychain = keychain;
125  	return mPrimaryKey;
126  }
127  
128  
129  void UserTrustItem::populateAttributes()
130  {
131  	StLock<Mutex>_(mMutex);
132  	CssmAutoData encodedIndex(Allocator::standard());
133  	makeCertIndex(mCertificate, encodedIndex);
134  	const CssmOid &policyOid = mPolicy->oid();
135  
136  	mDbAttributes->add(Schema::attributeInfo(kSecTrustCertAttr), encodedIndex.get());
137  	mDbAttributes->add(Schema::attributeInfo(kSecTrustPolicyAttr), policyOid);
138  }
139  
140  
141  //
142  // An ad-hoc hold-and-destroy accessor for a single-valued certificate field
143  //
144  class CertField {
145  public:
146  	CertField(Certificate *cert, const CSSM_OID &inField)
147  		: certificate(cert), field(inField)
148  	{ mData = certificate->copyFirstFieldValue(field); }
149  		
150  	~CertField() { certificate->releaseFieldValue(field, mData); }
151  	
152  	Certificate * const certificate;
153  	const CSSM_OID &field;
154  	
155  	operator bool () const { return mData && mData->Data; }
156  	CssmData &data() const { return CssmData::overlay(*mData); }
157  
158  private:
159  	CSSM_DATA_PTR mData;
160  };
161  
162  
163  //
164  // Construct a trust item index.
165  // This is an ASN.1 sequence of issuer and serial number.
166  //
167  struct IssuerAndSN {
168      CSSM_DATA issuer;
169      CSSM_DATA serial;
170  };
171  
172  static const SecAsn1Template issuerAndSNTemplate[] = {
173  	{ SEC_ASN1_SEQUENCE, 0, NULL, sizeof(IssuerAndSN) },
174  	{ SEC_ASN1_OCTET_STRING, offsetof(IssuerAndSN, issuer) },
175  	{ SEC_ASN1_OCTET_STRING, offsetof(IssuerAndSN, serial) },
176  	{ 0 }
177  };
178  
179  void UserTrustItem::makeCertIndex(Certificate *cert, CssmOwnedData &encodedIndex)
180  {
181  	CertField issuer(cert, CSSMOID_X509V1IssuerName);
182  	CertField serial(cert, CSSMOID_X509V1SerialNumber);
183  	IssuerAndSN index;
184  	index.issuer = issuer.data();
185  	index.serial = serial.data();
186  	if (SecNssEncodeItemOdata(&index, issuerAndSNTemplate, encodedIndex))
187  		CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
188  }
189  
190  
191  } // end namespace KeychainCore
192  } // end namespace Security