-/*
- * 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();
-}