]> git.saurik.com Git - apple/security.git/blob - SecureTransport/securetransport++.cpp
Security-177.tar.gz
[apple/security.git] / SecureTransport / securetransport++.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 //
20 // securetransport++ - C++ interface to Apple's Secure Transport layer
21 //
22 #include "securetransport++.h"
23 #include <Security/debugging.h>
24
25
26 namespace Security {
27 namespace IPPlusPlus {
28
29
30 //
31 // Construct a core object.
32 // This creates the Context object and sets the I/O functions.
33 //
34 SecureTransportCore::SecureTransportCore() : mAtEnd(false)
35 {
36 MacOSError::check(SSLNewContext(false, &mContext));
37 try {
38 MacOSError::check(SSLSetIOFuncs(mContext, sslReadFunc, sslWriteFunc));
39 MacOSError::check(SSLSetConnection(mContext, this));
40 secdebug("ssl", "%p constructed", this);
41 } catch (...) {
42 SSLDisposeContext(mContext);
43 throw;
44 }
45 }
46
47
48 //
49 // On destruction, we force a close and destroy the Context.
50 //
51 SecureTransportCore::~SecureTransportCore()
52 {
53 SSLDisposeContext(mContext); // ignore error (can't do anything if error)
54 secdebug("ssl", "%p destroyed", this);
55 }
56
57
58 //
59 // Open initiates or continues the SSL handshake.
60 // In nonblocking mode, open may return while handshake is still in
61 // Progress. Keep calling open until state() != errSSLWouldBlock, or
62 // go directly to I/O.
63 //
64 void SecureTransportCore::open()
65 {
66 switch (OSStatus err = SSLHandshake(mContext)) {
67 case noErr:
68 case errSSLWouldBlock:
69 secdebug("ssl", "%p open, state=%d", this, state());
70 return;
71 default:
72 MacOSError::throwMe(err);
73 }
74 }
75
76
77 //
78 // Close the SSL layer if needed.
79 // Note that this does nothing to the underlying I/O layer.
80 //
81 void SecureTransportCore::close()
82 {
83 switch (state()) {
84 case kSSLHandshake:
85 case kSSLConnected:
86 secdebug("ssl", "%p closed", this);
87 SSLClose(mContext);
88 break;
89 default:
90 break;
91 }
92 }
93
94
95 //
96 // Read bytes from the SSL layer. This is the standard FileDescoid
97 // read function.
98 // Note that if the connection is still handshaking, handshake will proceed
99 // and no bytes will be read (yet).
100 //
101 size_t SecureTransportCore::read(void *data, size_t length)
102 {
103 if (continueHandshake())
104 return 0;
105 UInt32 bytesRead;
106 switch (OSStatus err = SSLRead(mContext, data, length, &bytesRead)) {
107 case noErr: // full read
108 case errSSLWouldBlock: // partial read
109 return bytesRead; // (may be zero in non-blocking scenarios)
110 case errSSLClosedGraceful: // means end-of-data, but we may still return some
111 case errSSLClosedNoNotify: // peer closed abruptly (not sending SSL layer shutdown)
112 if (bytesRead == 0)
113 mAtEnd = true; // no more data - set final end-of-data flag
114 return bytesRead;
115 default:
116 MacOSError::throwMe(err);
117 }
118 }
119
120
121 //
122 // Write bytes to the SSL layer. This is the standard FileDescoid write function.
123 // Note that if the connection is still handshaking, handshake will proceed
124 // and no bytes will be written (yet).
125 //
126 size_t SecureTransportCore::write(const void *data, size_t length)
127 {
128 if (continueHandshake())
129 return 0;
130 UInt32 bytesWritten;
131 switch (OSStatus err = SSLWrite(mContext, data, length, &bytesWritten)) {
132 case noErr:
133 return bytesWritten;
134 case errSSLWouldBlock:
135 return 0; // no data, no error, no fuss
136 default:
137 MacOSError::throwMe(err);
138 }
139 }
140
141
142 //
143 // Continue handshake processing if necessary.
144 // Returns true if handshake is in Progress and not yet complete.
145 //
146 bool SecureTransportCore::continueHandshake()
147 {
148 if (state() == kSSLHandshake) {
149 // still in handshake mode; prod it along
150 secdebug("ssl", "%p continuing handshake", this);
151 switch (OSStatus err = SSLHandshake(mContext)) {
152 case noErr:
153 case errSSLWouldBlock:
154 break;
155 default:
156 MacOSError::throwMe(err);
157 }
158 IFDEBUG(if (state() != kSSLHandshake) secdebug("ssl", "%p handshake complete", this));
159 return state() == kSSLHandshake;
160 } else
161 return false;
162 }
163
164
165 //
166 // State access methods
167 //
168 SSLSessionState SecureTransportCore::state() const
169 {
170 SSLSessionState state;
171 MacOSError::check(SSLGetSessionState(mContext, &state));
172 return state;
173 }
174
175 SSLProtocol SecureTransportCore::version() const
176 {
177 SSLProtocol version;
178 MacOSError::check(SSLGetProtocolVersion(mContext, &version));
179 return version;
180 }
181
182 void SecureTransportCore::version(SSLProtocol version)
183 {
184 MacOSError::check(SSLSetProtocolVersion(mContext, version));
185 }
186
187 UInt32 SecureTransportCore::numSupportedCiphers() const
188 {
189 UInt32 numCiphers;
190 MacOSError::check(SSLGetNumberSupportedCiphers(mContext, &numCiphers));
191 return numCiphers;
192 }
193
194 void SecureTransportCore::supportedCiphers(
195 SSLCipherSuite *ciphers,
196 UInt32 &numCiphers) const
197 {
198 MacOSError::check(SSLGetSupportedCiphers(mContext, ciphers, &numCiphers));
199 }
200
201 UInt32 SecureTransportCore::numEnabledCiphers() const
202 {
203 UInt32 numCiphers;
204 MacOSError::check(SSLGetNumberEnabledCiphers(mContext, &numCiphers));
205 return numCiphers;
206 }
207
208 void SecureTransportCore::enabledCiphers(
209 SSLCipherSuite *ciphers,
210 UInt32 &numCiphers) const
211 {
212 MacOSError::check(SSLGetEnabledCiphers(mContext, ciphers, &numCiphers));
213 }
214
215 void SecureTransportCore::enabledCiphers(
216 SSLCipherSuite *ciphers,
217 UInt32 numCiphers)
218 {
219 MacOSError::check(SSLSetEnabledCiphers(mContext, ciphers, numCiphers));
220 }
221
222 bool SecureTransportCore::allowsExpiredCerts() const
223 {
224 Boolean allow;
225 MacOSError::check(SSLGetAllowsExpiredCerts(mContext, &allow));
226 return allow;
227 }
228
229 void SecureTransportCore::allowsExpiredCerts(bool allow)
230 {
231 MacOSError::check(SSLSetAllowsExpiredCerts(mContext, allow));
232 }
233
234 bool SecureTransportCore::allowsUnknownRoots() const
235 {
236 Boolean allow;
237 MacOSError::check(SSLGetAllowsAnyRoot(mContext, &allow));
238 return allow;
239 }
240
241 void SecureTransportCore::allowsUnknownRoots(bool allow)
242 {
243 MacOSError::check(SSLSetAllowsAnyRoot(mContext, allow));
244 }
245
246 void SecureTransportCore::peerId(const void *id, size_t length)
247 {
248 MacOSError::check(SSLSetPeerID(mContext, id, length));
249 }
250
251
252 //
253 // Implement SecureTransport's read/write transport functions.
254 // Note that this API is very un-UNIX in that error codes (errSSLClosedGraceful, errSSLWouldBlock)
255 // are returned even though data has been produced.
256 //
257 OSStatus SecureTransportCore::sslReadFunc(SSLConnectionRef connection,
258 void *data, UInt32 *length)
259 {
260 const SecureTransportCore *stc = reinterpret_cast<const SecureTransportCore *>(connection);
261 try {
262 size_t lengthRequested = *length;
263 *length = stc->ioRead(data, lengthRequested);
264 secdebug("sslconio", "%p read %ld of %ld bytes", stc, *length, lengthRequested);
265 if (*length == lengthRequested) // full deck
266 return noErr;
267 else if (stc->ioAtEnd()) {
268 secdebug("sslconio", "%p end of source input, returning %ld bytes",
269 stc, *length);
270 return errSSLClosedGraceful;
271 } else
272 return errSSLWouldBlock;
273 } catch (const UnixError &err) {
274 *length = 0;
275 if (err.error == ECONNRESET)
276 return errSSLClosedGraceful;
277 throw;
278 } catch (const CssmCommonError &err) {
279 *length = 0;
280 return err.osStatus();
281 } catch (...) {
282 *length = 0;
283 return -1; //@@@ generic internal error?
284 }
285 }
286
287 OSStatus SecureTransportCore::sslWriteFunc(SSLConnectionRef connection,
288 const void *data, UInt32 *length)
289 {
290 const SecureTransportCore *stc = reinterpret_cast<const SecureTransportCore *>(connection);
291 try {
292 size_t lengthRequested = *length;
293 *length = stc->ioWrite(data, lengthRequested);
294 secdebug("sslconio", "%p wrote %ld of %ld bytes", stc, *length, lengthRequested);
295 return *length == lengthRequested ? OSStatus(noErr) : OSStatus(errSSLWouldBlock);
296 } catch (const CssmCommonError &err) {
297 *length = 0;
298 return err.osStatus();
299 } catch (...) {
300 *length = 0;
301 return -1; //@@@ generic internal error?
302 }
303 }
304
305
306 } // end namespace IPPlusPlus
307 } // end namespace Security