]> git.saurik.com Git - apple/security.git/blobdiff - Security/libsecurity_keychain/lib/Policies.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / Security / libsecurity_keychain / lib / Policies.cpp
diff --git a/Security/libsecurity_keychain/lib/Policies.cpp b/Security/libsecurity_keychain/lib/Policies.cpp
new file mode 100644 (file)
index 0000000..769a78b
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2002-2004,2011-2014 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@
+ */
+
+//
+// Policy.cpp - Working with Policies
+//
+#include <security_keychain/Policies.h>
+#include <security_utilities/debugging.h>
+#include <Security/oidsalg.h>
+#include <sys/param.h>
+
+/* Oids longer than this are considered invalid. */
+#define MAX_OID_SIZE                           32
+
+//%%FIXME: need to use a common copy of this utility function
+static
+CFStringRef SecDERItemCopyOIDDecimalRepresentation(uint8 *oid, size_t oidLen)
+{
+       if (oidLen == 0)
+               return CFSTR("<NULL>");
+
+       if (oidLen > MAX_OID_SIZE)
+               return CFSTR("Oid too long");
+
+       CFMutableStringRef result = CFStringCreateMutable(kCFAllocatorDefault, 0);
+
+       // The first two levels are encoded into one byte, since the root level
+       // has only 3 nodes (40*x + y).  However if x = joint-iso-itu-t(2) then
+       // y may be > 39, so we have to add special-case handling for this.
+       uint32_t x = oid[0] / 40;
+       uint32_t y = oid[0] % 40;
+       if (x > 2)
+       {
+               // Handle special case for large y if x = 2
+               y += (x - 2) * 40;
+               x = 2;
+       }
+       CFStringAppendFormat(result, NULL, CFSTR("%u.%u"), x, y);
+
+       unsigned long value = 0;
+       for (x = 1; x < oidLen; ++x)
+       {
+               value = (value << 7) | (oid[x] & 0x7F);
+               /* @@@ value may not span more than 4 bytes. */
+               /* A max number of 20 values is allowed. */
+               if (!(oid[x] & 0x80))
+               {
+                       CFStringAppendFormat(result, NULL, CFSTR(".%lu"), value);
+                       value = 0;
+               }
+       }
+       return result;
+}
+
+
+using namespace KeychainCore;
+
+Policy::Policy(TP supportingTp, const CssmOid &policyOid)
+    : mTp(supportingTp),
+      mOid(Allocator::standard(), policyOid),
+      mValue(Allocator::standard()),
+      mAuxValue(Allocator::standard())
+{
+       // value is as yet unimplemented
+       secdebug("policy", "Policy() this %p", this);
+}
+
+Policy::~Policy() throw()
+{
+       secdebug("policy", "~Policy() this %p", this);
+}
+
+void Policy::setValue(const CssmData &value)
+{
+       StLock<Mutex>_(mMutex);
+       mValue = value;
+       mAuxValue.reset();
+
+       // Certain policy values may contain an embedded pointer. Ask me how I feel about that.
+       if (mOid == CSSMOID_APPLE_TP_SSL ||
+               mOid == CSSMOID_APPLE_TP_EAP ||
+               mOid == CSSMOID_APPLE_TP_IP_SEC ||
+               mOid == CSSMOID_APPLE_TP_APPLEID_SHARING)
+       {
+               CSSM_APPLE_TP_SSL_OPTIONS *opts = (CSSM_APPLE_TP_SSL_OPTIONS *)value.data();
+               if (opts->Version == CSSM_APPLE_TP_SSL_OPTS_VERSION)
+               {
+                       if (opts->ServerNameLen > 0)
+                       {
+                               // Copy auxiliary data, then update the embedded pointer to reference our copy
+                               mAuxValue.copy(const_cast<char*>(opts->ServerName), opts->ServerNameLen);
+                               mValue.get().interpretedAs<CSSM_APPLE_TP_SSL_OPTIONS>()->ServerName =
+                                       reinterpret_cast<char*>(mAuxValue.data());
+                       }
+                       else
+                       {
+                               // Clear the embedded pointer!
+                               mValue.get().interpretedAs<CSSM_APPLE_TP_SSL_OPTIONS>()->ServerName =
+                                       reinterpret_cast<char*>(NULL);
+                       }
+               }
+       }
+       else if (mOid == CSSMOID_APPLE_TP_SMIME ||
+                       mOid == CSSMOID_APPLE_TP_ICHAT ||
+                       mOid == CSSMOID_APPLE_TP_PASSBOOK_SIGNING)
+       {
+               CSSM_APPLE_TP_SMIME_OPTIONS *opts = (CSSM_APPLE_TP_SMIME_OPTIONS *)value.data();
+               if (opts->Version == CSSM_APPLE_TP_SMIME_OPTS_VERSION)
+               {
+                       if (opts->SenderEmailLen > 0)
+                       {
+                               // Copy auxiliary data, then update the embedded pointer to reference our copy
+                               mAuxValue.copy(const_cast<char*>(opts->SenderEmail), opts->SenderEmailLen);
+                               mValue.get().interpretedAs<CSSM_APPLE_TP_SMIME_OPTIONS>()->SenderEmail =
+                                       reinterpret_cast<char*>(mAuxValue.data());
+                       }
+                       else
+                       {
+                               // Clear the embedded pointer!
+                               mValue.get().interpretedAs<CSSM_APPLE_TP_SMIME_OPTIONS>()->SenderEmail =
+                                       reinterpret_cast<char*>(NULL);
+                       }
+               }
+       }
+}
+
+void Policy::setProperties(CFDictionaryRef properties)
+{
+       // Set the policy value based on the provided dictionary keys.
+       if (properties == NULL)
+               return;
+
+       if (mOid == CSSMOID_APPLE_TP_SSL ||
+               mOid == CSSMOID_APPLE_TP_EAP ||
+               mOid == CSSMOID_APPLE_TP_IP_SEC ||
+               mOid == CSSMOID_APPLE_TP_APPLEID_SHARING)
+       {
+               CSSM_APPLE_TP_SSL_OPTIONS options = { CSSM_APPLE_TP_SSL_OPTS_VERSION, 0, NULL, 0 };
+               char *buf = NULL;
+               CFStringRef nameStr = NULL;
+               if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyName, (const void **)&nameStr)) {
+                       buf = (char *)malloc(MAXPATHLEN);
+                       if (buf) {
+                               if (CFStringGetCString(nameStr, buf, MAXPATHLEN, kCFStringEncodingUTF8)) {
+                                       options.ServerName = buf;
+                                       options.ServerNameLen = (unsigned)(strlen(buf)+1); // include terminating null
+                               }
+                       }
+               }
+               CFBooleanRef clientRef = NULL;
+               if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyClient, (const void **)&clientRef)
+                       && CFBooleanGetValue(clientRef) == true)
+                       options.Flags |= CSSM_APPLE_TP_SSL_CLIENT;
+
+               const CssmData value((uint8*)&options, sizeof(options));
+               this->setValue(value);
+
+               if (buf) free(buf);
+       }
+       else if (mOid == CSSMOID_APPLE_TP_SMIME ||
+                       mOid == CSSMOID_APPLE_TP_ICHAT ||
+                       mOid == CSSMOID_APPLE_TP_PASSBOOK_SIGNING)
+       {
+               CSSM_APPLE_TP_SMIME_OPTIONS options = { CSSM_APPLE_TP_SMIME_OPTS_VERSION, 0, 0, NULL };
+               char *buf = NULL;
+               CFStringRef nameStr = NULL;
+               if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyName, (const void **)&nameStr)) {
+                       buf = (char *)malloc(MAXPATHLEN);
+                       if (buf) {
+                               if (CFStringGetCString(nameStr, buf, MAXPATHLEN, kCFStringEncodingUTF8)) {
+                                       CFStringRef teamIDStr = NULL;
+                                       if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyTeamIdentifier, (const void **)&teamIDStr)) {
+                                               char *buf2 = (char *)malloc(MAXPATHLEN);
+                                               if (buf2) {
+                                                       if (CFStringGetCString(teamIDStr, buf2, MAXPATHLEN, kCFStringEncodingUTF8)) {
+                                                               /* append tab separator and team identifier */
+                                                               strlcat(buf, "\t", MAXPATHLEN);
+                                                               strlcat(buf, buf2, MAXPATHLEN);
+                                                       }
+                                                       free(buf2);
+                                               }
+                                       }
+                                       options.SenderEmail = buf;
+                                       options.SenderEmailLen = (unsigned)(strlen(buf)+1); // include terminating null
+                               }
+                       }
+               }
+               CFBooleanRef kuRef = NULL;
+               if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyKU_DigitalSignature, (const void **)&kuRef)
+                       && CFBooleanGetValue(kuRef) == true)
+                       options.IntendedUsage |= CE_KU_DigitalSignature;
+               if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyKU_NonRepudiation, (const void **)&kuRef)
+                       && CFBooleanGetValue(kuRef) == true)
+                       options.IntendedUsage |= CE_KU_NonRepudiation;
+               if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyKU_KeyEncipherment, (const void **)&kuRef)
+                       && CFBooleanGetValue(kuRef) == true)
+                       options.IntendedUsage |= CE_KU_KeyEncipherment;
+               if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyKU_DataEncipherment, (const void **)&kuRef)
+                       && CFBooleanGetValue(kuRef) == true)
+                       options.IntendedUsage |= CE_KU_DataEncipherment;
+               if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyKU_KeyAgreement, (const void **)&kuRef)
+                       && CFBooleanGetValue(kuRef) == true)
+                       options.IntendedUsage |= CE_KU_KeyAgreement;
+               if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyKU_KeyCertSign, (const void **)&kuRef)
+                       && CFBooleanGetValue(kuRef) == true)
+                       options.IntendedUsage |= CE_KU_KeyCertSign;
+               if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyKU_CRLSign, (const void **)&kuRef)
+                       && CFBooleanGetValue(kuRef) == true)
+                       options.IntendedUsage |= CE_KU_CRLSign;
+               if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyKU_EncipherOnly, (const void **)&kuRef)
+                       && CFBooleanGetValue(kuRef) == true)
+                       options.IntendedUsage |= CE_KU_EncipherOnly;
+               if (CFDictionaryGetValueIfPresent(properties, (const void *)kSecPolicyKU_DecipherOnly, (const void **)&kuRef)
+                       && CFBooleanGetValue(kuRef) == true)
+                       options.IntendedUsage |= CE_KU_DecipherOnly;
+
+               const CssmData value((uint8*)&options, sizeof(options));
+               this->setValue(value);
+
+               if (buf) free(buf);
+    }
+
+}
+
+CFDictionaryRef Policy::properties()
+{
+       // Builds and returns a dictionary which the caller must release.
+       CFMutableDictionaryRef properties = CFDictionaryCreateMutable(NULL, 0,
+               &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+       if (!properties) return NULL;
+
+       // kSecPolicyOid
+       CFStringRef oidStr = SecDERItemCopyOIDDecimalRepresentation((uint8*)mOid.data(), mOid.length());
+       if (oidStr) {
+               CFDictionarySetValue(properties, (const void *)kSecPolicyOid, (const void *)oidStr);
+               CFRelease(oidStr);
+       }
+
+       // kSecPolicyName
+       if (mAuxValue) {
+               CFStringRef nameStr = CFStringCreateWithBytes(NULL,
+                       (const UInt8 *)reinterpret_cast<char*>(mAuxValue.data()),
+                       (CFIndex)mAuxValue.length(), kCFStringEncodingUTF8, false);
+               if (nameStr) {
+                       if (mOid == CSSMOID_APPLE_TP_PASSBOOK_SIGNING) {
+                               CFArrayRef strs = CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault, nameStr, CFSTR("\t"));
+                               if (strs) {
+                                       CFIndex count = CFArrayGetCount(strs);
+                                       if (count > 0)
+                                               CFDictionarySetValue(properties, (const void *)kSecPolicyName, (const void *)CFArrayGetValueAtIndex(strs, 0));
+                                       if (count > 1)
+                                               CFDictionarySetValue(properties, (const void *)kSecPolicyTeamIdentifier, (const void *)CFArrayGetValueAtIndex(strs, 1));
+                                       CFRelease(strs);
+                               }
+                       }
+                       else {
+                               CFDictionarySetValue(properties, (const void *)kSecPolicyName, (const void *)nameStr);
+                       }
+                       CFRelease(nameStr);
+               }
+       }
+
+       // kSecPolicyClient
+       if (mValue) {
+               if (mOid == CSSMOID_APPLE_TP_SSL ||
+                       mOid == CSSMOID_APPLE_TP_EAP ||
+                       mOid == CSSMOID_APPLE_TP_IP_SEC ||
+                       mOid == CSSMOID_APPLE_TP_APPLEID_SHARING)
+               {
+                       CSSM_APPLE_TP_SSL_OPTIONS *opts = (CSSM_APPLE_TP_SSL_OPTIONS *)mValue.data();
+                       if (opts->Flags & CSSM_APPLE_TP_SSL_CLIENT) {
+                               CFDictionarySetValue(properties, (const void *)kSecPolicyClient, (const void *)kCFBooleanTrue);
+                       }
+               }
+       }
+
+       // key usage flags (currently only for S/MIME and iChat policies)
+       if (mValue) {
+               if (mOid == CSSMOID_APPLE_TP_SMIME ||
+                       mOid == CSSMOID_APPLE_TP_ICHAT)
+               {
+                       CSSM_APPLE_TP_SMIME_OPTIONS *opts = (CSSM_APPLE_TP_SMIME_OPTIONS *)mValue.data();
+                       CE_KeyUsage usage = opts->IntendedUsage;
+                       if (usage & CE_KU_DigitalSignature)
+                               CFDictionarySetValue(properties, (const void *)kSecPolicyKU_DigitalSignature, (const void *)kCFBooleanTrue);
+                       if (usage & CE_KU_NonRepudiation)
+                               CFDictionarySetValue(properties, (const void *)kSecPolicyKU_NonRepudiation, (const void *)kCFBooleanTrue);
+                       if (usage & CE_KU_KeyEncipherment)
+                               CFDictionarySetValue(properties, (const void *)kSecPolicyKU_KeyEncipherment, (const void *)kCFBooleanTrue);
+                       if (usage & CE_KU_DataEncipherment)
+                               CFDictionarySetValue(properties, (const void *)kSecPolicyKU_DataEncipherment, (const void *)kCFBooleanTrue);
+                       if (usage & CE_KU_KeyAgreement)
+                               CFDictionarySetValue(properties, (const void *)kSecPolicyKU_KeyAgreement, (const void *)kCFBooleanTrue);
+                       if (usage & CE_KU_KeyCertSign)
+                               CFDictionarySetValue(properties, (const void *)kSecPolicyKU_KeyCertSign, (const void *)kCFBooleanTrue);
+                       if (usage & CE_KU_CRLSign)
+                               CFDictionarySetValue(properties, (const void *)kSecPolicyKU_CRLSign, (const void *)kCFBooleanTrue);
+                       if (usage & CE_KU_EncipherOnly)
+                               CFDictionarySetValue(properties, (const void *)kSecPolicyKU_EncipherOnly, (const void *)kCFBooleanTrue);
+                       if (usage & CE_KU_DecipherOnly)
+                               CFDictionarySetValue(properties, (const void *)kSecPolicyKU_DecipherOnly, (const void *)kCFBooleanTrue);
+               }
+       }
+       return properties;
+}
+
+
+bool Policy::operator < (const Policy& other) const
+{
+    //@@@ inefficient
+    return (oid() < other.oid()) ||
+        (oid() == other.oid() && value() < other.value());
+}
+
+bool Policy::operator == (const Policy& other) const
+{
+    return oid() == other.oid() && value() == other.value();
+}