]> git.saurik.com Git - apple/security.git/blob - Network/https-protocol.cpp
Security-54.1.9.tar.gz
[apple/security.git] / Network / https-protocol.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 // https-protocol - SSL based HTTP.
21 //
22 #include "https-protocol.h"
23 #include "netparameters.h"
24
25
26
27 namespace Security {
28 namespace Network {
29
30 //
31 // Construct the protocol object
32 //
33 SecureHTTPProtocol::SecureHTTPProtocol(Manager &mgr) : HTTPProtocol(mgr, "https")
34 {
35 }
36
37
38 //
39 // Names and identifiers
40 //
41 const char *SecureHTTPProtocol::name() const
42 {
43 return "http/ssl";
44 }
45
46
47 //
48 // Create a Transfer object for our protocol
49 //
50 SecureHTTPProtocol::SecureHTTPTransfer *SecureHTTPProtocol::makeTransfer(const Target &target,
51 Operation operation)
52 {
53 return new SecureHTTPTransfer(*this, target, operation, defaultHttpsPort);
54 }
55
56
57 //
58 // Construct an HTTPConnection object
59 //
60 SecureHTTPProtocol::SecureHTTPConnection::SecureHTTPConnection(Protocol &proto,
61 const HostTarget &hostTarget)
62 : HTTPConnection(proto, hostTarget),
63 SecureTransport<Socket>(static_cast<TCPClientSocket &>(*this)), // (CC pitfall)
64 deferStartSSL(false), sslActive(false)
65
66 {
67 // HTTPConnection already set up everything for talking to the server
68 deferSendRequest = true; // interrupt HTTP state machine after connecting state
69 sslState = sslConnecting;
70 }
71
72 SecureHTTPProtocol::SecureHTTPConnection::~SecureHTTPConnection()
73 {
74 }
75
76 void SecureHTTPProtocol::SecureHTTPConnection::sslRequest()
77 {
78 switch (sslState) {
79 case sslConnecting: // new connection - wait for TL ready
80 break;
81 case sslConnected: // already set; go ahead HTTP
82 transfer().startRequest();
83 break;
84 default:
85 assert(false); // huh?
86 }
87 }
88
89 void SecureHTTPProtocol::SecureHTTPConnection::startSSL()
90 {
91 assert(sslState == sslStartup);
92
93 // from now on, perform I/O through the SSL layer
94 sslActive = true;
95
96 // switch initially to raw input mode. Note that no input bytes will actually
97 // be delivered by our modified read() until SSL handshake is complete.
98 mode(rawInput);
99
100 // configure the SSL session
101 allowsExpiredCerts(getv<bool>(kNetworkHttpAcceptExpiredCerts, false));
102 allowsUnknownRoots(getv<bool>(kNetworkHttpAcceptUnknownRoots, false));
103 peerId(peerAddress());
104
105 // start SSL handshake
106 SSL::open();
107 assert(SSL::state() == kSSLHandshake); // there is no chance that we could already be done
108 sslState = sslHandshaking;
109 }
110
111
112 //
113 // Validate a connection retrieved from the cache
114 //
115 bool SecureHTTPProtocol::SecureHTTPConnection::validate()
116 {
117 return HTTPConnection::validate() && SSL::state() == kSSLConnected;
118 }
119
120
121 //
122 // Our state transit method controls only the initial SSL handshake.
123 // Think of it as a "prefix" to the HTTP protocol state engine. Once the handshake
124 // is complete, we hand off further state management to the HTTP machine.
125 //
126 void SecureHTTPProtocol::SecureHTTPConnection::transit(Event event,
127 char *input, size_t inputLength)
128 {
129 try {
130 switch (sslState) {
131 case sslConnecting:
132 HTTPConnection::transit(event, input, inputLength);
133 if (HTTPConnection::state == idle) { // transport level ready
134 sslState = sslStartup;
135 if (!deferStartSSL)
136 startSSL();
137 }
138 return;
139 case sslHandshaking:
140 assert(event == inputAvailable);
141 SecureTransport<Socket>::open(); // advance handshake protocol
142 switch (SSL::state()) {
143 case kSSLHandshake: // not yet done
144 return;
145 case kSSLConnected: // ready for HTTP
146 sslState = sslConnected;
147 transfer().startRequest();
148 return;
149 default:
150 assert(false); // can't happen - would have thrown
151 }
152 case sslConnected:
153 return HTTPConnection::transit(event, input, inputLength);
154 default:
155 assert(false); // huh?
156 }
157
158 // if SSL fails, we have to abandon the Connection
159 } catch (const CssmCommonError &err) {
160 setError("SSL failed", err.osStatus());
161 throw;
162 } catch (...) {
163 setError("SSL failed");
164 throw;
165 }
166 }
167
168
169 //
170 // The I/O layer for SecureHTTPConnection objects.
171 //
172 size_t SecureHTTPProtocol::SecureHTTPConnection::read(void *data, size_t length)
173 {
174 return sslActive ? SSL::read(data, length) : Socket::read(data, length);
175 }
176
177 size_t SecureHTTPProtocol::SecureHTTPConnection::write(const void *data, size_t length)
178 {
179 return sslActive ? SSL::write(data, length) : Socket::write(data, length);
180 }
181
182 bool SecureHTTPProtocol::SecureHTTPConnection::atEnd() const
183 {
184 return sslActive ? SSL::atEnd() : Socket::atEnd();
185 }
186
187
188 //
189 // HTTPS Transfer objects.
190 //
191 SecureHTTPProtocol::SecureHTTPTransfer::SecureHTTPTransfer(Protocol &proto,
192 const Target &tgt, Operation operation, IPPort defPort)
193 : HTTPTransfer(proto, tgt, operation, defPort)
194 {
195 }
196
197 void SecureHTTPProtocol::SecureHTTPTransfer::start()
198 {
199 SecureHTTPConnection *connection =
200 protocol.manager.findConnection<SecureHTTPConnection>(target);
201 if (connection == NULL)
202 connection = new SecureHTTPConnection(protocol, target);
203 connection->dock(this);
204 connection->sslRequest();
205 }
206
207
208 } // end namespace Network
209 } // end namespace Security