dinput: Avoid signed-unsigned integer comparisons.
[wine] / dlls / secur32 / schannel_macosx.c
1 /*
2  * Mac OS X Secure Transport implementation of the schannel (SSL/TLS) provider.
3  *
4  * Copyright 2005 Juan Lang
5  * Copyright 2008 Henri Verbeet
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <stdarg.h>
26 #ifdef HAVE_SECURITY_SECURITY_H
27 #include <Security/Security.h>
28 #define GetCurrentThread GetCurrentThread_Mac
29 #define LoadResource LoadResource_Mac
30 #include <CoreServices/CoreServices.h>
31 #undef GetCurrentThread
32 #undef LoadResource
33 #undef DPRINTF
34 #endif
35
36 #include "windef.h"
37 #include "winbase.h"
38 #include "sspi.h"
39 #include "schannel.h"
40 #include "secur32_priv.h"
41 #include "wine/debug.h"
42 #include "wine/library.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(secur32);
45
46 #ifdef HAVE_SECURITY_SECURITY_H
47
48 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1060
49 /* Defined in <Security/CipherSuite.h> in the 10.6 SDK or later. */
50 enum {
51     TLS_ECDH_ECDSA_WITH_NULL_SHA           =    0xC001,
52     TLS_ECDH_ECDSA_WITH_RC4_128_SHA        =    0xC002,
53     TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA   =    0xC003,
54     TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA    =    0xC004,
55     TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA    =    0xC005,
56     TLS_ECDHE_ECDSA_WITH_NULL_SHA          =    0xC006,
57     TLS_ECDHE_ECDSA_WITH_RC4_128_SHA       =    0xC007,
58     TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA  =    0xC008,
59     TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA   =    0xC009,
60     TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA   =    0xC00A,
61     TLS_ECDH_RSA_WITH_NULL_SHA             =    0xC00B,
62     TLS_ECDH_RSA_WITH_RC4_128_SHA          =    0xC00C,
63     TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA     =    0xC00D,
64     TLS_ECDH_RSA_WITH_AES_128_CBC_SHA      =    0xC00E,
65     TLS_ECDH_RSA_WITH_AES_256_CBC_SHA      =    0xC00F,
66     TLS_ECDHE_RSA_WITH_NULL_SHA            =    0xC010,
67     TLS_ECDHE_RSA_WITH_RC4_128_SHA         =    0xC011,
68     TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA    =    0xC012,
69     TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA     =    0xC013,
70     TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA     =    0xC014,
71     TLS_ECDH_anon_WITH_NULL_SHA            =    0xC015,
72     TLS_ECDH_anon_WITH_RC4_128_SHA         =    0xC016,
73     TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA    =    0xC017,
74     TLS_ECDH_anon_WITH_AES_128_CBC_SHA     =    0xC018,
75     TLS_ECDH_anon_WITH_AES_256_CBC_SHA     =    0xC019,
76 };
77 #endif
78
79 struct mac_session {
80     SSLContextRef context;
81     struct schan_transport *transport;
82 };
83
84
85 enum {
86     schan_proto_SSL,
87     schan_proto_TLS,
88 };
89
90 enum {
91     schan_kx_DH_anon_EXPORT,
92     schan_kx_DH_anon,
93     schan_kx_DH_DSS_EXPORT,
94     schan_kx_DH_DSS,
95     schan_kx_DH_RSA_EXPORT,
96     schan_kx_DH_RSA,
97     schan_kx_DHE_DSS_EXPORT,
98     schan_kx_DHE_DSS,
99     schan_kx_DHE_RSA_EXPORT,
100     schan_kx_DHE_RSA,
101     schan_kx_ECDH_anon,
102     schan_kx_ECDH_ECDSA,
103     schan_kx_ECDH_RSA,
104     schan_kx_ECDHE_ECDSA,
105     schan_kx_ECDHE_RSA,
106     schan_kx_FORTEZZA_DMS,
107     schan_kx_NULL,
108     schan_kx_RSA_EXPORT,
109     schan_kx_RSA,
110 };
111
112 enum {
113     schan_enc_3DES_EDE_CBC,
114     schan_enc_AES_128_CBC,
115     schan_enc_AES_256_CBC,
116     schan_enc_DES_CBC,
117     schan_enc_DES40_CBC,
118     schan_enc_FORTEZZA_CBC,
119     schan_enc_IDEA_CBC,
120     schan_enc_NULL,
121     schan_enc_RC2_CBC,
122     schan_enc_RC2_CBC_40,
123     schan_enc_RC4_128,
124     schan_enc_RC4_40,
125 };
126
127 enum {
128     schan_mac_MD5,
129     schan_mac_NULL,
130     schan_mac_SHA,
131 };
132
133
134 struct cipher_suite {
135     SSLCipherSuite suite;
136     int protocol;
137     int kx_alg;
138     int enc_alg;
139     int mac_alg;
140 };
141
142 /* This table corresponds to the enum in <Security/CipherSuite.h>. */
143 static const struct cipher_suite cipher_suites[] = {
144 #define CIPHER_SUITE(p, kx, enc, mac) { p##_##kx##_WITH_##enc##_##mac, schan_proto_##p, \
145                                         schan_kx_##kx, schan_enc_##enc, schan_mac_##mac }
146     CIPHER_SUITE(SSL, RSA, NULL, MD5),
147     CIPHER_SUITE(SSL, RSA, NULL, MD5),
148     CIPHER_SUITE(SSL, RSA, NULL, SHA),
149     CIPHER_SUITE(SSL, RSA_EXPORT, RC4_40, MD5),
150     CIPHER_SUITE(SSL, RSA, RC4_128, MD5),
151     CIPHER_SUITE(SSL, RSA, RC4_128, SHA),
152     CIPHER_SUITE(SSL, RSA_EXPORT, RC2_CBC_40, MD5),
153     CIPHER_SUITE(SSL, RSA, IDEA_CBC, SHA),
154     CIPHER_SUITE(SSL, RSA_EXPORT, DES40_CBC, SHA),
155     CIPHER_SUITE(SSL, RSA, DES_CBC, SHA),
156     CIPHER_SUITE(SSL, RSA, 3DES_EDE_CBC, SHA),
157     CIPHER_SUITE(SSL, DH_DSS_EXPORT, DES40_CBC, SHA),
158     CIPHER_SUITE(SSL, DH_DSS, DES_CBC, SHA),
159     CIPHER_SUITE(SSL, DH_DSS, 3DES_EDE_CBC, SHA),
160     CIPHER_SUITE(SSL, DH_RSA_EXPORT, DES40_CBC, SHA),
161     CIPHER_SUITE(SSL, DH_RSA, DES_CBC, SHA),
162     CIPHER_SUITE(SSL, DH_RSA, 3DES_EDE_CBC, SHA),
163     CIPHER_SUITE(SSL, DHE_DSS_EXPORT, DES40_CBC, SHA),
164     CIPHER_SUITE(SSL, DHE_DSS, DES_CBC, SHA),
165     CIPHER_SUITE(SSL, DHE_DSS, 3DES_EDE_CBC, SHA),
166     CIPHER_SUITE(SSL, DHE_RSA_EXPORT, DES40_CBC, SHA),
167     CIPHER_SUITE(SSL, DHE_RSA, DES_CBC, SHA),
168     CIPHER_SUITE(SSL, DHE_RSA, 3DES_EDE_CBC, SHA),
169     CIPHER_SUITE(SSL, DH_anon_EXPORT, RC4_40, MD5),
170     CIPHER_SUITE(SSL, DH_anon, RC4_128, MD5),
171     CIPHER_SUITE(SSL, DH_anon_EXPORT, DES40_CBC, SHA),
172     CIPHER_SUITE(SSL, DH_anon, DES_CBC, SHA),
173     CIPHER_SUITE(SSL, DH_anon, 3DES_EDE_CBC, SHA),
174     CIPHER_SUITE(SSL, FORTEZZA_DMS, NULL, SHA),
175     CIPHER_SUITE(SSL, FORTEZZA_DMS, FORTEZZA_CBC, SHA),
176
177     CIPHER_SUITE(TLS, RSA, AES_128_CBC, SHA),
178     CIPHER_SUITE(TLS, DH_DSS, AES_128_CBC, SHA),
179     CIPHER_SUITE(TLS, DH_RSA, AES_128_CBC, SHA),
180     CIPHER_SUITE(TLS, DHE_DSS, AES_128_CBC, SHA),
181     CIPHER_SUITE(TLS, DHE_RSA, AES_128_CBC, SHA),
182     CIPHER_SUITE(TLS, DH_anon, AES_128_CBC, SHA),
183     CIPHER_SUITE(TLS, RSA, AES_256_CBC, SHA),
184     CIPHER_SUITE(TLS, DH_DSS, AES_256_CBC, SHA),
185     CIPHER_SUITE(TLS, DH_RSA, AES_256_CBC, SHA),
186     CIPHER_SUITE(TLS, DHE_DSS, AES_256_CBC, SHA),
187     CIPHER_SUITE(TLS, DHE_RSA, AES_256_CBC, SHA),
188     CIPHER_SUITE(TLS, DH_anon, AES_256_CBC, SHA),
189
190     CIPHER_SUITE(TLS, ECDH_ECDSA, NULL, SHA),
191     CIPHER_SUITE(TLS, ECDH_ECDSA, RC4_128, SHA),
192     CIPHER_SUITE(TLS, ECDH_ECDSA, 3DES_EDE_CBC, SHA),
193     CIPHER_SUITE(TLS, ECDH_ECDSA, AES_128_CBC, SHA),
194     CIPHER_SUITE(TLS, ECDH_ECDSA, AES_256_CBC, SHA),
195     CIPHER_SUITE(TLS, ECDHE_ECDSA, NULL, SHA),
196     CIPHER_SUITE(TLS, ECDHE_ECDSA, RC4_128, SHA),
197     CIPHER_SUITE(TLS, ECDHE_ECDSA, 3DES_EDE_CBC, SHA),
198     CIPHER_SUITE(TLS, ECDHE_ECDSA, AES_128_CBC, SHA),
199     CIPHER_SUITE(TLS, ECDHE_ECDSA, AES_256_CBC, SHA),
200     CIPHER_SUITE(TLS, ECDH_RSA, NULL, SHA),
201     CIPHER_SUITE(TLS, ECDH_RSA, RC4_128, SHA),
202     CIPHER_SUITE(TLS, ECDH_RSA, 3DES_EDE_CBC, SHA),
203     CIPHER_SUITE(TLS, ECDH_RSA, AES_128_CBC, SHA),
204     CIPHER_SUITE(TLS, ECDH_RSA, AES_256_CBC, SHA),
205     CIPHER_SUITE(TLS, ECDHE_RSA, NULL, SHA),
206     CIPHER_SUITE(TLS, ECDHE_RSA, RC4_128, SHA),
207     CIPHER_SUITE(TLS, ECDHE_RSA, 3DES_EDE_CBC, SHA),
208     CIPHER_SUITE(TLS, ECDHE_RSA, AES_128_CBC, SHA),
209     CIPHER_SUITE(TLS, ECDHE_RSA, AES_256_CBC, SHA),
210     CIPHER_SUITE(TLS, ECDH_anon, NULL, SHA),
211     CIPHER_SUITE(TLS, ECDH_anon, RC4_128, SHA),
212     CIPHER_SUITE(TLS, ECDH_anon, 3DES_EDE_CBC, SHA),
213     CIPHER_SUITE(TLS, ECDH_anon, AES_128_CBC, SHA),
214     CIPHER_SUITE(TLS, ECDH_anon, AES_256_CBC, SHA),
215
216     CIPHER_SUITE(SSL, RSA, RC2_CBC, MD5),
217     CIPHER_SUITE(SSL, RSA, IDEA_CBC, MD5),
218     CIPHER_SUITE(SSL, RSA, DES_CBC, MD5),
219     CIPHER_SUITE(SSL, RSA, 3DES_EDE_CBC, MD5),
220 #undef CIPHER_SUITE
221 };
222
223
224 static const struct cipher_suite* get_cipher_suite(SSLCipherSuite cipher_suite)
225 {
226     int i;
227     for (i = 0; i < sizeof(cipher_suites)/sizeof(cipher_suites[0]); i++)
228     {
229         if (cipher_suites[i].suite == cipher_suite)
230             return &cipher_suites[i];
231     }
232
233     return NULL;
234 }
235
236
237 static DWORD schan_get_session_protocol(struct mac_session* s)
238 {
239     SSLProtocol protocol;
240     OSStatus status;
241
242     TRACE("(%p/%p)\n", s, s->context);
243
244     status = SSLGetNegotiatedProtocolVersion(s->context, &protocol);
245     if (status != noErr)
246     {
247         ERR("Failed to get session protocol: %ld\n", status);
248         return 0;
249     }
250
251     TRACE("protocol %d\n", protocol);
252
253     switch (protocol)
254     {
255     case kSSLProtocol2: return SP_PROT_SSL2_CLIENT;
256     case kSSLProtocol3: return SP_PROT_SSL3_CLIENT;
257     case kTLSProtocol1: return SP_PROT_TLS1_CLIENT;
258     default:
259         FIXME("unknown protocol %d\n", protocol);
260         return 0;
261     }
262 }
263
264 static ALG_ID schan_get_cipher_algid(const struct cipher_suite* c)
265 {
266     TRACE("(%#x)\n", (unsigned int)c->suite);
267
268     switch (c->enc_alg)
269     {
270     case schan_enc_3DES_EDE_CBC:    return CALG_3DES;
271     case schan_enc_AES_128_CBC:     return CALG_AES_128;
272     case schan_enc_AES_256_CBC:     return CALG_AES_256;
273     case schan_enc_DES_CBC:         return CALG_DES;
274     case schan_enc_DES40_CBC:       return CALG_DES;
275     case schan_enc_NULL:            return 0;
276     case schan_enc_RC2_CBC_40:      return CALG_RC2;
277     case schan_enc_RC2_CBC:         return CALG_RC2;
278     case schan_enc_RC4_128:         return CALG_RC4;
279     case schan_enc_RC4_40:          return CALG_RC4;
280
281     case schan_enc_FORTEZZA_CBC:
282     case schan_enc_IDEA_CBC:
283         FIXME("Don't know CALG for encryption algorithm %d, returning 0\n", c->enc_alg);
284         return 0;
285
286     default:
287         FIXME("Unknown encryption algorithm %d for cipher suite %#x, returning 0\n", c->enc_alg, (unsigned int)c->suite);
288         return 0;
289     }
290 }
291
292 static unsigned int schan_get_cipher_key_size(const struct cipher_suite* c)
293 {
294     TRACE("(%#x)\n", (unsigned int)c->suite);
295
296     switch (c->enc_alg)
297     {
298     case schan_enc_3DES_EDE_CBC:    return 168;
299     case schan_enc_AES_128_CBC:     return 128;
300     case schan_enc_AES_256_CBC:     return 256;
301     case schan_enc_DES_CBC:         return 56;
302     case schan_enc_DES40_CBC:       return 40;
303     case schan_enc_NULL:            return 0;
304     case schan_enc_RC2_CBC_40:      return 40;
305     case schan_enc_RC2_CBC:         return 128;
306     case schan_enc_RC4_128:         return 128;
307     case schan_enc_RC4_40:          return 40;
308
309     case schan_enc_FORTEZZA_CBC:
310     case schan_enc_IDEA_CBC:
311         FIXME("Don't know key size for encryption algorithm %d, returning 0\n", c->enc_alg);
312         return 0;
313
314     default:
315         FIXME("Unknown encryption algorithm %d for cipher suite %#x, returning 0\n", c->enc_alg, (unsigned int)c->suite);
316         return 0;
317     }
318 }
319
320 static ALG_ID schan_get_mac_algid(const struct cipher_suite* c)
321 {
322     TRACE("(%#x)\n", (unsigned int)c->suite);
323
324     switch (c->mac_alg)
325     {
326     case schan_mac_MD5:     return CALG_MD5;
327     case schan_mac_NULL:    return 0;
328     case schan_mac_SHA:     return CALG_SHA;
329
330     default:
331         FIXME("Unknown hashing algorithm %d for cipher suite %#x, returning 0\n", c->mac_alg, (unsigned)c->suite);
332         return 0;
333     }
334 }
335
336 static unsigned int schan_get_mac_key_size(const struct cipher_suite* c)
337 {
338     TRACE("(%#x)\n", (unsigned int)c->suite);
339
340     switch (c->mac_alg)
341     {
342     case schan_mac_MD5:     return 128;
343     case schan_mac_NULL:    return 0;
344     case schan_mac_SHA:     return 160;
345
346     default:
347         FIXME("Unknown hashing algorithm %d for cipher suite %#x, returning 0\n", c->mac_alg, (unsigned)c->suite);
348         return 0;
349     }
350 }
351
352 static ALG_ID schan_get_kx_algid(const struct cipher_suite* c)
353 {
354     TRACE("(%#x)\n", (unsigned int)c->suite);
355
356     switch (c->kx_alg)
357     {
358     case schan_kx_DHE_DSS_EXPORT:
359     case schan_kx_DHE_DSS:
360     case schan_kx_DHE_RSA_EXPORT:
361     case schan_kx_DHE_RSA:          return CALG_DH_EPHEM;
362     case schan_kx_ECDH_anon:
363     case schan_kx_ECDH_ECDSA:
364     case schan_kx_ECDH_RSA:
365     case schan_kx_ECDHE_ECDSA:
366     case schan_kx_ECDHE_RSA:        return CALG_ECDH;
367     case schan_kx_NULL:             return 0;
368     case schan_kx_RSA:              return CALG_RSA_KEYX;
369
370     case schan_kx_DH_anon_EXPORT:
371     case schan_kx_DH_anon:
372     case schan_kx_DH_DSS_EXPORT:
373     case schan_kx_DH_DSS:
374     case schan_kx_DH_RSA_EXPORT:
375     case schan_kx_DH_RSA:
376     case schan_kx_FORTEZZA_DMS:
377     case schan_kx_RSA_EXPORT:
378         FIXME("Don't know CALG for key exchange algorithm %d for cipher suite %#x, returning 0\n", c->kx_alg, (unsigned)c->suite);
379         return 0;
380
381     default:
382         FIXME("Unknown key exchange algorithm %d for cipher suite %#x, returning 0\n", c->kx_alg, (unsigned)c->suite);
383         return 0;
384     }
385 }
386
387
388 /* schan_pull_adapter
389  *      Callback registered with SSLSetIOFuncs as the read function for a
390  *      session.  Reads data from the session connection.  Conforms to the
391  *      SSLReadFunc type.
392  *
393  *  transport - The session connection
394  *  buff - The buffer into which to store the read data.  Must be at least
395  *         *buff_len bytes in length.
396  *  *buff_len - On input, the desired length to read.  On successful return,
397  *              the number of bytes actually read.
398  *
399  *  Returns:
400  *      noErr on complete success meaning the requested length was successfully
401  *          read.
402  *      errSSLWouldBlock when the requested length could not be read without
403  *          blocking.  *buff_len indicates how much was actually read.  The
404  *          caller should try again if/when they want to read more.
405  *      errSSLClosedGraceful when the connection has closed and there's no
406  *          more data to be read.
407  *      other error code for failure.
408  */
409 static OSStatus schan_pull_adapter(SSLConnectionRef transport, void *buff,
410                                    SIZE_T *buff_len)
411 {
412     struct mac_session *s = (struct mac_session*)transport;
413     size_t requested = *buff_len;
414     int status;
415     OSStatus ret;
416
417     TRACE("(%p/%p, %p, %p/%lu)\n", s, s->transport, buff, buff_len, *buff_len);
418
419     status = schan_pull(s->transport, buff, buff_len);
420     if (status == 0)
421     {
422         if (*buff_len == 0)
423         {
424             TRACE("Connection closed\n");
425             ret = errSSLClosedGraceful;
426         }
427         else if (*buff_len < requested)
428         {
429             TRACE("Pulled %lu bytes before would block\n", *buff_len);
430             ret = errSSLWouldBlock;
431         }
432         else
433         {
434             TRACE("Pulled %lu bytes\n", *buff_len);
435             ret = noErr;
436         }
437     }
438     else if (status == EAGAIN)
439     {
440         TRACE("Would block before being able to pull anything\n");
441         ret = errSSLWouldBlock;
442     }
443     else
444     {
445         FIXME("Unknown status code from schan_pull: %d\n", status);
446         ret = ioErr;
447     }
448
449     return ret;
450 }
451
452 /* schan_push_adapter
453  *      Callback registered with SSLSetIOFuncs as the write function for a
454  *      session.  Writes data to the session connection.  Conforms to the
455  *      SSLWriteFunc type.
456  *
457  *  transport - The session connection
458  *  buff - The buffer of data to write.  Must be at least *buff_len bytes in length.
459  *  *buff_len - On input, the desired length to write.  On successful return,
460  *              the number of bytes actually written.
461  *
462  *  Returns:
463  *      noErr on complete or partial success; *buff_len indicates how much data
464  *          was actually written, which may be less than requrested.
465  *      errSSLWouldBlock when no data could be written without blocking.  The
466  *          caller should try again.
467  *      other error code for failure.
468  */
469 static OSStatus schan_push_adapter(SSLConnectionRef transport, const void *buff,
470                                        SIZE_T *buff_len)
471 {
472     struct mac_session *s = (struct mac_session*)transport;
473     int status;
474     OSStatus ret;
475
476     TRACE("(%p/%p, %p, %p/%lu)\n", s, s->transport, buff, buff_len, *buff_len);
477
478     status = schan_push(s->transport, buff, buff_len);
479     if (status == 0)
480     {
481         TRACE("Pushed %lu bytes\n", *buff_len);
482         ret = noErr;
483     }
484     else if (status == EAGAIN)
485     {
486         TRACE("Would block before being able to push anything\n");
487         ret = errSSLWouldBlock;
488     }
489     else
490     {
491         FIXME("Unknown status code from schan_push: %d\n", status);
492         ret = ioErr;
493     }
494
495     return ret;
496 }
497
498
499 BOOL schan_imp_create_session(schan_imp_session *session, BOOL is_server,
500                               schan_imp_certificate_credentials cred)
501 {
502     struct mac_session *s;
503     OSStatus status;
504
505     TRACE("(%p, %d)\n", session, is_server);
506
507     s = HeapAlloc(GetProcessHeap(), 0, sizeof(*s));
508     if (!s)
509         return FALSE;
510
511     status = SSLNewContext(is_server, &s->context);
512     if (status != noErr)
513     {
514         ERR("Failed to create session context: %ld\n", (long)status);
515         goto fail;
516     }
517
518     status = SSLSetConnection(s->context, s);
519     if (status != noErr)
520     {
521         ERR("Failed to set session connection: %ld\n", (long)status);
522         goto fail;
523     }
524
525     status = SSLSetEnableCertVerify(s->context, FALSE);
526     if (status != noErr)
527     {
528         ERR("Failed to disable certificate verification: %ld\n", (long)status);
529         goto fail;
530     }
531
532     status = SSLSetProtocolVersionEnabled(s->context, kSSLProtocol2, FALSE);
533     if (status != noErr)
534     {
535         ERR("Failed to disable SSL version 2: %ld\n", (long)status);
536         goto fail;
537     }
538
539     status = SSLSetIOFuncs(s->context, schan_pull_adapter, schan_push_adapter);
540     if (status != noErr)
541     {
542         ERR("Failed to set session I/O funcs: %ld\n", (long)status);
543         goto fail;
544     }
545
546     TRACE("    -> %p/%p\n", s, s->context);
547
548     *session = (schan_imp_session)s;
549     return TRUE;
550
551 fail:
552     HeapFree(GetProcessHeap(), 0, s);
553     return FALSE;
554 }
555
556 void schan_imp_dispose_session(schan_imp_session session)
557 {
558     struct mac_session *s = (struct mac_session*)session;
559     OSStatus status;
560
561     TRACE("(%p/%p)\n", s, s->context);
562
563     status = SSLDisposeContext(s->context);
564     if (status != noErr)
565         ERR("Failed to dispose of session context: %ld\n", status);
566     HeapFree(GetProcessHeap(), 0, s);
567 }
568
569 void schan_imp_set_session_transport(schan_imp_session session,
570                                      struct schan_transport *t)
571 {
572     struct mac_session *s = (struct mac_session*)session;
573
574     TRACE("(%p/%p, %p)\n", s, s->context, t);
575
576     s->transport = t;
577 }
578
579 SECURITY_STATUS schan_imp_handshake(schan_imp_session session)
580 {
581     struct mac_session *s = (struct mac_session*)session;
582     OSStatus status;
583
584     TRACE("(%p/%p)\n", s, s->context);
585
586     status = SSLHandshake(s->context);
587     if (status == noErr)
588     {
589         TRACE("Handshake completed\n");
590         return SEC_E_OK;
591     }
592     else if (status == errSSLWouldBlock)
593     {
594         TRACE("Continue...\n");
595         return SEC_I_CONTINUE_NEEDED;
596     }
597     else if (errSecErrnoBase <= status && status <= errSecErrnoLimit)
598     {
599         ERR("Handshake failed: %s\n", strerror(status));
600         return SEC_E_INTERNAL_ERROR;
601     }
602     else
603     {
604         ERR("Handshake failed: %ld\n", (long)status);
605         cssmPerror("SSLHandshake", status);
606         return SEC_E_INTERNAL_ERROR;
607     }
608
609     /* Never reached */
610     return SEC_E_OK;
611 }
612
613 unsigned int schan_imp_get_session_cipher_block_size(schan_imp_session session)
614 {
615     struct mac_session* s = (struct mac_session*)session;
616     SSLCipherSuite cipherSuite;
617     const struct cipher_suite* c;
618     OSStatus status;
619
620     TRACE("(%p/%p)\n", s, s->context);
621
622     status = SSLGetNegotiatedCipher(s->context, &cipherSuite);
623     if (status != noErr)
624     {
625         ERR("Failed to get session cipher suite: %ld\n", status);
626         return 0;
627     }
628
629     c = get_cipher_suite(cipherSuite);
630     if (!c)
631     {
632         ERR("Unknown session cipher suite: %#x\n", (unsigned int)cipherSuite);
633         return 0;
634     }
635
636     switch (c->enc_alg)
637     {
638     case schan_enc_3DES_EDE_CBC:    return 64;
639     case schan_enc_AES_128_CBC:     return 128;
640     case schan_enc_AES_256_CBC:     return 128;
641     case schan_enc_DES_CBC:         return 64;
642     case schan_enc_DES40_CBC:       return 64;
643     case schan_enc_NULL:            return 0;
644     case schan_enc_RC2_CBC_40:      return 64;
645     case schan_enc_RC2_CBC:         return 64;
646     case schan_enc_RC4_128:         return 0;
647     case schan_enc_RC4_40:          return 0;
648
649     case schan_enc_FORTEZZA_CBC:
650     case schan_enc_IDEA_CBC:
651         FIXME("Don't know block size for encryption algorithm %d, returning 0\n", c->enc_alg);
652         return 0;
653
654     default:
655         FIXME("Unknown encryption algorithm %d for cipher suite %#x, returning 0\n", c->enc_alg, (unsigned int)c->suite);
656         return 0;
657     }
658 }
659
660 unsigned int schan_imp_get_max_message_size(schan_imp_session session)
661 {
662     FIXME("Returning 1 << 14.\n");
663     return 1 << 14;
664 }
665
666 SECURITY_STATUS schan_imp_get_connection_info(schan_imp_session session,
667                                               SecPkgContext_ConnectionInfo *info)
668 {
669     struct mac_session* s = (struct mac_session*)session;
670     SSLCipherSuite cipherSuite;
671     const struct cipher_suite* c;
672     OSStatus status;
673
674     TRACE("(%p/%p, %p)\n", s, s->context, info);
675
676     status = SSLGetNegotiatedCipher(s->context, &cipherSuite);
677     if (status != noErr)
678     {
679         ERR("Failed to get session cipher suite: %ld\n", status);
680         return SEC_E_INTERNAL_ERROR;
681     }
682
683     c = get_cipher_suite(cipherSuite);
684     if (!c)
685     {
686         ERR("Unknown session cipher suite: %#x\n", (unsigned int)cipherSuite);
687         return SEC_E_INTERNAL_ERROR;
688     }
689
690     info->dwProtocol = schan_get_session_protocol(s);
691     info->aiCipher = schan_get_cipher_algid(c);
692     info->dwCipherStrength = schan_get_cipher_key_size(c);
693     info->aiHash = schan_get_mac_algid(c);
694     info->dwHashStrength = schan_get_mac_key_size(c);
695     info->aiExch = schan_get_kx_algid(c);
696     /* FIXME: info->dwExchStrength? */
697     info->dwExchStrength = 0;
698
699     return SEC_E_OK;
700 }
701
702 #ifndef HAVE_SSLCOPYPEERCERTIFICATES
703 static void schan_imp_cf_release(const void *arg, void *ctx)
704 {
705     CFRelease(arg);
706 }
707 #endif
708
709 SECURITY_STATUS schan_imp_get_session_peer_certificate(schan_imp_session session,
710                                                        PCCERT_CONTEXT *cert)
711 {
712     struct mac_session* s = (struct mac_session*)session;
713     SECURITY_STATUS ret = SEC_E_INTERNAL_ERROR;
714     CFArrayRef certs;
715     OSStatus status;
716
717     TRACE("(%p/%p, %p)\n", s, s->context, cert);
718
719 #ifdef HAVE_SSLCOPYPEERCERTIFICATES
720     status = SSLCopyPeerCertificates(s->context, &certs);
721 #else
722     status = SSLGetPeerCertificates(s->context, &certs);
723 #endif
724     if (status == noErr && certs)
725     {
726         SecCertificateRef mac_cert;
727         CFDataRef data;
728         if (CFArrayGetCount(certs) &&
729             (mac_cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, 0)) &&
730             (SecKeychainItemExport(mac_cert, kSecFormatX509Cert, 0, NULL, &data) == noErr))
731         {
732             *cert = CertCreateCertificateContext(X509_ASN_ENCODING,
733                     CFDataGetBytePtr(data), CFDataGetLength(data));
734             if (*cert)
735                 ret = SEC_E_OK;
736             else
737             {
738                 ret = GetLastError();
739                 WARN("CertCreateCertificateContext failed: %x\n", ret);
740             }
741             CFRelease(data);
742         }
743         else
744             WARN("Couldn't extract certificate data\n");
745 #ifndef HAVE_SSLCOPYPEERCERTIFICATES
746         /* This is why SSLGetPeerCertificates was deprecated */
747         CFArrayApplyFunction(certs, CFRangeMake(0, CFArrayGetCount(certs)),
748                              schan_imp_cf_release, NULL);
749 #endif
750         CFRelease(certs);
751     }
752     else
753         WARN("SSLCopyPeerCertificates failed: %ld\n", (long)status);
754
755     return ret;
756 }
757
758 SECURITY_STATUS schan_imp_send(schan_imp_session session, const void *buffer,
759                                SIZE_T *length)
760 {
761     struct mac_session* s = (struct mac_session*)session;
762     OSStatus status;
763
764     TRACE("(%p/%p, %p, %p/%lu)\n", s, s->context, buffer, length, *length);
765
766     status = SSLWrite(s->context, buffer, *length, length);
767     if (status == noErr)
768         TRACE("Wrote %lu bytes\n", *length);
769     else if (status == errSSLWouldBlock)
770     {
771         if (!*length)
772         {
773             TRACE("Would block before being able to write anything\n");
774             return SEC_I_CONTINUE_NEEDED;
775         }
776         else
777             TRACE("Wrote %lu bytes before would block\n", *length);
778     }
779     else
780     {
781         WARN("SSLWrite failed: %ld\n", (long)status);
782         return SEC_E_INTERNAL_ERROR;
783     }
784
785     return SEC_E_OK;
786 }
787
788 SECURITY_STATUS schan_imp_recv(schan_imp_session session, void *buffer,
789                                SIZE_T *length)
790 {
791     struct mac_session* s = (struct mac_session*)session;
792     OSStatus status;
793
794     TRACE("(%p/%p, %p, %p/%lu)\n", s, s->context, buffer, length, *length);
795
796     status = SSLRead(s->context, buffer, *length, length);
797     if (status == noErr)
798         TRACE("Read %lu bytes\n", *length);
799     else if (status == errSSLWouldBlock)
800     {
801         if (!*length)
802         {
803             TRACE("Would block before being able to read anything\n");
804             return SEC_I_CONTINUE_NEEDED;
805         }
806         else
807             TRACE("Read %lu bytes before would block\n", *length);
808     }
809     else
810     {
811         WARN("SSLRead failed: %ld\n", (long)status);
812         return SEC_E_INTERNAL_ERROR;
813     }
814
815     return SEC_E_OK;
816 }
817
818 BOOL schan_imp_allocate_certificate_credentials(schan_imp_certificate_credentials *c)
819 {
820     /* The certificate is never really used for anything. */
821     *c = NULL;
822     return TRUE;
823 }
824
825 void schan_imp_free_certificate_credentials(schan_imp_certificate_credentials c)
826 {
827 }
828
829 BOOL schan_imp_init(void)
830 {
831     TRACE("()\n");
832     return TRUE;
833 }
834
835 void schan_imp_deinit(void)
836 {
837     TRACE("()\n");
838 }
839
840 #endif /* HAVE_SECURITY_SECURITY_H */