// // Copyright (c) ZeroC, Inc. All rights reserved. // #include #include #include #include #include #include #include #include #include #include using namespace Ice; using namespace IceInternal; using namespace IceSSL; using namespace IceSSL::SecureTransport; using namespace std; namespace { CFMutableDataRef readCertFile(const string& file) { ifstream is(IceUtilInternal::streamFilename(file).c_str(), ios::in | ios::binary); if(!is.good()) { throw CertificateReadException(__FILE__, __LINE__, "error opening file " + file); } is.seekg(0, is.end); size_t size = static_cast(is.tellg()); is.seekg(0, is.beg); UniqueRef data(CFDataCreateMutable(kCFAllocatorDefault, static_cast(size))); CFDataSetLength(data.get(), static_cast(size)); is.read(reinterpret_cast(CFDataGetMutableBytePtr(data.get())), static_cast(size)); if(!is.good()) { throw CertificateReadException(__FILE__, __LINE__, "error reading file " + file); } return data.release(); } } string IceSSL::SecureTransport::sslErrorToString(CFErrorRef err) { ostringstream os; if(err) { UniqueRef s(CFErrorCopyDescription(err)); os << "(error: " << CFErrorGetCode(err) << " description: " << fromCFString(s.get()) << ")"; } return os.str(); } string IceSSL::SecureTransport::sslErrorToString(OSStatus status) { ostringstream os; os << "(error: " << status; #if defined(ICE_USE_SECURE_TRANSPORT_MACOS) UniqueRef s(SecCopyErrorMessageString(status, 0)); if(s) { os << " description: " << fromCFString(s.get()); } #endif os << ")"; return os.str(); } #if defined(ICE_USE_SECURE_TRANSPORT_MACOS) CFDictionaryRef IceSSL::SecureTransport::getCertificateProperty(SecCertificateRef cert, CFTypeRef key) { UniqueRef property; UniqueRef keys(CFArrayCreate(ICE_NULLPTR, &key , 1, &kCFTypeArrayCallBacks)); UniqueRef err; UniqueRef values(SecCertificateCopyValues(cert, keys.get(), &err.get())); if(err) { ostringstream os; os << "IceSSL: error getting property for certificate:\n" << sslErrorToString(err); throw CertificateReadException(__FILE__, __LINE__, os.str()); } assert(values); property.retain(static_cast(CFDictionaryGetValue(values.get(), key))); return property.release(); } namespace { // // Check the certificate basic constraints to check if the certificate is marked as a CA. // bool isCA(SecCertificateRef cert) { UniqueRef property(getCertificateProperty(cert, kSecOIDBasicConstraints)); if(property) { CFArrayRef propertyValues = static_cast(CFDictionaryGetValue(property.get(), kSecPropertyKeyValue)); for(CFIndex i = 0, size = CFArrayGetCount(propertyValues); i < size; ++i) { CFDictionaryRef dict = static_cast(CFArrayGetValueAtIndex(propertyValues, i)); CFStringRef label = static_cast(CFDictionaryGetValue(dict, kSecPropertyKeyLabel)); if(CFEqual(label, CFSTR("Certificate Authority"))) { return CFEqual(static_cast(CFDictionaryGetValue(dict, kSecPropertyKeyValue)), CFSTR("Yes")); } } } return false; } // // Load keychain items (Certificates or Private Keys) from a file. On return items param contain // the list of items, the caller must release it. // CFArrayRef loadKeychainItems(const string& file, SecExternalItemType type, SecKeychainRef keychain, const string& passphrase, const PasswordPromptPtr& prompt, int retryMax) { UniqueRef data(readCertFile(file)); SecItemImportExportKeyParameters params; memset(¶ms, 0, sizeof(params)); params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; params.flags |= kSecKeyNoAccessControl; UniqueRef passphraseHolder; if(!passphrase.empty()) { passphraseHolder.reset(toCFString(passphrase)); params.passphrase = passphraseHolder.get(); } UniqueRef items; SecExternalItemType importType = type; SecExternalFormat format = type == kSecItemTypeUnknown ? kSecFormatPKCS12 : kSecFormatUnknown; UniqueRef path(toCFString(file)); OSStatus err = SecItemImport(data.get(), path.get(), &format, &importType, 0, ¶ms, keychain, &items.get()); // // If passphrase failure and no password was configured, we obtain // the password from the given prompt or configure the import to // prompt the user with an alert dialog. // UniqueRef alertPromptHolder; if(passphrase.empty() && (err == errSecPassphraseRequired || err == errSecInvalidData || err == errSecPkcs12VerifyFailure)) { if(!prompt) { params.flags |= kSecKeySecurePassphrase; ostringstream os; os << "Enter the password for\n" << file; alertPromptHolder.reset(toCFString(os.str())); params.alertPrompt = alertPromptHolder.get(); } int count = 0; while((err == errSecPassphraseRequired || err == errSecInvalidData || err == errSecPkcs12VerifyFailure) && count < retryMax) { if(prompt) { passphraseHolder.reset(toCFString(prompt->getPassword())); params.passphrase = passphraseHolder.get(); } err = SecItemImport(data.get(), path.get(), &format, &importType, 0, ¶ms, keychain, &items.get()); ++count; } } if(err != noErr) { ostringstream os; os << "IceSSL: error reading " << (type == kSecItemTypePrivateKey ? "private key" : "certificate"); os << " `" << file << "':\n" << sslErrorToString(err); throw CertificateReadException(__FILE__, __LINE__, os.str()); } if(type != kSecItemTypeUnknown && importType != kSecItemTypeAggregate && importType != type) { ostringstream os; os << "IceSSL: error reading " << (type == kSecItemTypePrivateKey ? "private key" : "certificate"); os << " `" << file << "' doesn't contain the expected item"; throw CertificateReadException(__FILE__, __LINE__, os.str()); } return items.release(); } SecKeychainRef openKeychain(const std::string& path, const std::string& keychainPassword) { string keychainPath = path; UniqueRef keychain; OSStatus err = 0; if(keychainPath.empty()) { if((err = SecKeychainCopyDefault(&keychain.get()))) { throw PluginInitializationException(__FILE__, __LINE__, "IceSSL: unable to retrieve default keychain:\n" + sslErrorToString(err)); } } else { // // KeyChain path is relative to the current working directory. // if(!IceUtilInternal::isAbsolutePath(keychainPath)) { string cwd; if(IceUtilInternal::getcwd(cwd) == 0) { keychainPath = string(cwd) + '/' + keychainPath; } } if((err = SecKeychainOpen(keychainPath.c_str(), &keychain.get()))) { throw PluginInitializationException(__FILE__, __LINE__, "IceSSL: unable to open keychain: `" + keychainPath + "'\n" + sslErrorToString(err)); } } SecKeychainStatus status; err = SecKeychainGetStatus(keychain.get(), &status); if(err == noErr) { const char* pass = keychainPassword.empty() ? 0 : keychainPassword.c_str(); if((err = SecKeychainUnlock(keychain.get(), static_cast(keychainPassword.size()), pass, pass != 0))) { throw PluginInitializationException(__FILE__, __LINE__, "IceSSL: unable to unlock keychain:\n" + sslErrorToString(err)); } } else if(err == errSecNoSuchKeychain) { const char* pass = keychainPassword.empty() ? 0 : keychainPassword.c_str(); keychain.reset(0); if((err = SecKeychainCreate(keychainPath.c_str(), static_cast(keychainPassword.size()), pass, pass == 0, 0, &keychain.get()))) { throw PluginInitializationException(__FILE__, __LINE__, "IceSSL: unable to create keychain:\n" + sslErrorToString(err)); } } else { throw PluginInitializationException(__FILE__, __LINE__, "IceSSL: unable to open keychain:\n" + sslErrorToString(err)); } // // Set keychain settings to avoid keychain lock. // SecKeychainSettings settings; settings.version = SEC_KEYCHAIN_SETTINGS_VERS1; settings.lockOnSleep = FALSE; settings.useLockInterval = FALSE; settings.lockInterval = INT_MAX; if((err = SecKeychainSetSettings(keychain.get(), &settings))) { throw PluginInitializationException(__FILE__, __LINE__, "IceSSL: error setting keychain settings:\n" + sslErrorToString(err)); } return keychain.release(); } // // Imports a certificate private key and optionally add it to a keychain. // SecIdentityRef loadPrivateKey(const string& file, SecCertificateRef cert, SecKeychainRef keychain, const string& password, const PasswordPromptPtr& prompt, int retryMax) { // // Check if we already imported the certificate // UniqueRef hash; UniqueRef subjectKeyProperty(getCertificateProperty(cert, kSecOIDSubjectKeyIdentifier)); if(subjectKeyProperty) { CFArrayRef values = static_cast(CFDictionaryGetValue(subjectKeyProperty.get(), kSecPropertyKeyValue)); for(int i = 0; i < CFArrayGetCount(values); ++i) { CFDictionaryRef dict = static_cast(CFArrayGetValueAtIndex(values, i)); if(CFEqual(CFDictionaryGetValue(dict, kSecPropertyKeyLabel), CFSTR("Key Identifier"))) { hash.retain(static_cast(CFDictionaryGetValue(dict, kSecPropertyKeyValue))); break; } } } const void* values[] = { keychain }; UniqueRef searchList(CFArrayCreate(kCFAllocatorDefault, values, 1, &kCFTypeArrayCallBacks)); UniqueRef query(CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); CFDictionarySetValue(query.get(), kSecClass, kSecClassCertificate); CFDictionarySetValue(query.get(), kSecMatchLimit, kSecMatchLimitOne); CFDictionarySetValue(query.get(), kSecMatchSearchList, searchList.get()); CFDictionarySetValue(query.get(), kSecAttrSubjectKeyID, hash.get()); CFDictionarySetValue(query.get(), kSecReturnRef, kCFBooleanTrue); UniqueRef value(0); OSStatus err = SecItemCopyMatching(query.get(), &value.get()); UniqueRef item(static_cast(const_cast(value.release()))); if(err == noErr) { // // If the certificate has already been imported, create the // identity. The key should also have been imported. // UniqueRef identity; err = SecIdentityCreateWithCertificate(keychain, item.get(), &identity.get()); if(err != noErr) { ostringstream os; os << "IceSSL: error creating certificate identity:\n" << sslErrorToString(err); throw CertificateReadException(__FILE__, __LINE__, os.str()); } return identity.release(); } else if(err != errSecItemNotFound) { ostringstream os; os << "IceSSL: error searching for keychain items:\n" << sslErrorToString(err); throw CertificateReadException(__FILE__, __LINE__, os.str()); } // // If the certificate isn't already in the keychain, load the // private key into the keychain and add the certificate. // UniqueRef items(loadKeychainItems(file, kSecItemTypePrivateKey, keychain, password, prompt, retryMax)); CFIndex count = CFArrayGetCount(items.get()); UniqueRef key; for(CFIndex i = 0; i < count; ++i) { SecKeychainItemRef itemRef = static_cast(const_cast(CFArrayGetValueAtIndex(items.get(), 0))); if(SecKeyGetTypeID() == CFGetTypeID(itemRef)) { key.retain(reinterpret_cast(itemRef)); break; } } if(!key) { throw CertificateReadException(__FILE__, __LINE__, "IceSSL: no key in file `" + file + "'"); } // // Add the certificate to the keychain // query.reset(CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); CFDictionarySetValue(query.get(), kSecUseKeychain, keychain); CFDictionarySetValue(query.get(), kSecClass, kSecClassCertificate); CFDictionarySetValue(query.get(), kSecValueRef, cert); CFDictionarySetValue(query.get(), kSecReturnRef, kCFBooleanTrue); value.reset(0); err = SecItemAdd(query.get(), static_cast(&value.get())); UniqueRef added(static_cast(value.release())); if(err != noErr) { ostringstream os; os << "IceSSL: failure adding certificate to keychain\n" << sslErrorToString(err); throw CertificateReadException(__FILE__, __LINE__, os.str()); } item.retain(static_cast(const_cast(CFArrayGetValueAtIndex(added.get(), 0)))); // // Create the association between the private key and the certificate, // kSecKeyLabel attribute should match the subject key identifier. // vector attributes; if(hash) { SecKeychainAttribute attr; attr.tag = kSecKeyLabel; attr.data = const_cast(CFDataGetBytePtr(hash.get())); attr.length = static_cast(CFDataGetLength(hash.get())); attributes.push_back(attr); } // // kSecKeyPrintName attribute correspond to the keychain display // name. // string label; UniqueRef commonName(0); if(SecCertificateCopyCommonName(item.get(), &commonName.get()) == noErr) { label = fromCFString(commonName.get()); SecKeychainAttribute attr; attr.tag = kSecKeyPrintName; attr.data = const_cast(label.c_str()); attr.length = static_cast(label.size()); attributes.push_back(attr); } SecKeychainAttributeList attrs; attrs.attr = &attributes[0]; attrs.count = static_cast(attributes.size()); SecKeychainItemModifyAttributesAndData(reinterpret_cast(key.get()), &attrs, 0, 0); UniqueRef identity; err = SecIdentityCreateWithCertificate(keychain, item.get(), &identity.get()); if(err != noErr) { ostringstream os; os << "IceSSL: error creating certificate identity:\n" << sslErrorToString(err); throw CertificateReadException(__FILE__, __LINE__, os.str()); } return identity.release(); } } // anonymous namespace end #else namespace { CFArrayRef loadCerts(const string& file) { UniqueRef certs(CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks)); if(file.find(".pem") != string::npos) { vector buffer; readFile(file, buffer); string strbuf(buffer.begin(), buffer.end()); string::size_type size, startpos, endpos = 0; bool first = true; while(true) { startpos = strbuf.find("-----BEGIN CERTIFICATE-----", endpos); if(startpos != string::npos) { startpos += sizeof("-----BEGIN CERTIFICATE-----"); endpos = strbuf.find("-----END CERTIFICATE-----", startpos); if(endpos == string::npos) { throw InitializationException(__FILE__, __LINE__, "IceSSL: certificate " + file + " is not a valid PEM-encoded certificate"); } size = endpos - startpos; } else if(first) { startpos = 0; endpos = string::npos; size = strbuf.size(); } else { break; } vector data(IceInternal::Base64::decode(string(&buffer[startpos], size))); UniqueRef certdata(CFDataCreate(kCFAllocatorDefault, &data[0], static_cast(data.size()))); UniqueRef cert(SecCertificateCreateWithData(0, certdata.get())); if(!cert) { throw InitializationException(__FILE__, __LINE__, "IceSSL: certificate " + file + " is not a valid PEM-encoded certificate"); } CFArrayAppendValue(const_cast(certs.get()), cert.get()); first = false; } } else { UniqueRef data(readCertFile(file)); UniqueRef cert(SecCertificateCreateWithData(0, data.get())); if(!cert) { throw InitializationException(__FILE__, __LINE__, "IceSSL: certificate " + file + " is not a valid DER-encoded certificate"); } CFArrayAppendValue(const_cast(certs.get()), cert.get()); } return certs.release(); } } #endif // // Imports a certificate (it might contain an identity or certificate depending on the format). // CFArrayRef IceSSL::SecureTransport::loadCertificateChain(const string& file, #if defined(ICE_USE_SECURE_TRANSPORT_IOS) const string& /*keyFile*/, const std::string& /*keychainPath*/, const string& /*keychainPassword*/, #else const string& keyFile, const std::string& keychainPath, const string& keychainPassword, #endif const string& password, const PasswordPromptPtr& prompt, int retryMax) { UniqueRef chain; #if defined(ICE_USE_SECURE_TRANSPORT_IOS) UniqueRef cert(readCertFile(file)); UniqueRef settings(CFDictionaryCreateMutable(0, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); UniqueRef items; OSStatus err; int count = 0; do { items.reset(); UniqueRef pass(toCFString(password.empty() && prompt ? prompt->getPassword() : password)); CFDictionarySetValue(settings.get(), kSecImportExportPassphrase, pass.get()); err = SecPKCS12Import(cert.get(), settings.get(), &items.get()); ++count; } while(password.empty() && prompt && err == errSecAuthFailed && count < retryMax); if(err != noErr) { ostringstream os; os << "IceSSL: unable to import certificate from file " << file << " (error = " << err << ")"; throw InitializationException(__FILE__, __LINE__, os.str()); } for(int i = 0; i < CFArrayGetCount(items.get()); ++i) { CFDictionaryRef dict = static_cast(CFArrayGetValueAtIndex(items.get(), i)); SecIdentityRef identity = static_cast( const_cast(CFDictionaryGetValue(dict, kSecImportItemIdentity))); if(identity) { CFArrayRef certs = static_cast(CFDictionaryGetValue(dict, kSecImportItemCertChain)); chain.reset(CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, certs)); CFArraySetValueAtIndex(const_cast(chain.get()), 0, identity); } } if(!chain) { ostringstream os; os << "IceSSL: couldn't find identity in file " << file; throw InitializationException(__FILE__, __LINE__, os.str()); } #else UniqueRef keychain(openKeychain(keychainPath, keychainPassword)); if(keyFile.empty()) { chain.reset(loadKeychainItems(file, kSecItemTypeUnknown, keychain.get(), password, prompt, retryMax)); } else { // // Load the certificate, don't load into the keychain as it // might already have been imported. // UniqueRef items(loadKeychainItems(file, kSecItemTypeCertificate, 0, password, prompt, retryMax)); SecCertificateRef cert = static_cast(const_cast(CFArrayGetValueAtIndex(items.get(), 0))); if(SecCertificateGetTypeID() != CFGetTypeID(cert)) { ostringstream os; os << "IceSSL: couldn't find certificate in `" << file << "'"; throw CertificateReadException(__FILE__, __LINE__, os.str()); } // // Load the private key for the given certificate. This will // add the certificate/key to the keychain if they aren't // already present in the keychain. // UniqueRef identity(loadPrivateKey(keyFile, cert, keychain.get(), password, prompt, retryMax)); chain.reset(CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, items.get())); CFArraySetValueAtIndex(const_cast(chain.get()), 0, identity.get()); } #endif return chain.release(); } SecCertificateRef IceSSL::SecureTransport::loadCertificate(const string& file) { UniqueRef cert; #if defined(ICE_USE_SECURE_TRANSPORT_IOS) UniqueRef certs(loadCerts(file)); assert(CFArrayGetCount(certs.get()) > 0); cert.retain((SecCertificateRef)CFArrayGetValueAtIndex(certs.get(), 0)); #else UniqueRef items(loadKeychainItems(file, kSecItemTypeCertificate, 0, "", 0, 0)); cert.retain((SecCertificateRef)CFArrayGetValueAtIndex(items.get(), 0)); #endif return cert.release(); } CFArrayRef IceSSL::SecureTransport::loadCACertificates(const string& file) { #if defined(ICE_USE_SECURE_TRANSPORT_IOS) return loadCerts(file); #else UniqueRef items(loadKeychainItems(file, kSecItemTypeCertificate, 0, "", 0, 0)); UniqueRef certificateAuthorities(CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks)); CFIndex count = CFArrayGetCount(items.get()); for(CFIndex i = 0; i < count; ++i) { SecCertificateRef cert = static_cast(const_cast(CFArrayGetValueAtIndex(items.get(), i))); assert(SecCertificateGetTypeID() == CFGetTypeID(cert)); if(isCA(cert)) { CFArrayAppendValue(const_cast(certificateAuthorities.get()), cert); } } return certificateAuthorities.release(); #endif } CFArrayRef #if defined(ICE_USE_SECURE_TRANSPORT_IOS) IceSSL::SecureTransport::findCertificateChain(const std::string&, const std::string&, const string& value) #else IceSSL::SecureTransport::findCertificateChain(const std::string& keychainPath, const std::string& keychainPassword, const string& value) #endif { // // Search the keychain using key:value pairs. The following keys are supported: // // Label // Serial // Subject // SubjectKeyId // // A value must be enclosed in single or double quotes if it contains whitespace. // UniqueRef query(CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); #if defined(ICE_USE_SECURE_TRANSPORT_MACOS) UniqueRef keychain(openKeychain(keychainPath, keychainPassword)); const void* values[] = { keychain.get() }; UniqueRef searchList(CFArrayCreate(kCFAllocatorDefault, values, 1, &kCFTypeArrayCallBacks)); CFDictionarySetValue(query.get(), kSecMatchSearchList, searchList.get()); #endif CFDictionarySetValue(query.get(), kSecMatchLimit, kSecMatchLimitOne); CFDictionarySetValue(query.get(), kSecClass, kSecClassCertificate); CFDictionarySetValue(query.get(), kSecReturnRef, kCFBooleanTrue); CFDictionarySetValue(query.get(), kSecMatchCaseInsensitive, kCFBooleanTrue); size_t start = 0; size_t pos; bool valid = false; while((pos = value.find(':', start)) != string::npos) { string field = IceUtilInternal::toUpper(IceUtilInternal::trim(value.substr(start, pos - start))); string arg; if(field != "LABEL" && field != "SERIAL" && field != "SUBJECT" && field != "SUBJECTKEYID") { throw PluginInitializationException(__FILE__, __LINE__, "IceSSL: unknown key in `" + value + "'"); } start = pos + 1; while(start < value.size() && (value[start] == ' ' || value[start] == '\t')) { ++start; } if(start == value.size()) { throw PluginInitializationException(__FILE__, __LINE__, "IceSSL: missing argument in `" + value + "'"); } if(value[start] == '"' || value[start] == '\'') { size_t end = start; ++end; while(end < value.size()) { if(value[end] == value[start] && value[end - 1] != '\\') { break; } ++end; } if(end == value.size() || value[end] != value[start]) { throw PluginInitializationException(__FILE__, __LINE__, "IceSSL: unmatched quote in `" + value + "'"); } ++start; arg = value.substr(start, end - start); start = end + 1; } else { size_t end = value.find_first_of(" \t", start); if(end == string::npos) { arg = value.substr(start); start = value.size(); } else { arg = value.substr(start, end - start); start = end + 1; } } if(field == "SUBJECT" || field == "LABEL") { UniqueRef v(toCFString(arg)); CFDictionarySetValue(query.get(), field == "LABEL" ? kSecAttrLabel : kSecMatchSubjectContains, v.get()); valid = true; } else if(field == "SUBJECTKEYID" || field == "SERIAL") { vector buffer; if(!parseBytes(arg, buffer)) { throw PluginInitializationException(__FILE__, __LINE__, "IceSSL: invalid value `" + value + "'"); } UniqueRef v(CFDataCreate(kCFAllocatorDefault, &buffer[0], static_cast(buffer.size()))); CFDictionarySetValue(query.get(), field == "SUBJECTKEYID" ? kSecAttrSubjectKeyID : kSecAttrSerialNumber, v.get()); valid = true; } } if(!valid) { throw PluginInitializationException(__FILE__, __LINE__, "IceSSL: invalid value `" + value + "'"); } UniqueRef cert; OSStatus err = SecItemCopyMatching(query.get(), (CFTypeRef*)&cert.get()); if(err != noErr) { throw PluginInitializationException(__FILE__, __LINE__, "IceSSL: find certificate `" + value + "' failed:\n" + sslErrorToString(err)); } // // Retrieve the certificate chain // UniqueRef policy(SecPolicyCreateSSL(true, 0)); UniqueRef trust; err = SecTrustCreateWithCertificates(reinterpret_cast(cert.get()), policy.get(), &trust.get()); if(err || !trust) { throw PluginInitializationException(__FILE__, __LINE__, "IceSSL: error creating trust object" + (err ? ":\n" + sslErrorToString(err) : "")); } SecTrustResultType trustResult; if((err = SecTrustEvaluate(trust.get(), &trustResult))) { throw PluginInitializationException(__FILE__, __LINE__, "IceSSL: error evaluating trust:\n" + sslErrorToString(err)); } CFIndex chainLength = SecTrustGetCertificateCount(trust.get()); UniqueRef items(CFArrayCreateMutable(kCFAllocatorDefault, chainLength, &kCFTypeArrayCallBacks)); for(int i = 0; i < chainLength; ++i) { CFArrayAppendValue(const_cast(items.get()), SecTrustGetCertificateAtIndex(trust.get(), i)); } // // Replace the first certificate in the chain with the // identity. // UniqueRef identity; #if defined(ICE_USE_SECURE_TRANSPORT_IOS) // // SecIdentityCreateWithCertificate isn't supported on iOS so we lookup the identity // using the certicate label. If the user added the identity with SecItemAdd the // identity has the same label as the certificate. // query.reset(CFDictionaryCreateMutable(0, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); CFDictionarySetValue(query.get(), kSecClass, kSecClassCertificate); CFDictionarySetValue(query.get(), kSecValueRef, cert.get()); CFDictionarySetValue(query.get(), kSecReturnAttributes, kCFBooleanTrue); UniqueRef attributes; err = SecItemCopyMatching(query.get(), reinterpret_cast(&attributes.get())); if(err != noErr) { ostringstream os; os << "IceSSL: couldn't create identity for certificate found in the keychain:\n" << sslErrorToString(err); throw PluginInitializationException(__FILE__, __LINE__, os.str()); } // Now lookup the identity with the label query.reset(CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); CFDictionarySetValue(query.get(), kSecMatchLimit, kSecMatchLimitOne); CFDictionarySetValue(query.get(), kSecClass, kSecClassIdentity); CFDictionarySetValue(query.get(), kSecAttrLabel, (CFDataRef)CFDictionaryGetValue(attributes.get(), kSecAttrLabel)); CFDictionarySetValue(query.get(), kSecReturnRef, kCFBooleanTrue); err = SecItemCopyMatching(query.get(), (CFTypeRef*)&identity.get()); if(err == noErr) { UniqueRef cert2; if((err = SecIdentityCopyCertificate(identity.get(), &cert2.get())) == noErr) { err = CFEqual(cert2.get(), cert.get()) ? noErr : errSecItemNotFound; } } #else err = SecIdentityCreateWithCertificate(keychain.get(), cert.get(), &identity.get()); #endif if(err != noErr) { ostringstream os; os << "IceSSL: couldn't create identity for certificate found in the keychain:\n" << sslErrorToString(err); throw PluginInitializationException(__FILE__, __LINE__, os.str()); } CFArraySetValueAtIndex(const_cast(items.get()), 0, identity.get()); return items.release(); }