winex11: Create contexts at initialization time to avoid the need for locks.
[wine/multimedia.git] / dlls / secur32 / schannel_macosx.c
blob75fe9a011102a3fbfa68c845c77a33c6f6d043fc
1 /*
2 * Mac OS X Secure Transport implementation of the schannel (SSL/TLS) provider.
4 * Copyright 2005 Juan Lang
5 * Copyright 2008 Henri Verbeet
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.
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.
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
22 #include "config.h"
23 #include "wine/port.h"
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
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"
44 WINE_DEFAULT_DEBUG_CHANNEL(secur32);
46 #ifdef HAVE_SECURITY_SECURITY_H
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,
77 #endif
79 struct mac_session {
80 SSLContextRef context;
81 struct schan_transport *transport;
85 enum {
86 schan_proto_SSL,
87 schan_proto_TLS,
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,
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,
127 enum {
128 schan_mac_MD5,
129 schan_mac_NULL,
130 schan_mac_SHA,
134 struct cipher_suite {
135 SSLCipherSuite suite;
136 int protocol;
137 int kx_alg;
138 int enc_alg;
139 int mac_alg;
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),
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),
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),
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
224 static const struct cipher_suite* get_cipher_suite(SSLCipherSuite cipher_suite)
226 int i;
227 for (i = 0; i < sizeof(cipher_suites)/sizeof(cipher_suites[0]); i++)
229 if (cipher_suites[i].suite == cipher_suite)
230 return &cipher_suites[i];
233 return NULL;
237 static DWORD schan_get_session_protocol(struct mac_session* s)
239 SSLProtocol protocol;
240 OSStatus status;
242 TRACE("(%p/%p)\n", s, s->context);
244 status = SSLGetNegotiatedProtocolVersion(s->context, &protocol);
245 if (status != noErr)
247 ERR("Failed to get session protocol: %ld\n", status);
248 return 0;
251 TRACE("protocol %d\n", protocol);
253 switch (protocol)
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;
264 static ALG_ID schan_get_cipher_algid(const struct cipher_suite* c)
266 TRACE("(%#x)\n", (unsigned int)c->suite);
268 switch (c->enc_alg)
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;
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;
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;
292 static unsigned int schan_get_cipher_key_size(const struct cipher_suite* c)
294 TRACE("(%#x)\n", (unsigned int)c->suite);
296 switch (c->enc_alg)
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;
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;
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;
320 static ALG_ID schan_get_mac_algid(const struct cipher_suite* c)
322 TRACE("(%#x)\n", (unsigned int)c->suite);
324 switch (c->mac_alg)
326 case schan_mac_MD5: return CALG_MD5;
327 case schan_mac_NULL: return 0;
328 case schan_mac_SHA: return CALG_SHA;
330 default:
331 FIXME("Unknown hashing algorithm %d for cipher suite %#x, returning 0\n", c->mac_alg, (unsigned)c->suite);
332 return 0;
336 static unsigned int schan_get_mac_key_size(const struct cipher_suite* c)
338 TRACE("(%#x)\n", (unsigned int)c->suite);
340 switch (c->mac_alg)
342 case schan_mac_MD5: return 128;
343 case schan_mac_NULL: return 0;
344 case schan_mac_SHA: return 160;
346 default:
347 FIXME("Unknown hashing algorithm %d for cipher suite %#x, returning 0\n", c->mac_alg, (unsigned)c->suite);
348 return 0;
352 static ALG_ID schan_get_kx_algid(const struct cipher_suite* c)
354 TRACE("(%#x)\n", (unsigned int)c->suite);
356 switch (c->kx_alg)
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;
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;
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;
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.
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.
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.
409 static OSStatus schan_pull_adapter(SSLConnectionRef transport, void *buff,
410 SIZE_T *buff_len)
412 struct mac_session *s = (struct mac_session*)transport;
413 size_t requested = *buff_len;
414 int status;
415 OSStatus ret;
417 TRACE("(%p/%p, %p, %p/%lu)\n", s, s->transport, buff, buff_len, *buff_len);
419 status = schan_pull(s->transport, buff, buff_len);
420 if (status == 0)
422 if (*buff_len == 0)
424 TRACE("Connection closed\n");
425 ret = errSSLClosedGraceful;
427 else if (*buff_len < requested)
429 TRACE("Pulled %lu bytes before would block\n", *buff_len);
430 ret = errSSLWouldBlock;
432 else
434 TRACE("Pulled %lu bytes\n", *buff_len);
435 ret = noErr;
438 else if (status == EAGAIN)
440 TRACE("Would block before being able to pull anything\n");
441 ret = errSSLWouldBlock;
443 else
445 FIXME("Unknown status code from schan_pull: %d\n", status);
446 ret = ioErr;
449 return ret;
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.
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.
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.
469 static OSStatus schan_push_adapter(SSLConnectionRef transport, const void *buff,
470 SIZE_T *buff_len)
472 struct mac_session *s = (struct mac_session*)transport;
473 int status;
474 OSStatus ret;
476 TRACE("(%p/%p, %p, %p/%lu)\n", s, s->transport, buff, buff_len, *buff_len);
478 status = schan_push(s->transport, buff, buff_len);
479 if (status == 0)
481 TRACE("Pushed %lu bytes\n", *buff_len);
482 ret = noErr;
484 else if (status == EAGAIN)
486 TRACE("Would block before being able to push anything\n");
487 ret = errSSLWouldBlock;
489 else
491 FIXME("Unknown status code from schan_push: %d\n", status);
492 ret = ioErr;
495 return ret;
499 BOOL schan_imp_create_session(schan_imp_session *session, BOOL is_server,
500 schan_imp_certificate_credentials cred)
502 struct mac_session *s;
503 OSStatus status;
505 TRACE("(%p, %d)\n", session, is_server);
507 s = HeapAlloc(GetProcessHeap(), 0, sizeof(*s));
508 if (!s)
509 return FALSE;
511 status = SSLNewContext(is_server, &s->context);
512 if (status != noErr)
514 ERR("Failed to create session context: %ld\n", (long)status);
515 goto fail;
518 status = SSLSetConnection(s->context, s);
519 if (status != noErr)
521 ERR("Failed to set session connection: %ld\n", (long)status);
522 goto fail;
525 status = SSLSetEnableCertVerify(s->context, FALSE);
526 if (status != noErr)
528 ERR("Failed to disable certificate verification: %ld\n", (long)status);
529 goto fail;
532 status = SSLSetProtocolVersionEnabled(s->context, kSSLProtocol2, FALSE);
533 if (status != noErr)
535 ERR("Failed to disable SSL version 2: %ld\n", (long)status);
536 goto fail;
539 status = SSLSetIOFuncs(s->context, schan_pull_adapter, schan_push_adapter);
540 if (status != noErr)
542 ERR("Failed to set session I/O funcs: %ld\n", (long)status);
543 goto fail;
546 TRACE(" -> %p/%p\n", s, s->context);
548 *session = (schan_imp_session)s;
549 return TRUE;
551 fail:
552 HeapFree(GetProcessHeap(), 0, s);
553 return FALSE;
556 void schan_imp_dispose_session(schan_imp_session session)
558 struct mac_session *s = (struct mac_session*)session;
559 OSStatus status;
561 TRACE("(%p/%p)\n", s, s->context);
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);
569 void schan_imp_set_session_transport(schan_imp_session session,
570 struct schan_transport *t)
572 struct mac_session *s = (struct mac_session*)session;
574 TRACE("(%p/%p, %p)\n", s, s->context, t);
576 s->transport = t;
579 SECURITY_STATUS schan_imp_handshake(schan_imp_session session)
581 struct mac_session *s = (struct mac_session*)session;
582 OSStatus status;
584 TRACE("(%p/%p)\n", s, s->context);
586 status = SSLHandshake(s->context);
587 if (status == noErr)
589 TRACE("Handshake completed\n");
590 return SEC_E_OK;
592 else if (status == errSSLWouldBlock)
594 TRACE("Continue...\n");
595 return SEC_I_CONTINUE_NEEDED;
597 else if (errSecErrnoBase <= status && status <= errSecErrnoLimit)
599 ERR("Handshake failed: %s\n", strerror(status));
600 return SEC_E_INTERNAL_ERROR;
602 else
604 ERR("Handshake failed: %ld\n", (long)status);
605 cssmPerror("SSLHandshake", status);
606 return SEC_E_INTERNAL_ERROR;
609 /* Never reached */
610 return SEC_E_OK;
613 unsigned int schan_imp_get_session_cipher_block_size(schan_imp_session session)
615 struct mac_session* s = (struct mac_session*)session;
616 SSLCipherSuite cipherSuite;
617 const struct cipher_suite* c;
618 OSStatus status;
620 TRACE("(%p/%p)\n", s, s->context);
622 status = SSLGetNegotiatedCipher(s->context, &cipherSuite);
623 if (status != noErr)
625 ERR("Failed to get session cipher suite: %ld\n", status);
626 return 0;
629 c = get_cipher_suite(cipherSuite);
630 if (!c)
632 ERR("Unknown session cipher suite: %#x\n", (unsigned int)cipherSuite);
633 return 0;
636 switch (c->enc_alg)
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;
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;
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;
660 unsigned int schan_imp_get_max_message_size(schan_imp_session session)
662 FIXME("Returning 1 << 14.\n");
663 return 1 << 14;
666 SECURITY_STATUS schan_imp_get_connection_info(schan_imp_session session,
667 SecPkgContext_ConnectionInfo *info)
669 struct mac_session* s = (struct mac_session*)session;
670 SSLCipherSuite cipherSuite;
671 const struct cipher_suite* c;
672 OSStatus status;
674 TRACE("(%p/%p, %p)\n", s, s->context, info);
676 status = SSLGetNegotiatedCipher(s->context, &cipherSuite);
677 if (status != noErr)
679 ERR("Failed to get session cipher suite: %ld\n", status);
680 return SEC_E_INTERNAL_ERROR;
683 c = get_cipher_suite(cipherSuite);
684 if (!c)
686 ERR("Unknown session cipher suite: %#x\n", (unsigned int)cipherSuite);
687 return SEC_E_INTERNAL_ERROR;
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;
699 return SEC_E_OK;
702 #ifndef HAVE_SSLCOPYPEERCERTIFICATES
703 static void schan_imp_cf_release(const void *arg, void *ctx)
705 CFRelease(arg);
707 #endif
709 SECURITY_STATUS schan_imp_get_session_peer_certificate(schan_imp_session session,
710 PCCERT_CONTEXT *cert)
712 struct mac_session* s = (struct mac_session*)session;
713 SECURITY_STATUS ret = SEC_E_INTERNAL_ERROR;
714 CFArrayRef certs;
715 OSStatus status;
717 TRACE("(%p/%p, %p)\n", s, s->context, cert);
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)
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))
732 *cert = CertCreateCertificateContext(X509_ASN_ENCODING,
733 CFDataGetBytePtr(data), CFDataGetLength(data));
734 if (*cert)
735 ret = SEC_E_OK;
736 else
738 ret = GetLastError();
739 WARN("CertCreateCertificateContext failed: %x\n", ret);
741 CFRelease(data);
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);
752 else
753 WARN("SSLCopyPeerCertificates failed: %ld\n", (long)status);
755 return ret;
758 SECURITY_STATUS schan_imp_send(schan_imp_session session, const void *buffer,
759 SIZE_T *length)
761 struct mac_session* s = (struct mac_session*)session;
762 OSStatus status;
764 TRACE("(%p/%p, %p, %p/%lu)\n", s, s->context, buffer, length, *length);
766 status = SSLWrite(s->context, buffer, *length, length);
767 if (status == noErr)
768 TRACE("Wrote %lu bytes\n", *length);
769 else if (status == errSSLWouldBlock)
771 if (!*length)
773 TRACE("Would block before being able to write anything\n");
774 return SEC_I_CONTINUE_NEEDED;
776 else
777 TRACE("Wrote %lu bytes before would block\n", *length);
779 else
781 WARN("SSLWrite failed: %ld\n", (long)status);
782 return SEC_E_INTERNAL_ERROR;
785 return SEC_E_OK;
788 SECURITY_STATUS schan_imp_recv(schan_imp_session session, void *buffer,
789 SIZE_T *length)
791 struct mac_session* s = (struct mac_session*)session;
792 OSStatus status;
794 TRACE("(%p/%p, %p, %p/%lu)\n", s, s->context, buffer, length, *length);
796 status = SSLRead(s->context, buffer, *length, length);
797 if (status == noErr)
798 TRACE("Read %lu bytes\n", *length);
799 else if (status == errSSLWouldBlock)
801 if (!*length)
803 TRACE("Would block before being able to read anything\n");
804 return SEC_I_CONTINUE_NEEDED;
806 else
807 TRACE("Read %lu bytes before would block\n", *length);
809 else
811 WARN("SSLRead failed: %ld\n", (long)status);
812 return SEC_E_INTERNAL_ERROR;
815 return SEC_E_OK;
818 BOOL schan_imp_allocate_certificate_credentials(schan_imp_certificate_credentials *c)
820 /* The certificate is never really used for anything. */
821 *c = NULL;
822 return TRUE;
825 void schan_imp_free_certificate_credentials(schan_imp_certificate_credentials c)
829 BOOL schan_imp_init(void)
831 TRACE("()\n");
832 return TRUE;
835 void schan_imp_deinit(void)
837 TRACE("()\n");
840 #endif /* HAVE_SECURITY_SECURITY_H */