| /* |
| * Mac OS X Secure Transport implementation of the schannel (SSL/TLS) provider. |
| * |
| * Copyright 2005 Juan Lang |
| * Copyright 2008 Henri Verbeet |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include "config.h" |
| #include "wine/port.h" |
| |
| #include <stdarg.h> |
| #ifdef HAVE_SECURITY_SECURITY_H |
| #include <Security/Security.h> |
| #define GetCurrentThread GetCurrentThread_Mac |
| #define LoadResource LoadResource_Mac |
| #include <CoreServices/CoreServices.h> |
| #undef GetCurrentThread |
| #undef LoadResource |
| #undef DPRINTF |
| #endif |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "sspi.h" |
| #include "schannel.h" |
| #include "secur32_priv.h" |
| #include "wine/debug.h" |
| #include "wine/library.h" |
| |
| #ifdef HAVE_SECURITY_SECURITY_H |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(secur32); |
| |
| #if MAC_OS_X_VERSION_MAX_ALLOWED < 1060 |
| /* Defined in <Security/CipherSuite.h> in the 10.6 SDK or later. */ |
| enum { |
| TLS_ECDH_ECDSA_WITH_NULL_SHA = 0xC001, |
| TLS_ECDH_ECDSA_WITH_RC4_128_SHA = 0xC002, |
| TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC003, |
| TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA = 0xC004, |
| TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA = 0xC005, |
| TLS_ECDHE_ECDSA_WITH_NULL_SHA = 0xC006, |
| TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = 0xC007, |
| TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC008, |
| TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009, |
| TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A, |
| TLS_ECDH_RSA_WITH_NULL_SHA = 0xC00B, |
| TLS_ECDH_RSA_WITH_RC4_128_SHA = 0xC00C, |
| TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA = 0xC00D, |
| TLS_ECDH_RSA_WITH_AES_128_CBC_SHA = 0xC00E, |
| TLS_ECDH_RSA_WITH_AES_256_CBC_SHA = 0xC00F, |
| TLS_ECDHE_RSA_WITH_NULL_SHA = 0xC010, |
| TLS_ECDHE_RSA_WITH_RC4_128_SHA = 0xC011, |
| TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = 0xC012, |
| TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013, |
| TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014, |
| TLS_ECDH_anon_WITH_NULL_SHA = 0xC015, |
| TLS_ECDH_anon_WITH_RC4_128_SHA = 0xC016, |
| TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA = 0xC017, |
| TLS_ECDH_anon_WITH_AES_128_CBC_SHA = 0xC018, |
| TLS_ECDH_anon_WITH_AES_256_CBC_SHA = 0xC019, |
| }; |
| #endif |
| |
| #if MAC_OS_X_VERSION_MAX_ALLOWED < 1080 |
| /* Defined in <Security/CipherSuite.h> in the 10.8 SDK or later. */ |
| enum { |
| TLS_NULL_WITH_NULL_NULL = 0x0000, |
| TLS_RSA_WITH_NULL_MD5 = 0x0001, |
| TLS_RSA_WITH_NULL_SHA = 0x0002, |
| TLS_RSA_WITH_RC4_128_MD5 = 0x0004, |
| TLS_RSA_WITH_RC4_128_SHA = 0x0005, |
| TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000A, |
| TLS_RSA_WITH_NULL_SHA256 = 0x003B, |
| TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x003C, |
| TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x003D, |
| TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = 0x000D, |
| TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = 0x0010, |
| TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x0013, |
| TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x0016, |
| TLS_DH_DSS_WITH_AES_128_CBC_SHA256 = 0x003E, |
| TLS_DH_RSA_WITH_AES_128_CBC_SHA256 = 0x003F, |
| TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = 0x0040, |
| TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x0067, |
| TLS_DH_DSS_WITH_AES_256_CBC_SHA256 = 0x0068, |
| TLS_DH_RSA_WITH_AES_256_CBC_SHA256 = 0x0069, |
| TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = 0x006A, |
| TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x006B, |
| TLS_DH_anon_WITH_RC4_128_MD5 = 0x0018, |
| TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = 0x001B, |
| TLS_DH_anon_WITH_AES_128_CBC_SHA256 = 0x006C, |
| TLS_DH_anon_WITH_AES_256_CBC_SHA256 = 0x006D, |
| TLS_RSA_WITH_AES_128_GCM_SHA256 = 0x009C, |
| TLS_RSA_WITH_AES_256_GCM_SHA384 = 0x009D, |
| TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = 0x009E, |
| TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = 0x009F, |
| TLS_DH_RSA_WITH_AES_128_GCM_SHA256 = 0x00A0, |
| TLS_DH_RSA_WITH_AES_256_GCM_SHA384 = 0x00A1, |
| TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 = 0x00A2, |
| TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 = 0x00A3, |
| TLS_DH_DSS_WITH_AES_128_GCM_SHA256 = 0x00A4, |
| TLS_DH_DSS_WITH_AES_256_GCM_SHA384 = 0x00A5, |
| TLS_DH_anon_WITH_AES_128_GCM_SHA256 = 0x00A6, |
| TLS_DH_anon_WITH_AES_256_GCM_SHA384 = 0x00A7, |
| TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023, |
| TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC024, |
| TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC025, |
| TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC026, |
| TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027, |
| TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xC028, |
| TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 = 0xC029, |
| TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 = 0xC02A, |
| TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02B, |
| TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02C, |
| TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02D, |
| TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02E, |
| TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xC02F, |
| TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 0xC030, |
| TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 = 0xC031, |
| TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 = 0xC032, |
| TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF, |
| }; |
| |
| /* Defined in <Security/SecureTransport.h> in the 10.8 SDK or later. */ |
| enum { |
| kTLSProtocol11 = 7, /* TLS 1.1 */ |
| kTLSProtocol12 = 8, /* TLS 1.2 */ |
| }; |
| #endif |
| |
| #if MAC_OS_X_VERSION_MAX_ALLOWED < 1090 |
| /* Defined in <Security/CipherSuite.h> in the 10.9 SDK or later. */ |
| enum { |
| TLS_PSK_WITH_RC4_128_SHA = 0x008A, |
| TLS_PSK_WITH_3DES_EDE_CBC_SHA = 0x008B, |
| TLS_PSK_WITH_AES_128_CBC_SHA = 0x008C, |
| TLS_PSK_WITH_AES_256_CBC_SHA = 0x008D, |
| TLS_DHE_PSK_WITH_RC4_128_SHA = 0x008E, |
| TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = 0x008F, |
| TLS_DHE_PSK_WITH_AES_128_CBC_SHA = 0x0090, |
| TLS_DHE_PSK_WITH_AES_256_CBC_SHA = 0x0091, |
| TLS_RSA_PSK_WITH_RC4_128_SHA = 0x0092, |
| TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA = 0x0093, |
| TLS_RSA_PSK_WITH_AES_128_CBC_SHA = 0x0094, |
| TLS_RSA_PSK_WITH_AES_256_CBC_SHA = 0x0095, |
| TLS_PSK_WITH_NULL_SHA = 0x002C, |
| TLS_DHE_PSK_WITH_NULL_SHA = 0x002D, |
| TLS_RSA_PSK_WITH_NULL_SHA = 0x002E, |
| TLS_PSK_WITH_AES_128_GCM_SHA256 = 0x00A8, |
| TLS_PSK_WITH_AES_256_GCM_SHA384 = 0x00A9, |
| TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 = 0x00AA, |
| TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 = 0x00AB, |
| TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 = 0x00AC, |
| TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 = 0x00AD, |
| TLS_PSK_WITH_AES_128_CBC_SHA256 = 0x00AE, |
| TLS_PSK_WITH_AES_256_CBC_SHA384 = 0x00AF, |
| TLS_PSK_WITH_NULL_SHA256 = 0x00B0, |
| TLS_PSK_WITH_NULL_SHA384 = 0x00B1, |
| TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 = 0x00B2, |
| TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 = 0x00B3, |
| TLS_DHE_PSK_WITH_NULL_SHA256 = 0x00B4, |
| TLS_DHE_PSK_WITH_NULL_SHA384 = 0x00B5, |
| TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 = 0x00B6, |
| TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 = 0x00B7, |
| TLS_RSA_PSK_WITH_NULL_SHA256 = 0x00B8, |
| TLS_RSA_PSK_WITH_NULL_SHA384 = 0x00B9, |
| }; |
| #endif |
| |
| |
| struct mac_session { |
| SSLContextRef context; |
| struct schan_transport *transport; |
| CRITICAL_SECTION cs; |
| }; |
| |
| |
| enum { |
| schan_proto_SSL, |
| schan_proto_TLS, |
| }; |
| |
| enum { |
| schan_kx_DH_anon_EXPORT, |
| schan_kx_DH_anon, |
| schan_kx_DH_DSS_EXPORT, |
| schan_kx_DH_DSS, |
| schan_kx_DH_RSA_EXPORT, |
| schan_kx_DH_RSA, |
| schan_kx_DHE_DSS_EXPORT, |
| schan_kx_DHE_DSS, |
| schan_kx_DHE_PSK, |
| schan_kx_DHE_RSA_EXPORT, |
| schan_kx_DHE_RSA, |
| schan_kx_ECDH_anon, |
| schan_kx_ECDH_ECDSA, |
| schan_kx_ECDH_RSA, |
| schan_kx_ECDHE_ECDSA, |
| schan_kx_ECDHE_RSA, |
| schan_kx_FORTEZZA_DMS, |
| schan_kx_NULL, |
| schan_kx_PSK, |
| schan_kx_RSA_EXPORT, |
| schan_kx_RSA_PSK, |
| schan_kx_RSA, |
| }; |
| |
| enum { |
| schan_enc_3DES_EDE_CBC, |
| schan_enc_AES_128_CBC, |
| schan_enc_AES_128_GCM, |
| schan_enc_AES_256_CBC, |
| schan_enc_AES_256_GCM, |
| schan_enc_DES_CBC, |
| schan_enc_DES40_CBC, |
| schan_enc_FORTEZZA_CBC, |
| schan_enc_IDEA_CBC, |
| schan_enc_NULL, |
| schan_enc_RC2_CBC, |
| schan_enc_RC2_CBC_40, |
| schan_enc_RC4_128, |
| schan_enc_RC4_40, |
| }; |
| |
| enum { |
| schan_mac_MD5, |
| schan_mac_NULL, |
| schan_mac_SHA, |
| schan_mac_SHA256, |
| schan_mac_SHA384, |
| }; |
| |
| |
| struct cipher_suite { |
| SSLCipherSuite suite; |
| int protocol; |
| int kx_alg; |
| int enc_alg; |
| int mac_alg; |
| }; |
| |
| /* This table corresponds to the enum in <Security/CipherSuite.h>. */ |
| static const struct cipher_suite cipher_suites[] = { |
| #define CIPHER_SUITE(p, kx, enc, mac) { p##_##kx##_WITH_##enc##_##mac, schan_proto_##p, \ |
| schan_kx_##kx, schan_enc_##enc, schan_mac_##mac } |
| CIPHER_SUITE(SSL, RSA, NULL, MD5), |
| CIPHER_SUITE(SSL, RSA, NULL, MD5), |
| CIPHER_SUITE(SSL, RSA, NULL, SHA), |
| CIPHER_SUITE(SSL, RSA_EXPORT, RC4_40, MD5), |
| CIPHER_SUITE(SSL, RSA, RC4_128, MD5), |
| CIPHER_SUITE(SSL, RSA, RC4_128, SHA), |
| CIPHER_SUITE(SSL, RSA_EXPORT, RC2_CBC_40, MD5), |
| CIPHER_SUITE(SSL, RSA, IDEA_CBC, SHA), |
| CIPHER_SUITE(SSL, RSA_EXPORT, DES40_CBC, SHA), |
| CIPHER_SUITE(SSL, RSA, DES_CBC, SHA), |
| CIPHER_SUITE(SSL, RSA, 3DES_EDE_CBC, SHA), |
| CIPHER_SUITE(SSL, DH_DSS_EXPORT, DES40_CBC, SHA), |
| CIPHER_SUITE(SSL, DH_DSS, DES_CBC, SHA), |
| CIPHER_SUITE(SSL, DH_DSS, 3DES_EDE_CBC, SHA), |
| CIPHER_SUITE(SSL, DH_RSA_EXPORT, DES40_CBC, SHA), |
| CIPHER_SUITE(SSL, DH_RSA, DES_CBC, SHA), |
| CIPHER_SUITE(SSL, DH_RSA, 3DES_EDE_CBC, SHA), |
| CIPHER_SUITE(SSL, DHE_DSS_EXPORT, DES40_CBC, SHA), |
| CIPHER_SUITE(SSL, DHE_DSS, DES_CBC, SHA), |
| CIPHER_SUITE(SSL, DHE_DSS, 3DES_EDE_CBC, SHA), |
| CIPHER_SUITE(SSL, DHE_RSA_EXPORT, DES40_CBC, SHA), |
| CIPHER_SUITE(SSL, DHE_RSA, DES_CBC, SHA), |
| CIPHER_SUITE(SSL, DHE_RSA, 3DES_EDE_CBC, SHA), |
| CIPHER_SUITE(SSL, DH_anon_EXPORT, RC4_40, MD5), |
| CIPHER_SUITE(SSL, DH_anon, RC4_128, MD5), |
| CIPHER_SUITE(SSL, DH_anon_EXPORT, DES40_CBC, SHA), |
| CIPHER_SUITE(SSL, DH_anon, DES_CBC, SHA), |
| CIPHER_SUITE(SSL, DH_anon, 3DES_EDE_CBC, SHA), |
| CIPHER_SUITE(SSL, FORTEZZA_DMS, NULL, SHA), |
| CIPHER_SUITE(SSL, FORTEZZA_DMS, FORTEZZA_CBC, SHA), |
| |
| CIPHER_SUITE(TLS, RSA, AES_128_CBC, SHA), |
| CIPHER_SUITE(TLS, DH_DSS, AES_128_CBC, SHA), |
| CIPHER_SUITE(TLS, DH_RSA, AES_128_CBC, SHA), |
| CIPHER_SUITE(TLS, DHE_DSS, AES_128_CBC, SHA), |
| CIPHER_SUITE(TLS, DHE_RSA, AES_128_CBC, SHA), |
| CIPHER_SUITE(TLS, DH_anon, AES_128_CBC, SHA), |
| CIPHER_SUITE(TLS, RSA, AES_256_CBC, SHA), |
| CIPHER_SUITE(TLS, DH_DSS, AES_256_CBC, SHA), |
| CIPHER_SUITE(TLS, DH_RSA, AES_256_CBC, SHA), |
| CIPHER_SUITE(TLS, DHE_DSS, AES_256_CBC, SHA), |
| CIPHER_SUITE(TLS, DHE_RSA, AES_256_CBC, SHA), |
| CIPHER_SUITE(TLS, DH_anon, AES_256_CBC, SHA), |
| |
| CIPHER_SUITE(TLS, ECDH_ECDSA, NULL, SHA), |
| CIPHER_SUITE(TLS, ECDH_ECDSA, RC4_128, SHA), |
| CIPHER_SUITE(TLS, ECDH_ECDSA, 3DES_EDE_CBC, SHA), |
| CIPHER_SUITE(TLS, ECDH_ECDSA, AES_128_CBC, SHA), |
| CIPHER_SUITE(TLS, ECDH_ECDSA, AES_256_CBC, SHA), |
| CIPHER_SUITE(TLS, ECDHE_ECDSA, NULL, SHA), |
| CIPHER_SUITE(TLS, ECDHE_ECDSA, RC4_128, SHA), |
| CIPHER_SUITE(TLS, ECDHE_ECDSA, 3DES_EDE_CBC, SHA), |
| CIPHER_SUITE(TLS, ECDHE_ECDSA, AES_128_CBC, SHA), |
| CIPHER_SUITE(TLS, ECDHE_ECDSA, AES_256_CBC, SHA), |
| CIPHER_SUITE(TLS, ECDH_RSA, NULL, SHA), |
| CIPHER_SUITE(TLS, ECDH_RSA, RC4_128, SHA), |
| CIPHER_SUITE(TLS, ECDH_RSA, 3DES_EDE_CBC, SHA), |
| CIPHER_SUITE(TLS, ECDH_RSA, AES_128_CBC, SHA), |
| CIPHER_SUITE(TLS, ECDH_RSA, AES_256_CBC, SHA), |
| CIPHER_SUITE(TLS, ECDHE_RSA, NULL, SHA), |
| CIPHER_SUITE(TLS, ECDHE_RSA, RC4_128, SHA), |
| CIPHER_SUITE(TLS, ECDHE_RSA, 3DES_EDE_CBC, SHA), |
| CIPHER_SUITE(TLS, ECDHE_RSA, AES_128_CBC, SHA), |
| CIPHER_SUITE(TLS, ECDHE_RSA, AES_256_CBC, SHA), |
| CIPHER_SUITE(TLS, ECDH_anon, NULL, SHA), |
| CIPHER_SUITE(TLS, ECDH_anon, RC4_128, SHA), |
| CIPHER_SUITE(TLS, ECDH_anon, 3DES_EDE_CBC, SHA), |
| CIPHER_SUITE(TLS, ECDH_anon, AES_128_CBC, SHA), |
| CIPHER_SUITE(TLS, ECDH_anon, AES_256_CBC, SHA), |
| |
| CIPHER_SUITE(TLS, NULL, NULL, NULL), |
| CIPHER_SUITE(TLS, RSA, NULL, MD5), |
| CIPHER_SUITE(TLS, RSA, NULL, SHA), |
| CIPHER_SUITE(TLS, RSA, RC4_128, MD5), |
| CIPHER_SUITE(TLS, RSA, RC4_128, SHA), |
| CIPHER_SUITE(TLS, RSA, 3DES_EDE_CBC, SHA), |
| CIPHER_SUITE(TLS, RSA, NULL, SHA256), |
| CIPHER_SUITE(TLS, RSA, AES_128_CBC, SHA256), |
| CIPHER_SUITE(TLS, RSA, AES_256_CBC, SHA256), |
| CIPHER_SUITE(TLS, DH_DSS, 3DES_EDE_CBC, SHA), |
| CIPHER_SUITE(TLS, DH_RSA, 3DES_EDE_CBC, SHA), |
| CIPHER_SUITE(TLS, DHE_DSS, 3DES_EDE_CBC, SHA), |
| CIPHER_SUITE(TLS, DHE_RSA, 3DES_EDE_CBC, SHA), |
| CIPHER_SUITE(TLS, DH_DSS, AES_128_CBC, SHA256), |
| CIPHER_SUITE(TLS, DH_RSA, AES_128_CBC, SHA256), |
| CIPHER_SUITE(TLS, DHE_DSS, AES_128_CBC, SHA256), |
| CIPHER_SUITE(TLS, DHE_RSA, AES_128_CBC, SHA256), |
| CIPHER_SUITE(TLS, DH_DSS, AES_256_CBC, SHA256), |
| CIPHER_SUITE(TLS, DH_RSA, AES_256_CBC, SHA256), |
| CIPHER_SUITE(TLS, DHE_DSS, AES_256_CBC, SHA256), |
| CIPHER_SUITE(TLS, DHE_RSA, AES_256_CBC, SHA256), |
| CIPHER_SUITE(TLS, DH_anon, RC4_128, MD5), |
| CIPHER_SUITE(TLS, DH_anon, 3DES_EDE_CBC, SHA), |
| CIPHER_SUITE(TLS, DH_anon, AES_128_CBC, SHA256), |
| CIPHER_SUITE(TLS, DH_anon, AES_256_CBC, SHA256), |
| |
| CIPHER_SUITE(TLS, PSK, RC4_128, SHA), |
| CIPHER_SUITE(TLS, PSK, 3DES_EDE_CBC, SHA), |
| CIPHER_SUITE(TLS, PSK, AES_128_CBC, SHA), |
| CIPHER_SUITE(TLS, PSK, AES_256_CBC, SHA), |
| CIPHER_SUITE(TLS, DHE_PSK, RC4_128, SHA), |
| CIPHER_SUITE(TLS, DHE_PSK, 3DES_EDE_CBC, SHA), |
| CIPHER_SUITE(TLS, DHE_PSK, AES_128_CBC, SHA), |
| CIPHER_SUITE(TLS, DHE_PSK, AES_256_CBC, SHA), |
| CIPHER_SUITE(TLS, RSA_PSK, RC4_128, SHA), |
| CIPHER_SUITE(TLS, RSA_PSK, 3DES_EDE_CBC, SHA), |
| CIPHER_SUITE(TLS, RSA_PSK, AES_128_CBC, SHA), |
| CIPHER_SUITE(TLS, RSA_PSK, AES_256_CBC, SHA), |
| CIPHER_SUITE(TLS, PSK, NULL, SHA), |
| CIPHER_SUITE(TLS, DHE_PSK, NULL, SHA), |
| CIPHER_SUITE(TLS, RSA_PSK, NULL, SHA), |
| |
| CIPHER_SUITE(TLS, RSA, AES_128_GCM, SHA256), |
| CIPHER_SUITE(TLS, RSA, AES_256_GCM, SHA384), |
| CIPHER_SUITE(TLS, DHE_RSA, AES_128_GCM, SHA256), |
| CIPHER_SUITE(TLS, DHE_RSA, AES_256_GCM, SHA384), |
| CIPHER_SUITE(TLS, DH_RSA, AES_128_GCM, SHA256), |
| CIPHER_SUITE(TLS, DH_RSA, AES_256_GCM, SHA384), |
| CIPHER_SUITE(TLS, DHE_DSS, AES_128_GCM, SHA256), |
| CIPHER_SUITE(TLS, DHE_DSS, AES_256_GCM, SHA384), |
| CIPHER_SUITE(TLS, DH_DSS, AES_128_GCM, SHA256), |
| CIPHER_SUITE(TLS, DH_DSS, AES_256_GCM, SHA384), |
| CIPHER_SUITE(TLS, DH_anon, AES_128_GCM, SHA256), |
| CIPHER_SUITE(TLS, DH_anon, AES_256_GCM, SHA384), |
| |
| CIPHER_SUITE(TLS, PSK, AES_128_GCM, SHA256), |
| CIPHER_SUITE(TLS, PSK, AES_256_GCM, SHA384), |
| CIPHER_SUITE(TLS, DHE_PSK, AES_128_GCM, SHA256), |
| CIPHER_SUITE(TLS, DHE_PSK, AES_256_GCM, SHA384), |
| CIPHER_SUITE(TLS, RSA_PSK, AES_128_GCM, SHA256), |
| CIPHER_SUITE(TLS, RSA_PSK, AES_256_GCM, SHA384), |
| CIPHER_SUITE(TLS, PSK, AES_128_CBC, SHA256), |
| CIPHER_SUITE(TLS, PSK, AES_256_CBC, SHA384), |
| CIPHER_SUITE(TLS, PSK, NULL, SHA256), |
| CIPHER_SUITE(TLS, PSK, NULL, SHA384), |
| CIPHER_SUITE(TLS, DHE_PSK, AES_128_CBC, SHA256), |
| CIPHER_SUITE(TLS, DHE_PSK, AES_256_CBC, SHA384), |
| CIPHER_SUITE(TLS, DHE_PSK, NULL, SHA256), |
| CIPHER_SUITE(TLS, DHE_PSK, NULL, SHA384), |
| CIPHER_SUITE(TLS, RSA_PSK, AES_128_CBC, SHA256), |
| CIPHER_SUITE(TLS, RSA_PSK, AES_256_CBC, SHA384), |
| CIPHER_SUITE(TLS, RSA_PSK, NULL, SHA256), |
| CIPHER_SUITE(TLS, RSA_PSK, NULL, SHA384), |
| |
| CIPHER_SUITE(TLS, ECDHE_ECDSA, AES_128_CBC, SHA256), |
| CIPHER_SUITE(TLS, ECDHE_ECDSA, AES_256_CBC, SHA384), |
| CIPHER_SUITE(TLS, ECDH_ECDSA, AES_128_CBC, SHA256), |
| CIPHER_SUITE(TLS, ECDH_ECDSA, AES_256_CBC, SHA384), |
| CIPHER_SUITE(TLS, ECDHE_RSA, AES_128_CBC, SHA256), |
| CIPHER_SUITE(TLS, ECDHE_RSA, AES_256_CBC, SHA384), |
| CIPHER_SUITE(TLS, ECDH_RSA, AES_128_CBC, SHA256), |
| CIPHER_SUITE(TLS, ECDH_RSA, AES_256_CBC, SHA384), |
| CIPHER_SUITE(TLS, ECDHE_ECDSA, AES_128_GCM, SHA256), |
| CIPHER_SUITE(TLS, ECDHE_ECDSA, AES_256_GCM, SHA384), |
| CIPHER_SUITE(TLS, ECDH_ECDSA, AES_128_GCM, SHA256), |
| CIPHER_SUITE(TLS, ECDH_ECDSA, AES_256_GCM, SHA384), |
| CIPHER_SUITE(TLS, ECDHE_RSA, AES_128_GCM, SHA256), |
| CIPHER_SUITE(TLS, ECDHE_RSA, AES_256_GCM, SHA384), |
| CIPHER_SUITE(TLS, ECDH_RSA, AES_128_GCM, SHA256), |
| CIPHER_SUITE(TLS, ECDH_RSA, AES_256_GCM, SHA384), |
| |
| CIPHER_SUITE(SSL, RSA, RC2_CBC, MD5), |
| CIPHER_SUITE(SSL, RSA, IDEA_CBC, MD5), |
| CIPHER_SUITE(SSL, RSA, DES_CBC, MD5), |
| CIPHER_SUITE(SSL, RSA, 3DES_EDE_CBC, MD5), |
| #undef CIPHER_SUITE |
| }; |
| |
| |
| static const struct cipher_suite* get_cipher_suite(SSLCipherSuite cipher_suite) |
| { |
| int i; |
| for (i = 0; i < sizeof(cipher_suites)/sizeof(cipher_suites[0]); i++) |
| { |
| if (cipher_suites[i].suite == cipher_suite) |
| return &cipher_suites[i]; |
| } |
| |
| return NULL; |
| } |
| |
| |
| static DWORD schan_get_session_protocol(struct mac_session* s) |
| { |
| SSLProtocol protocol; |
| int status; |
| |
| TRACE("(%p/%p)\n", s, s->context); |
| |
| status = SSLGetNegotiatedProtocolVersion(s->context, &protocol); |
| if (status != noErr) |
| { |
| ERR("Failed to get session protocol: %d\n", status); |
| return 0; |
| } |
| |
| TRACE("protocol %d\n", protocol); |
| |
| switch (protocol) |
| { |
| case kSSLProtocol2: return SP_PROT_SSL2_CLIENT; |
| case kSSLProtocol3: return SP_PROT_SSL3_CLIENT; |
| case kTLSProtocol1: return SP_PROT_TLS1_CLIENT; |
| case kTLSProtocol11: return SP_PROT_TLS1_1_CLIENT; |
| case kTLSProtocol12: return SP_PROT_TLS1_2_CLIENT; |
| default: |
| FIXME("unknown protocol %d\n", protocol); |
| return 0; |
| } |
| } |
| |
| static ALG_ID schan_get_cipher_algid(const struct cipher_suite* c) |
| { |
| TRACE("(%#x)\n", (unsigned int)c->suite); |
| |
| switch (c->enc_alg) |
| { |
| case schan_enc_3DES_EDE_CBC: return CALG_3DES; |
| case schan_enc_AES_128_CBC: return CALG_AES_128; |
| case schan_enc_AES_256_CBC: return CALG_AES_256; |
| case schan_enc_DES_CBC: return CALG_DES; |
| case schan_enc_DES40_CBC: return CALG_DES; |
| case schan_enc_NULL: return 0; |
| case schan_enc_RC2_CBC_40: return CALG_RC2; |
| case schan_enc_RC2_CBC: return CALG_RC2; |
| case schan_enc_RC4_128: return CALG_RC4; |
| case schan_enc_RC4_40: return CALG_RC4; |
| |
| case schan_enc_AES_128_GCM: |
| case schan_enc_AES_256_GCM: |
| case schan_enc_FORTEZZA_CBC: |
| case schan_enc_IDEA_CBC: |
| FIXME("Don't know CALG for encryption algorithm %d, returning 0\n", c->enc_alg); |
| return 0; |
| |
| default: |
| FIXME("Unknown encryption algorithm %d for cipher suite %#x, returning 0\n", c->enc_alg, (unsigned int)c->suite); |
| return 0; |
| } |
| } |
| |
| static unsigned int schan_get_cipher_key_size(const struct cipher_suite* c) |
| { |
| TRACE("(%#x)\n", (unsigned int)c->suite); |
| |
| switch (c->enc_alg) |
| { |
| case schan_enc_3DES_EDE_CBC: return 168; |
| case schan_enc_AES_128_CBC: return 128; |
| case schan_enc_AES_128_GCM: return 128; |
| case schan_enc_AES_256_CBC: return 256; |
| case schan_enc_AES_256_GCM: return 256; |
| case schan_enc_DES_CBC: return 56; |
| case schan_enc_DES40_CBC: return 40; |
| case schan_enc_NULL: return 0; |
| case schan_enc_RC2_CBC_40: return 40; |
| case schan_enc_RC2_CBC: return 128; |
| case schan_enc_RC4_128: return 128; |
| case schan_enc_RC4_40: return 40; |
| |
| case schan_enc_FORTEZZA_CBC: |
| case schan_enc_IDEA_CBC: |
| FIXME("Don't know key size for encryption algorithm %d, returning 0\n", c->enc_alg); |
| return 0; |
| |
| default: |
| FIXME("Unknown encryption algorithm %d for cipher suite %#x, returning 0\n", c->enc_alg, (unsigned int)c->suite); |
| return 0; |
| } |
| } |
| |
| static ALG_ID schan_get_mac_algid(const struct cipher_suite* c) |
| { |
| TRACE("(%#x)\n", (unsigned int)c->suite); |
| |
| switch (c->mac_alg) |
| { |
| case schan_mac_MD5: return CALG_MD5; |
| case schan_mac_NULL: return 0; |
| case schan_mac_SHA: return CALG_SHA; |
| case schan_mac_SHA256: return CALG_SHA_256; |
| case schan_mac_SHA384: return CALG_SHA_384; |
| |
| default: |
| FIXME("Unknown hashing algorithm %d for cipher suite %#x, returning 0\n", c->mac_alg, (unsigned)c->suite); |
| return 0; |
| } |
| } |
| |
| static unsigned int schan_get_mac_key_size(const struct cipher_suite* c) |
| { |
| TRACE("(%#x)\n", (unsigned int)c->suite); |
| |
| switch (c->mac_alg) |
| { |
| case schan_mac_MD5: return 128; |
| case schan_mac_NULL: return 0; |
| case schan_mac_SHA: return 160; |
| case schan_mac_SHA256: return 256; |
| case schan_mac_SHA384: return 384; |
| |
| default: |
| FIXME("Unknown hashing algorithm %d for cipher suite %#x, returning 0\n", c->mac_alg, (unsigned)c->suite); |
| return 0; |
| } |
| } |
| |
| static ALG_ID schan_get_kx_algid(const struct cipher_suite* c) |
| { |
| TRACE("(%#x)\n", (unsigned int)c->suite); |
| |
| switch (c->kx_alg) |
| { |
| case schan_kx_DHE_DSS_EXPORT: |
| case schan_kx_DHE_DSS: |
| case schan_kx_DHE_PSK: |
| case schan_kx_DHE_RSA_EXPORT: |
| case schan_kx_DHE_RSA: return CALG_DH_EPHEM; |
| case schan_kx_ECDH_anon: |
| case schan_kx_ECDH_ECDSA: |
| case schan_kx_ECDH_RSA: return CALG_ECDH; |
| case schan_kx_ECDHE_ECDSA: |
| case schan_kx_ECDHE_RSA: return CALG_ECDH_EPHEM; |
| case schan_kx_NULL: return 0; |
| case schan_kx_RSA: |
| case schan_kx_RSA_EXPORT: |
| case schan_kx_RSA_PSK: return CALG_RSA_KEYX; |
| |
| case schan_kx_DH_anon_EXPORT: |
| case schan_kx_DH_anon: |
| case schan_kx_DH_DSS_EXPORT: |
| case schan_kx_DH_DSS: |
| case schan_kx_DH_RSA_EXPORT: |
| case schan_kx_DH_RSA: |
| case schan_kx_FORTEZZA_DMS: |
| case schan_kx_PSK: |
| FIXME("Don't know CALG for key exchange algorithm %d for cipher suite %#x, returning 0\n", c->kx_alg, (unsigned)c->suite); |
| return 0; |
| |
| default: |
| FIXME("Unknown key exchange algorithm %d for cipher suite %#x, returning 0\n", c->kx_alg, (unsigned)c->suite); |
| return 0; |
| } |
| } |
| |
| |
| /* schan_pull_adapter |
| * Callback registered with SSLSetIOFuncs as the read function for a |
| * session. Reads data from the session connection. Conforms to the |
| * SSLReadFunc type. |
| * |
| * transport - The session connection |
| * buff - The buffer into which to store the read data. Must be at least |
| * *buff_len bytes in length. |
| * *buff_len - On input, the desired length to read. On successful return, |
| * the number of bytes actually read. |
| * |
| * Returns: |
| * noErr on complete success meaning the requested length was successfully |
| * read. |
| * errSSLWouldBlock when the requested length could not be read without |
| * blocking. *buff_len indicates how much was actually read. The |
| * caller should try again if/when they want to read more. |
| * errSSLClosedGraceful when the connection has closed and there's no |
| * more data to be read. |
| * other error code for failure. |
| */ |
| static OSStatus schan_pull_adapter(SSLConnectionRef transport, void *buff, |
| SIZE_T *buff_len) |
| { |
| struct mac_session *s = (struct mac_session*)transport; |
| size_t requested = *buff_len; |
| int status; |
| OSStatus ret; |
| |
| TRACE("(%p/%p, %p, %p/%lu)\n", s, s->transport, buff, buff_len, *buff_len); |
| |
| status = schan_pull(s->transport, buff, buff_len); |
| if (status == 0) |
| { |
| if (*buff_len == 0) |
| { |
| TRACE("Connection closed\n"); |
| ret = errSSLClosedGraceful; |
| } |
| else if (*buff_len < requested) |
| { |
| TRACE("Pulled %lu bytes before would block\n", *buff_len); |
| ret = errSSLWouldBlock; |
| } |
| else |
| { |
| TRACE("Pulled %lu bytes\n", *buff_len); |
| ret = noErr; |
| } |
| } |
| else if (status == EAGAIN) |
| { |
| TRACE("Would block before being able to pull anything\n"); |
| ret = errSSLWouldBlock; |
| } |
| else |
| { |
| FIXME("Unknown status code from schan_pull: %d\n", status); |
| ret = ioErr; |
| } |
| |
| return ret; |
| } |
| |
| /* schan_push_adapter |
| * Callback registered with SSLSetIOFuncs as the write function for a |
| * session. Writes data to the session connection. Conforms to the |
| * SSLWriteFunc type. |
| * |
| * transport - The session connection |
| * buff - The buffer of data to write. Must be at least *buff_len bytes in length. |
| * *buff_len - On input, the desired length to write. On successful return, |
| * the number of bytes actually written. |
| * |
| * Returns: |
| * noErr on complete or partial success; *buff_len indicates how much data |
| * was actually written, which may be less than requested. |
| * errSSLWouldBlock when no data could be written without blocking. The |
| * caller should try again. |
| * other error code for failure. |
| */ |
| static OSStatus schan_push_adapter(SSLConnectionRef transport, const void *buff, |
| SIZE_T *buff_len) |
| { |
| struct mac_session *s = (struct mac_session*)transport; |
| int status; |
| OSStatus ret; |
| |
| TRACE("(%p/%p, %p, %p/%lu)\n", s, s->transport, buff, buff_len, *buff_len); |
| |
| status = schan_push(s->transport, buff, buff_len); |
| if (status == 0) |
| { |
| TRACE("Pushed %lu bytes\n", *buff_len); |
| ret = noErr; |
| } |
| else if (status == EAGAIN) |
| { |
| TRACE("Would block before being able to push anything\n"); |
| ret = errSSLWouldBlock; |
| } |
| else |
| { |
| FIXME("Unknown status code from schan_push: %d\n", status); |
| ret = ioErr; |
| } |
| |
| return ret; |
| } |
| |
| static const struct { |
| DWORD enable_flag; |
| SSLProtocol mac_version; |
| } protocol_priority_flags[] = { |
| {SP_PROT_TLS1_2_CLIENT, kTLSProtocol12}, |
| {SP_PROT_TLS1_1_CLIENT, kTLSProtocol11}, |
| {SP_PROT_TLS1_0_CLIENT, kTLSProtocol1}, |
| {SP_PROT_SSL3_CLIENT, kSSLProtocol3}, |
| {SP_PROT_SSL2_CLIENT, kSSLProtocol2} |
| }; |
| |
| static DWORD supported_protocols; |
| |
| DWORD schan_imp_enabled_protocols(void) |
| { |
| return supported_protocols; |
| } |
| |
| BOOL schan_imp_create_session(schan_imp_session *session, schan_credentials *cred) |
| { |
| struct mac_session *s; |
| unsigned i; |
| int status; |
| |
| TRACE("(%p)\n", session); |
| |
| s = HeapAlloc(GetProcessHeap(), 0, sizeof(*s)); |
| if (!s) |
| return FALSE; |
| |
| InitializeCriticalSection(&s->cs); |
| s->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": mac_session.cs"); |
| |
| status = SSLNewContext(cred->credential_use == SECPKG_CRED_INBOUND, &s->context); |
| if (status != noErr) |
| { |
| ERR("Failed to create session context: %d\n", status); |
| goto fail; |
| } |
| |
| status = SSLSetConnection(s->context, s); |
| if (status != noErr) |
| { |
| ERR("Failed to set session connection: %d\n", status); |
| goto fail; |
| } |
| |
| status = SSLSetEnableCertVerify(s->context, FALSE); |
| if (status != noErr) |
| { |
| ERR("Failed to disable certificate verification: %d\n", status); |
| goto fail; |
| } |
| |
| for(i=0; i < sizeof(protocol_priority_flags)/sizeof(*protocol_priority_flags); i++) { |
| if(!(protocol_priority_flags[i].enable_flag & supported_protocols)) |
| continue; |
| |
| status = SSLSetProtocolVersionEnabled(s->context, protocol_priority_flags[i].mac_version, |
| (cred->enabled_protocols & protocol_priority_flags[i].enable_flag) != 0); |
| if (status != noErr) |
| { |
| ERR("Failed to set SSL version %d: %d\n", protocol_priority_flags[i].mac_version, status); |
| goto fail; |
| } |
| } |
| |
| status = SSLSetIOFuncs(s->context, schan_pull_adapter, schan_push_adapter); |
| if (status != noErr) |
| { |
| ERR("Failed to set session I/O funcs: %d\n", status); |
| goto fail; |
| } |
| |
| TRACE(" -> %p/%p\n", s, s->context); |
| |
| *session = (schan_imp_session)s; |
| return TRUE; |
| |
| fail: |
| HeapFree(GetProcessHeap(), 0, s); |
| return FALSE; |
| } |
| |
| void schan_imp_dispose_session(schan_imp_session session) |
| { |
| struct mac_session *s = (struct mac_session*)session; |
| int status; |
| |
| TRACE("(%p/%p)\n", s, s->context); |
| |
| status = SSLDisposeContext(s->context); |
| if (status != noErr) |
| ERR("Failed to dispose of session context: %d\n", status); |
| DeleteCriticalSection(&s->cs); |
| HeapFree(GetProcessHeap(), 0, s); |
| } |
| |
| void schan_imp_set_session_transport(schan_imp_session session, |
| struct schan_transport *t) |
| { |
| struct mac_session *s = (struct mac_session*)session; |
| |
| TRACE("(%p/%p, %p)\n", s, s->context, t); |
| |
| s->transport = t; |
| } |
| |
| void schan_imp_set_session_target(schan_imp_session session, const char *target) |
| { |
| struct mac_session *s = (struct mac_session*)session; |
| |
| TRACE("(%p/%p, %s)\n", s, s->context, debugstr_a(target)); |
| |
| SSLSetPeerDomainName( s->context, target, strlen(target) ); |
| } |
| |
| SECURITY_STATUS schan_imp_handshake(schan_imp_session session) |
| { |
| struct mac_session *s = (struct mac_session*)session; |
| int status; |
| |
| TRACE("(%p/%p)\n", s, s->context); |
| |
| status = SSLHandshake(s->context); |
| if (status == noErr) |
| { |
| TRACE("Handshake completed\n"); |
| return SEC_E_OK; |
| } |
| else if (status == errSSLWouldBlock) |
| { |
| TRACE("Continue...\n"); |
| return SEC_I_CONTINUE_NEEDED; |
| } |
| else if (errSecErrnoBase <= status && status <= errSecErrnoLimit) |
| { |
| ERR("Handshake failed: %s\n", strerror(status)); |
| return SEC_E_INTERNAL_ERROR; |
| } |
| else |
| { |
| ERR("Handshake failed: %d\n", status); |
| cssmPerror("SSLHandshake", status); |
| return SEC_E_INTERNAL_ERROR; |
| } |
| |
| /* Never reached */ |
| return SEC_E_OK; |
| } |
| |
| unsigned int schan_imp_get_session_cipher_block_size(schan_imp_session session) |
| { |
| struct mac_session* s = (struct mac_session*)session; |
| SSLCipherSuite cipherSuite; |
| const struct cipher_suite* c; |
| int status; |
| |
| TRACE("(%p/%p)\n", s, s->context); |
| |
| status = SSLGetNegotiatedCipher(s->context, &cipherSuite); |
| if (status != noErr) |
| { |
| ERR("Failed to get session cipher suite: %d\n", status); |
| return 0; |
| } |
| |
| c = get_cipher_suite(cipherSuite); |
| if (!c) |
| { |
| ERR("Unknown session cipher suite: %#x\n", (unsigned int)cipherSuite); |
| return 0; |
| } |
| |
| switch (c->enc_alg) |
| { |
| case schan_enc_3DES_EDE_CBC: return 64; |
| case schan_enc_AES_128_CBC: return 128; |
| case schan_enc_AES_128_GCM: return 128; |
| case schan_enc_AES_256_CBC: return 128; |
| case schan_enc_AES_256_GCM: return 128; |
| case schan_enc_DES_CBC: return 64; |
| case schan_enc_DES40_CBC: return 64; |
| case schan_enc_NULL: return 0; |
| case schan_enc_RC2_CBC_40: return 64; |
| case schan_enc_RC2_CBC: return 64; |
| case schan_enc_RC4_128: return 0; |
| case schan_enc_RC4_40: return 0; |
| |
| case schan_enc_FORTEZZA_CBC: |
| case schan_enc_IDEA_CBC: |
| FIXME("Don't know block size for encryption algorithm %d, returning 0\n", c->enc_alg); |
| return 0; |
| |
| default: |
| FIXME("Unknown encryption algorithm %d for cipher suite %#x, returning 0\n", c->enc_alg, (unsigned int)c->suite); |
| return 0; |
| } |
| } |
| |
| unsigned int schan_imp_get_max_message_size(schan_imp_session session) |
| { |
| FIXME("Returning 1 << 14.\n"); |
| return 1 << 14; |
| } |
| |
| ALG_ID schan_imp_get_key_signature_algorithm(schan_imp_session session) |
| { |
| struct mac_session* s = (struct mac_session*)session; |
| SSLCipherSuite cipherSuite; |
| const struct cipher_suite* c; |
| int status; |
| |
| TRACE("(%p/%p)\n", s, s->context); |
| |
| status = SSLGetNegotiatedCipher(s->context, &cipherSuite); |
| if (status != noErr) |
| { |
| ERR("Failed to get session cipher suite: %d\n", status); |
| return 0; |
| } |
| |
| c = get_cipher_suite(cipherSuite); |
| if (!c) |
| { |
| ERR("Unknown session cipher suite: %#x\n", (unsigned int)cipherSuite); |
| return 0; |
| } |
| |
| switch (c->kx_alg) |
| { |
| case schan_kx_DH_DSS_EXPORT: |
| case schan_kx_DH_DSS: |
| case schan_kx_DHE_DSS_EXPORT: |
| case schan_kx_DHE_DSS: |
| return CALG_DSS_SIGN; |
| |
| case schan_kx_DH_RSA_EXPORT: |
| case schan_kx_DH_RSA: |
| case schan_kx_DHE_RSA_EXPORT: |
| case schan_kx_DHE_RSA: |
| case schan_kx_ECDH_RSA: |
| case schan_kx_ECDHE_RSA: |
| case schan_kx_RSA_EXPORT: |
| case schan_kx_RSA: |
| return CALG_RSA_SIGN; |
| |
| case schan_kx_ECDH_ECDSA: |
| case schan_kx_ECDHE_ECDSA: |
| return CALG_ECDSA; |
| |
| case schan_kx_DH_anon_EXPORT: |
| case schan_kx_DH_anon: |
| case schan_kx_DHE_PSK: |
| case schan_kx_ECDH_anon: |
| case schan_kx_FORTEZZA_DMS: |
| case schan_kx_NULL: |
| case schan_kx_PSK: |
| case schan_kx_RSA_PSK: |
| FIXME("Don't know key signature algorithm for key exchange algorithm %d, returning 0\n", c->kx_alg); |
| return 0; |
| |
| default: |
| FIXME("Unknown key exchange algorithm %d for cipher suite %#x, returning 0\n", c->kx_alg, (unsigned int)c->suite); |
| return 0; |
| } |
| } |
| |
| SECURITY_STATUS schan_imp_get_connection_info(schan_imp_session session, |
| SecPkgContext_ConnectionInfo *info) |
| { |
| struct mac_session* s = (struct mac_session*)session; |
| SSLCipherSuite cipherSuite; |
| const struct cipher_suite* c; |
| int status; |
| |
| TRACE("(%p/%p, %p)\n", s, s->context, info); |
| |
| status = SSLGetNegotiatedCipher(s->context, &cipherSuite); |
| if (status != noErr) |
| { |
| ERR("Failed to get session cipher suite: %d\n", status); |
| return SEC_E_INTERNAL_ERROR; |
| } |
| |
| c = get_cipher_suite(cipherSuite); |
| if (!c) |
| { |
| ERR("Unknown session cipher suite: %#x\n", (unsigned int)cipherSuite); |
| return SEC_E_INTERNAL_ERROR; |
| } |
| |
| info->dwProtocol = schan_get_session_protocol(s); |
| info->aiCipher = schan_get_cipher_algid(c); |
| info->dwCipherStrength = schan_get_cipher_key_size(c); |
| info->aiHash = schan_get_mac_algid(c); |
| info->dwHashStrength = schan_get_mac_key_size(c); |
| info->aiExch = schan_get_kx_algid(c); |
| /* FIXME: info->dwExchStrength? */ |
| info->dwExchStrength = 0; |
| |
| return SEC_E_OK; |
| } |
| |
| #ifndef HAVE_SSLCOPYPEERCERTIFICATES |
| static void schan_imp_cf_release(const void *arg, void *ctx) |
| { |
| CFRelease(arg); |
| } |
| #endif |
| |
| SECURITY_STATUS schan_imp_get_session_peer_certificate(schan_imp_session session, HCERTSTORE store, |
| PCCERT_CONTEXT *ret_cert) |
| { |
| struct mac_session* s = (struct mac_session*)session; |
| SECURITY_STATUS ret = SEC_E_OK; |
| PCCERT_CONTEXT cert = NULL; |
| SecCertificateRef mac_cert; |
| CFArrayRef cert_array; |
| int status; |
| CFIndex cnt, i; |
| CFDataRef data; |
| BOOL res; |
| |
| TRACE("(%p/%p, %p)\n", s, s->context, cert); |
| |
| #ifdef HAVE_SSLCOPYPEERCERTIFICATES |
| status = SSLCopyPeerCertificates(s->context, &cert_array); |
| #else |
| status = SSLGetPeerCertificates(s->context, &cert_array); |
| #endif |
| if (status != noErr || !cert_array) |
| { |
| WARN("SSLCopyPeerCertificates failed: %d\n", status); |
| return SEC_E_INTERNAL_ERROR; |
| } |
| |
| cnt = CFArrayGetCount(cert_array); |
| for (i=0; i < cnt; i++) { |
| if (!(mac_cert = (SecCertificateRef)CFArrayGetValueAtIndex(cert_array, i)) || |
| (SecKeychainItemExport(mac_cert, kSecFormatX509Cert, 0, NULL, &data) != noErr)) |
| { |
| WARN("Couldn't extract certificate data\n"); |
| ret = SEC_E_INTERNAL_ERROR; |
| break; |
| } |
| |
| res = CertAddEncodedCertificateToStore(store, X509_ASN_ENCODING, CFDataGetBytePtr(data), CFDataGetLength(data), |
| CERT_STORE_ADD_REPLACE_EXISTING, i ? NULL : &cert); |
| CFRelease(data); |
| if (!res) |
| { |
| ret = GetLastError(); |
| WARN("CertAddEncodedCertificateToStore failed: %x\n", ret); |
| break; |
| } |
| } |
| |
| #ifndef HAVE_SSLCOPYPEERCERTIFICATES |
| /* This is why SSLGetPeerCertificates was deprecated */ |
| CFArrayApplyFunction(cert_array, CFRangeMake(0, CFArrayGetCount(cert_array)), |
| schan_imp_cf_release, NULL); |
| #endif |
| CFRelease(cert_array); |
| if (ret != SEC_E_OK) { |
| if(cert) |
| CertFreeCertificateContext(cert); |
| return ret; |
| } |
| |
| *ret_cert = cert; |
| return SEC_E_OK; |
| } |
| |
| SECURITY_STATUS schan_imp_send(schan_imp_session session, const void *buffer, |
| SIZE_T *length) |
| { |
| struct mac_session* s = (struct mac_session*)session; |
| int status; |
| |
| TRACE("(%p/%p, %p, %p/%lu)\n", s, s->context, buffer, length, *length); |
| |
| EnterCriticalSection(&s->cs); |
| status = SSLWrite(s->context, buffer, *length, length); |
| LeaveCriticalSection(&s->cs); |
| if (status == noErr) |
| TRACE("Wrote %lu bytes\n", *length); |
| else if (status == errSSLWouldBlock) |
| { |
| if (!*length) |
| { |
| TRACE("Would block before being able to write anything\n"); |
| return SEC_I_CONTINUE_NEEDED; |
| } |
| else |
| TRACE("Wrote %lu bytes before would block\n", *length); |
| } |
| else |
| { |
| WARN("SSLWrite failed: %d\n", status); |
| return SEC_E_INTERNAL_ERROR; |
| } |
| |
| return SEC_E_OK; |
| } |
| |
| SECURITY_STATUS schan_imp_recv(schan_imp_session session, void *buffer, |
| SIZE_T *length) |
| { |
| struct mac_session* s = (struct mac_session*)session; |
| int status; |
| |
| TRACE("(%p/%p, %p, %p/%lu)\n", s, s->context, buffer, length, *length); |
| |
| EnterCriticalSection(&s->cs); |
| status = SSLRead(s->context, buffer, *length, length); |
| LeaveCriticalSection(&s->cs); |
| if (status == noErr || status == errSSLClosedGraceful) |
| TRACE("Read %lu bytes\n", *length); |
| else if (status == errSSLWouldBlock) |
| { |
| if (!*length) |
| { |
| TRACE("Would block before being able to read anything\n"); |
| return SEC_I_CONTINUE_NEEDED; |
| } |
| else |
| TRACE("Read %lu bytes before would block\n", *length); |
| } |
| else |
| { |
| WARN("SSLRead failed: %d\n", status); |
| return SEC_E_INTERNAL_ERROR; |
| } |
| |
| return SEC_E_OK; |
| } |
| |
| BOOL schan_imp_allocate_certificate_credentials(schan_credentials *c) |
| { |
| /* The certificate is never really used for anything. */ |
| c->credentials = NULL; |
| return TRUE; |
| } |
| |
| void schan_imp_free_certificate_credentials(schan_credentials *c) |
| { |
| } |
| |
| BOOL schan_imp_init(void) |
| { |
| TRACE("()\n"); |
| |
| supported_protocols = SP_PROT_SSL2_CLIENT | SP_PROT_SSL3_CLIENT | SP_PROT_TLS1_0_CLIENT; |
| |
| #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 |
| if(SSLGetProtocolVersionMax != NULL) { |
| SSLProtocol max_protocol; |
| SSLContextRef ctx; |
| OSStatus status; |
| |
| status = SSLNewContext(FALSE, &ctx); |
| if(status == noErr) { |
| status = SSLGetProtocolVersionMax(ctx, &max_protocol); |
| if(status == noErr) { |
| if(max_protocol >= kTLSProtocol11) |
| supported_protocols |= SP_PROT_TLS1_1_CLIENT; |
| if(max_protocol >= kTLSProtocol12) |
| supported_protocols |= SP_PROT_TLS1_2_CLIENT; |
| } |
| SSLDisposeContext(ctx); |
| }else { |
| WARN("SSLNewContext failed\n"); |
| } |
| } |
| #endif |
| |
| return TRUE; |
| } |
| |
| void schan_imp_deinit(void) |
| { |
| TRACE("()\n"); |
| } |
| |
| #endif /* HAVE_SECURITY_SECURITY_H */ |