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