winemenubuilder: silence an err
[wine/multimedia.git] / dlls / secur32 / schannel_macosx.c
blob01493b1984ba28e05fe28530a6f4e40b8da49e71
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 struct mac_session {
49 SSLContextRef context;
50 struct schan_transport *transport;
54 enum {
55 schan_proto_SSL,
56 schan_proto_TLS,
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,
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,
96 enum {
97 schan_mac_MD5,
98 schan_mac_NULL,
99 schan_mac_SHA,
103 struct cipher_suite {
104 SSLCipherSuite suite;
105 int protocol;
106 int kx_alg;
107 int enc_alg;
108 int mac_alg;
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),
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),
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
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
195 static const struct cipher_suite* get_cipher_suite(SSLCipherSuite cipher_suite)
197 int i;
198 for (i = 0; i < sizeof(cipher_suites)/sizeof(cipher_suites[0]); i++)
200 if (cipher_suites[i].suite == cipher_suite)
201 return &cipher_suites[i];
204 return NULL;
208 static DWORD schan_get_session_protocol(struct mac_session* s)
210 SSLProtocol protocol;
211 OSStatus status;
213 TRACE("(%p/%p)\n", s, s->context);
215 status = SSLGetNegotiatedProtocolVersion(s->context, &protocol);
216 if (status != noErr)
218 ERR("Failed to get session protocol: %ld\n", status);
219 return 0;
222 TRACE("protocol %d\n", protocol);
224 switch (protocol)
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;
235 static ALG_ID schan_get_cipher_algid(const struct cipher_suite* c)
237 TRACE("(%#x)\n", (unsigned int)c->suite);
239 switch (c->enc_alg)
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;
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;
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;
263 static unsigned int schan_get_cipher_key_size(const struct cipher_suite* c)
265 TRACE("(%#x)\n", (unsigned int)c->suite);
267 switch (c->enc_alg)
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;
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;
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;
291 static ALG_ID schan_get_mac_algid(const struct cipher_suite* c)
293 TRACE("(%#x)\n", (unsigned int)c->suite);
295 switch (c->mac_alg)
297 case schan_mac_MD5: return CALG_MD5;
298 case schan_mac_NULL: return 0;
299 case schan_mac_SHA: return CALG_SHA;
301 default:
302 FIXME("Unknown hashing algorithm %d for cipher suite %#x, returning 0\n", c->mac_alg, (unsigned)c->suite);
303 return 0;
307 static unsigned int schan_get_mac_key_size(const struct cipher_suite* c)
309 TRACE("(%#x)\n", (unsigned int)c->suite);
311 switch (c->mac_alg)
313 case schan_mac_MD5: return 128;
314 case schan_mac_NULL: return 0;
315 case schan_mac_SHA: return 160;
317 default:
318 FIXME("Unknown hashing algorithm %d for cipher suite %#x, returning 0\n", c->mac_alg, (unsigned)c->suite);
319 return 0;
323 static ALG_ID schan_get_kx_algid(const struct cipher_suite* c)
325 TRACE("(%#x)\n", (unsigned int)c->suite);
327 switch (c->kx_alg)
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;
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;
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;
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.
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.
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.
380 static OSStatus schan_pull_adapter(SSLConnectionRef transport, void *buff,
381 SIZE_T *buff_len)
383 struct mac_session *s = (struct mac_session*)transport;
384 size_t requested = *buff_len;
385 int status;
386 OSStatus ret;
388 TRACE("(%p/%p, %p, %p/%lu)\n", s, s->transport, buff, buff_len, *buff_len);
390 status = schan_pull(s->transport, buff, buff_len);
391 if (status == 0)
393 if (*buff_len == 0)
395 TRACE("Connection closed\n");
396 ret = errSSLClosedGraceful;
398 else if (*buff_len < requested)
400 TRACE("Pulled %lu bytes before would block\n", *buff_len);
401 ret = errSSLWouldBlock;
403 else
405 TRACE("Pulled %lu bytes\n", *buff_len);
406 ret = noErr;
409 else if (status == EAGAIN)
411 TRACE("Would block before being able to pull anything\n");
412 ret = errSSLWouldBlock;
414 else
416 FIXME("Unknown status code from schan_pull: %d\n", status);
417 ret = ioErr;
420 return ret;
423 /* schan_push_adapter
424 * Callback registered with SSLSetIOFuncs as the write function for a
425 * session. Writes data to the session connection. Conforms to the
426 * SSLWriteFunc type.
428 * transport - The session connection
429 * buff - The buffer of data to write. Must be at least *buff_len bytes in length.
430 * *buff_len - On input, the desired length to write. On successful return,
431 * the number of bytes actually written.
433 * Returns:
434 * noErr on complete or partial success; *buff_len indicates how much data
435 * was actually written, which may be less than requrested.
436 * errSSLWouldBlock when no data could be written without blocking. The
437 * caller should try again.
438 * other error code for failure.
440 static OSStatus schan_push_adapter(SSLConnectionRef transport, const void *buff,
441 SIZE_T *buff_len)
443 struct mac_session *s = (struct mac_session*)transport;
444 int status;
445 OSStatus ret;
447 TRACE("(%p/%p, %p, %p/%lu)\n", s, s->transport, buff, buff_len, *buff_len);
449 status = schan_push(s->transport, buff, buff_len);
450 if (status == 0)
452 TRACE("Pushed %lu bytes\n", *buff_len);
453 ret = noErr;
455 else if (status == EAGAIN)
457 TRACE("Would block before being able to push anything\n");
458 ret = errSSLWouldBlock;
460 else
462 FIXME("Unknown status code from schan_push: %d\n", status);
463 ret = ioErr;
466 return ret;
470 BOOL schan_imp_create_session(schan_imp_session *session, BOOL is_server,
471 schan_imp_certificate_credentials cred)
473 struct mac_session *s;
474 OSStatus status;
476 TRACE("(%p, %d)\n", session, is_server);
478 s = HeapAlloc(GetProcessHeap(), 0, sizeof(*s));
479 if (!s)
480 return FALSE;
482 status = SSLNewContext(is_server, &s->context);
483 if (status != noErr)
485 ERR("Failed to create session context: %ld\n", (long)status);
486 goto fail;
489 status = SSLSetConnection(s->context, s);
490 if (status != noErr)
492 ERR("Failed to set session connection: %ld\n", (long)status);
493 goto fail;
496 status = SSLSetEnableCertVerify(s->context, FALSE);
497 if (status != noErr)
499 ERR("Failed to disable certificate verification: %ld\n", (long)status);
500 goto fail;
503 status = SSLSetProtocolVersionEnabled(s->context, kSSLProtocol2, FALSE);
504 if (status != noErr)
506 ERR("Failed to disable SSL version 2: %ld\n", (long)status);
507 goto fail;
510 status = SSLSetIOFuncs(s->context, schan_pull_adapter, schan_push_adapter);
511 if (status != noErr)
513 ERR("Failed to set session I/O funcs: %ld\n", (long)status);
514 goto fail;
517 TRACE(" -> %p/%p\n", s, s->context);
519 *session = (schan_imp_session)s;
520 return TRUE;
522 fail:
523 HeapFree(GetProcessHeap(), 0, s);
524 return FALSE;
527 void schan_imp_dispose_session(schan_imp_session session)
529 struct mac_session *s = (struct mac_session*)session;
530 OSStatus status;
532 TRACE("(%p/%p)\n", s, s->context);
534 status = SSLDisposeContext(s->context);
535 if (status != noErr)
536 ERR("Failed to dispose of session context: %ld\n", status);
537 HeapFree(GetProcessHeap(), 0, s);
540 void schan_imp_set_session_transport(schan_imp_session session,
541 struct schan_transport *t)
543 struct mac_session *s = (struct mac_session*)session;
545 TRACE("(%p/%p, %p)\n", s, s->context, t);
547 s->transport = t;
550 SECURITY_STATUS schan_imp_handshake(schan_imp_session session)
552 struct mac_session *s = (struct mac_session*)session;
553 OSStatus status;
555 TRACE("(%p/%p)\n", s, s->context);
557 status = SSLHandshake(s->context);
558 if (status == noErr)
560 TRACE("Handshake completed\n");
561 return SEC_E_OK;
563 else if (status == errSSLWouldBlock)
565 TRACE("Continue...\n");
566 return SEC_I_CONTINUE_NEEDED;
568 else if (errSecErrnoBase <= status && status <= errSecErrnoLimit)
570 ERR("Handshake failed: %s\n", strerror(status));
571 return SEC_E_INTERNAL_ERROR;
573 else
575 ERR("Handshake failed: %ld\n", (long)status);
576 cssmPerror("SSLHandshake", status);
577 return SEC_E_INTERNAL_ERROR;
580 /* Never reached */
581 return SEC_E_OK;
584 unsigned int schan_imp_get_session_cipher_block_size(schan_imp_session session)
586 struct mac_session* s = (struct mac_session*)session;
587 SSLCipherSuite cipherSuite;
588 const struct cipher_suite* c;
589 OSStatus status;
591 TRACE("(%p/%p)\n", s, s->context);
593 status = SSLGetNegotiatedCipher(s->context, &cipherSuite);
594 if (status != noErr)
596 ERR("Failed to get session cipher suite: %ld\n", status);
597 return 0;
600 c = get_cipher_suite(cipherSuite);
601 if (!c)
603 ERR("Unknown session cipher suite: %#x\n", (unsigned int)cipherSuite);
604 return 0;
607 switch (c->enc_alg)
609 case schan_enc_3DES_EDE_CBC: return 64;
610 case schan_enc_AES_128_CBC: return 128;
611 case schan_enc_AES_256_CBC: return 128;
612 case schan_enc_DES_CBC: return 64;
613 case schan_enc_DES40_CBC: return 64;
614 case schan_enc_NULL: return 0;
615 case schan_enc_RC2_CBC_40: return 64;
616 case schan_enc_RC2_CBC: return 64;
617 case schan_enc_RC4_128: return 0;
618 case schan_enc_RC4_40: return 0;
620 case schan_enc_FORTEZZA_CBC:
621 case schan_enc_IDEA_CBC:
622 FIXME("Don't know block size for encryption algorithm %d, returning 0\n", c->enc_alg);
623 return 0;
625 default:
626 FIXME("Unknown encryption algorithm %d for cipher suite %#x, returning 0\n", c->enc_alg, (unsigned int)c->suite);
627 return 0;
631 unsigned int schan_imp_get_max_message_size(schan_imp_session session)
633 FIXME("Returning 1 << 14.\n");
634 return 1 << 14;
637 SECURITY_STATUS schan_imp_get_connection_info(schan_imp_session session,
638 SecPkgContext_ConnectionInfo *info)
640 struct mac_session* s = (struct mac_session*)session;
641 SSLCipherSuite cipherSuite;
642 const struct cipher_suite* c;
643 OSStatus status;
645 TRACE("(%p/%p, %p)\n", s, s->context, info);
647 status = SSLGetNegotiatedCipher(s->context, &cipherSuite);
648 if (status != noErr)
650 ERR("Failed to get session cipher suite: %ld\n", status);
651 return SEC_E_INTERNAL_ERROR;
654 c = get_cipher_suite(cipherSuite);
655 if (!c)
657 ERR("Unknown session cipher suite: %#x\n", (unsigned int)cipherSuite);
658 return SEC_E_INTERNAL_ERROR;
661 info->dwProtocol = schan_get_session_protocol(s);
662 info->aiCipher = schan_get_cipher_algid(c);
663 info->dwCipherStrength = schan_get_cipher_key_size(c);
664 info->aiHash = schan_get_mac_algid(c);
665 info->dwHashStrength = schan_get_mac_key_size(c);
666 info->aiExch = schan_get_kx_algid(c);
667 /* FIXME: info->dwExchStrength? */
668 info->dwExchStrength = 0;
670 return SEC_E_OK;
673 #ifndef HAVE_SSLCOPYPEERCERTIFICATES
674 static void schan_imp_cf_release(const void *arg, void *ctx)
676 CFRelease(arg);
678 #endif
680 SECURITY_STATUS schan_imp_get_session_peer_certificate(schan_imp_session session,
681 PCCERT_CONTEXT *cert)
683 struct mac_session* s = (struct mac_session*)session;
684 SECURITY_STATUS ret = SEC_E_INTERNAL_ERROR;
685 CFArrayRef certs;
686 OSStatus status;
688 TRACE("(%p/%p, %p)\n", s, s->context, cert);
690 #ifdef HAVE_SSLCOPYPEERCERTIFICATES
691 status = SSLCopyPeerCertificates(s->context, &certs);
692 #else
693 status = SSLGetPeerCertificates(s->context, &certs);
694 #endif
695 if (status == noErr && certs)
697 SecCertificateRef mac_cert;
698 CFDataRef data;
699 if (CFArrayGetCount(certs) &&
700 (mac_cert = (SecCertificateRef)CFArrayGetValueAtIndex(certs, 0)) &&
701 (SecKeychainItemExport(mac_cert, kSecFormatX509Cert, 0, NULL, &data) == noErr))
703 *cert = CertCreateCertificateContext(X509_ASN_ENCODING,
704 CFDataGetBytePtr(data), CFDataGetLength(data));
705 if (*cert)
706 ret = SEC_E_OK;
707 else
709 ret = GetLastError();
710 WARN("CertCreateCertificateContext failed: %x\n", ret);
712 CFRelease(data);
714 else
715 WARN("Couldn't extract certificate data\n");
716 #ifndef HAVE_SSLCOPYPEERCERTIFICATES
717 /* This is why SSLGetPeerCertificates was deprecated */
718 CFArrayApplyFunction(certs, CFRangeMake(0, CFArrayGetCount(certs)),
719 schan_imp_cf_release, NULL);
720 #endif
721 CFRelease(certs);
723 else
724 WARN("SSLCopyPeerCertificates failed: %ld\n", (long)status);
726 return ret;
729 SECURITY_STATUS schan_imp_send(schan_imp_session session, const void *buffer,
730 SIZE_T *length)
732 struct mac_session* s = (struct mac_session*)session;
733 OSStatus status;
735 TRACE("(%p/%p, %p, %p/%lu)\n", s, s->context, buffer, length, *length);
737 status = SSLWrite(s->context, buffer, *length, length);
738 if (status == noErr)
739 TRACE("Wrote %lu bytes\n", *length);
740 else if (status == errSSLWouldBlock)
742 if (!*length)
744 TRACE("Would block before being able to write anything\n");
745 return SEC_I_CONTINUE_NEEDED;
747 else
748 TRACE("Wrote %lu bytes before would block\n", *length);
750 else
752 WARN("SSLWrite failed: %ld\n", (long)status);
753 return SEC_E_INTERNAL_ERROR;
756 return SEC_E_OK;
759 SECURITY_STATUS schan_imp_recv(schan_imp_session session, void *buffer,
760 SIZE_T *length)
762 struct mac_session* s = (struct mac_session*)session;
763 OSStatus status;
765 TRACE("(%p/%p, %p, %p/%lu)\n", s, s->context, buffer, length, *length);
767 status = SSLRead(s->context, buffer, *length, length);
768 if (status == noErr)
769 TRACE("Read %lu bytes\n", *length);
770 else if (status == errSSLWouldBlock)
772 if (!*length)
774 TRACE("Would block before being able to read anything\n");
775 return SEC_I_CONTINUE_NEEDED;
777 else
778 TRACE("Read %lu bytes before would block\n", *length);
780 else
782 WARN("SSLRead failed: %ld\n", (long)status);
783 return SEC_E_INTERNAL_ERROR;
786 return SEC_E_OK;
789 BOOL schan_imp_allocate_certificate_credentials(schan_imp_certificate_credentials *c)
791 /* The certificate is never really used for anything. */
792 *c = NULL;
793 return TRUE;
796 void schan_imp_free_certificate_credentials(schan_imp_certificate_credentials c)
800 BOOL schan_imp_init(void)
802 TRACE("()\n");
803 return TRUE;
806 void schan_imp_deinit(void)
808 TRACE("()\n");
811 #endif /* HAVE_SECURITY_SECURITY_H */