(ssl) wip code to handle certs on apple
This commit is contained in:
		@@ -130,6 +130,104 @@ namespace
 | 
				
			|||||||
        return errMsg;
 | 
					        return errMsg;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#undef CURL_BUILD_IOS
 | 
				
			||||||
 | 
					    OSStatus CopyIdentityFromPKCS12File(
 | 
				
			||||||
 | 
					        const char *cPath,
 | 
				
			||||||
 | 
					        const char *cPassword,
 | 
				
			||||||
 | 
					        SecIdentityRef *out_cert_and_key)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        OSStatus status = errSecItemNotFound;
 | 
				
			||||||
 | 
					        CFURLRef pkcs_url = CFURLCreateFromFileSystemRepresentation(
 | 
				
			||||||
 | 
					            NULL, (const UInt8 *)cPath, strlen(cPath), false);
 | 
				
			||||||
 | 
					        CFStringRef password = cPassword ? CFStringCreateWithCString(NULL,
 | 
				
			||||||
 | 
					            cPassword, kCFStringEncodingUTF8) : NULL;
 | 
				
			||||||
 | 
					        CFDataRef pkcs_data = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* We can import P12 files on iOS or OS X 10.7 or later: */
 | 
				
			||||||
 | 
					        /* These constants are documented as having first appeared in 10.6 but they
 | 
				
			||||||
 | 
					           raise linker errors when used on that cat for some reason. */
 | 
				
			||||||
 | 
					        if (CFURLCreateDataAndPropertiesFromResource(
 | 
				
			||||||
 | 
					            NULL, pkcs_url, &pkcs_data, NULL, NULL, &status)) {
 | 
				
			||||||
 | 
					            CFArrayRef items = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* On iOS SecPKCS12Import will never add the client certificate to the
 | 
				
			||||||
 | 
					             * Keychain.
 | 
				
			||||||
 | 
					             *
 | 
				
			||||||
 | 
					             * It gives us back a SecIdentityRef that we can use directly. */
 | 
				
			||||||
 | 
					#if CURL_BUILD_IOS
 | 
				
			||||||
 | 
					            const void *cKeys[] = {kSecImportExportPassphrase};
 | 
				
			||||||
 | 
					            const void *cValues[] = {password};
 | 
				
			||||||
 | 
					            CFDictionaryRef options = CFDictionaryCreate(NULL, cKeys, cValues,
 | 
				
			||||||
 | 
					                    password ? 1L : 0L, NULL, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (options != NULL) {
 | 
				
			||||||
 | 
					                status = SecPKCS12Import(pkcs_data, options, &items);
 | 
				
			||||||
 | 
					                CFRelease(options);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* On macOS SecPKCS12Import will always add the client certificate to
 | 
				
			||||||
 | 
					             * the Keychain.
 | 
				
			||||||
 | 
					             *
 | 
				
			||||||
 | 
					             * As this doesn't match iOS, and apps may not want to see their client
 | 
				
			||||||
 | 
					             * certificate saved in the the user's keychain, we use SecItemImport
 | 
				
			||||||
 | 
					             * with a NULL keychain to avoid importing it.
 | 
				
			||||||
 | 
					             *
 | 
				
			||||||
 | 
					             * This returns a SecCertificateRef from which we can construct a
 | 
				
			||||||
 | 
					             * SecIdentityRef.
 | 
				
			||||||
 | 
					             */
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					            SecItemImportExportKeyParameters keyParams;
 | 
				
			||||||
 | 
					            SecExternalFormat inputFormat = kSecFormatPKCS12;
 | 
				
			||||||
 | 
					            SecExternalItemType inputType = kSecItemTypeCertificate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            memset(&keyParams, 0x00, sizeof(keyParams));
 | 
				
			||||||
 | 
					            keyParams.version    = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
 | 
				
			||||||
 | 
					            keyParams.passphrase = password;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            status = SecItemImport(pkcs_data, NULL, &inputFormat, &inputType,
 | 
				
			||||||
 | 
					                                   0, &keyParams, NULL, &items);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* Extract the SecIdentityRef */
 | 
				
			||||||
 | 
					            if (status == errSecSuccess && items && CFArrayGetCount(items))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                CFIndex i, count;
 | 
				
			||||||
 | 
					                count = CFArrayGetCount(items);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                for (i = 0; i < count; i++)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    CFTypeRef item = (CFTypeRef) CFArrayGetValueAtIndex(items, i);
 | 
				
			||||||
 | 
					                    CFTypeID  itemID = CFGetTypeID(item);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (itemID == CFDictionaryGetTypeID())
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        CFTypeRef identity = (CFTypeRef) CFDictionaryGetValue(
 | 
				
			||||||
 | 
					                                (CFDictionaryRef) item,
 | 
				
			||||||
 | 
					                                kSecImportItemIdentity);
 | 
				
			||||||
 | 
					                        CFRetain(identity);
 | 
				
			||||||
 | 
					                        *out_cert_and_key = (SecIdentityRef) identity;
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else if (itemID == SecCertificateGetTypeID())
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        status = SecIdentityCreateWithCertificate(NULL,
 | 
				
			||||||
 | 
					                                (SecCertificateRef) item,
 | 
				
			||||||
 | 
					                                out_cert_and_key);
 | 
				
			||||||
 | 
					                        break;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (items) CFRelease(items);
 | 
				
			||||||
 | 
					            CFRelease(pkcs_data);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (password) CFRelease(password);
 | 
				
			||||||
 | 
					        CFRelease(pkcs_url);
 | 
				
			||||||
 | 
					        return status;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
} // anonymous namespace
 | 
					} // anonymous namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ix
 | 
					namespace ix
 | 
				
			||||||
@@ -153,6 +251,63 @@ namespace ix
 | 
				
			|||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool SocketAppleSSL::handleTLSOptions(std::string& errMsg)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        SecIdentityRef cert_and_key = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const char* ssl_cert = _tlsOptions.certFile.c_str();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        OSStatus err = CopyIdentityFromPKCS12File(ssl_cert, "foobar", &cert_and_key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (err == noErr && cert_and_key)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            SecCertificateRef cert = NULL;
 | 
				
			||||||
 | 
					            CFTypeRef certs_c[1];
 | 
				
			||||||
 | 
					            CFArrayRef certs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            err = SecIdentityCopyCertificate(cert_and_key, &cert);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            certs_c[0] = cert_and_key;
 | 
				
			||||||
 | 
					            certs = CFArrayCreate(NULL, (const void **)certs_c, 1L,
 | 
				
			||||||
 | 
					                    &kCFTypeArrayCallBacks);
 | 
				
			||||||
 | 
					            err = SSLSetCertificate(_sslContext, certs);
 | 
				
			||||||
 | 
					            if (err != noErr)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                errMsg = "SSLSetCertificate failed";
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            switch(err) {
 | 
				
			||||||
 | 
					                case errSecAuthFailed: case -25264: /* errSecPkcs12VerifyFailure */
 | 
				
			||||||
 | 
					                    errMsg = "SSL: Incorrect password for the certificate \"%s\" "
 | 
				
			||||||
 | 
					                            "and its private key."; // , ssl_cert);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case -26275: /* errSecDecode */ case -25257: /* errSecUnknownFormat */
 | 
				
			||||||
 | 
					                    errMsg = "SSL: Couldn't make sense of the data in the "
 | 
				
			||||||
 | 
					                            "certificate \"%s\" and its private key.";
 | 
				
			||||||
 | 
					                            ; // ssl_cert);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case -25260: /* errSecPassphraseRequired */
 | 
				
			||||||
 | 
					                    errMsg = "SSL The certificate \"%s\" requires a password.";
 | 
				
			||||||
 | 
					                            // ssl_cert);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                case errSecItemNotFound:
 | 
				
			||||||
 | 
					                    errMsg = "SSL: Can't find the certificate \"%s\" and its private "
 | 
				
			||||||
 | 
					                            "key in the Keychain."; // , ssl_cert);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					                default:
 | 
				
			||||||
 | 
					                    errMsg = "SSL: Can't load the certificate \"%s\" and its private "
 | 
				
			||||||
 | 
					                            "key: OSStatus %d" ; // , ssl_cert, err);
 | 
				
			||||||
 | 
					                    break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // No wait support
 | 
					    // No wait support
 | 
				
			||||||
    bool SocketAppleSSL::connect(const std::string& host,
 | 
					    bool SocketAppleSSL::connect(const std::string& host,
 | 
				
			||||||
                                 int port,
 | 
					                                 int port,
 | 
				
			||||||
@@ -173,6 +328,8 @@ namespace ix
 | 
				
			|||||||
            SSLSetProtocolVersionMin(_sslContext, kTLSProtocol12);
 | 
					            SSLSetProtocolVersionMin(_sslContext, kTLSProtocol12);
 | 
				
			||||||
            SSLSetPeerDomainName(_sslContext, host.c_str(), host.size());
 | 
					            SSLSetPeerDomainName(_sslContext, host.c_str(), host.size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!handleTLSOptions(errMsg)) return false; // FIXME not calling close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (_tlsOptions.isPeerVerifyDisabled())
 | 
					            if (_tlsOptions.isPeerVerifyDisabled())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Boolean option(1);
 | 
					                Boolean option(1);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,6 +34,8 @@ namespace ix
 | 
				
			|||||||
        virtual ssize_t recv(void* buffer, size_t length) final;
 | 
					        virtual ssize_t recv(void* buffer, size_t length) final;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private:
 | 
					    private:
 | 
				
			||||||
 | 
					        bool handleTLSOptions(std::string& errMsg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SSLContextRef _sslContext;
 | 
					        SSLContextRef _sslContext;
 | 
				
			||||||
        mutable std::mutex _mutex; // AppleSSL routines are not thread-safe
 | 
					        mutable std::mutex _mutex; // AppleSSL routines are not thread-safe
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user