]>
Commit | Line | Data |
---|---|---|
bac41a7b A |
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 | allowExpiredCerts(getv<bool>(kNetworkHttpAcceptExpiredCerts, false)); | |
102 | allowUnknownRoots(getv<bool>(kNetworkHttpAcceptUnknownRoots, false)); | |
103 | ||
104 | // start SSL handshake | |
105 | SSL::open(); | |
106 | assert(SSL::state() == kSSLHandshake); // there is no chance that we could already be done | |
107 | sslState = sslHandshaking; | |
108 | } | |
109 | ||
110 | ||
111 | // | |
112 | // Validate a connection retrieved from the cache | |
113 | // | |
114 | bool SecureHTTPProtocol::SecureHTTPConnection::validate() | |
115 | { | |
116 | return HTTPConnection::validate() && SSL::state() == kSSLConnected; | |
117 | } | |
118 | ||
119 | ||
120 | // | |
121 | // Our state transit method controls only the initial SSL handshake. | |
122 | // Think of it as a "prefix" to the HTTP protocol state engine. Once the handshake | |
123 | // is complete, we hand off further state management to the HTTP machine. | |
124 | // | |
125 | void SecureHTTPProtocol::SecureHTTPConnection::transit(Event event, | |
126 | char *input, size_t inputLength) | |
127 | { | |
128 | try { | |
129 | switch (sslState) { | |
130 | case sslConnecting: | |
131 | HTTPConnection::transit(event, input, inputLength); | |
132 | if (HTTPConnection::state == idle) { // transport level ready | |
133 | sslState = sslStartup; | |
134 | if (!deferStartSSL) | |
135 | startSSL(); | |
136 | } | |
137 | return; | |
138 | case sslHandshaking: | |
139 | assert(event == inputAvailable); | |
140 | SecureTransport<Socket>::open(); // advance handshake protocol | |
141 | switch (SSL::state()) { | |
142 | case kSSLHandshake: // not yet done | |
143 | return; | |
144 | case kSSLConnected: // ready for HTTP | |
145 | sslState = sslConnected; | |
146 | transfer().startRequest(); | |
147 | return; | |
148 | default: | |
149 | assert(false); // can't happen - would have thrown | |
150 | } | |
151 | case sslConnected: | |
152 | return HTTPConnection::transit(event, input, inputLength); | |
153 | default: | |
154 | assert(false); // huh? | |
155 | } | |
156 | ||
157 | // if SSL fails, we have to abandon the Connection | |
158 | } catch (CssmCommonError &err) { | |
159 | setError("SSL failed", err.osStatus()); | |
160 | throw; | |
161 | } catch (...) { | |
162 | setError("SSL failed"); | |
163 | throw; | |
164 | } | |
165 | } | |
166 | ||
167 | ||
168 | // | |
169 | // The I/O layer for SecureHTTPConnection objects. | |
170 | // | |
171 | size_t SecureHTTPProtocol::SecureHTTPConnection::read(void *data, size_t length) | |
172 | { | |
173 | return sslActive ? SSL::read(data, length) : Socket::read(data, length); | |
174 | } | |
175 | ||
176 | size_t SecureHTTPProtocol::SecureHTTPConnection::write(const void *data, size_t length) | |
177 | { | |
178 | return sslActive ? SSL::write(data, length) : Socket::write(data, length); | |
179 | } | |
180 | ||
181 | bool SecureHTTPProtocol::SecureHTTPConnection::atEnd() const | |
182 | { | |
183 | return sslActive ? SSL::atEnd() : Socket::atEnd(); | |
184 | } | |
185 | ||
186 | ||
187 | // | |
188 | // HTTPS Transfer objects. | |
189 | // | |
190 | SecureHTTPProtocol::SecureHTTPTransfer::SecureHTTPTransfer(Protocol &proto, | |
191 | const Target &tgt, Operation operation, IPPort defPort) | |
192 | : HTTPTransfer(proto, tgt, operation, defPort) | |
193 | { | |
194 | } | |
195 | ||
196 | void SecureHTTPProtocol::SecureHTTPTransfer::start() | |
197 | { | |
198 | SecureHTTPConnection *connection = | |
199 | protocol.manager.findConnection<SecureHTTPConnection>(target); | |
200 | if (connection == NULL) | |
201 | connection = new SecureHTTPConnection(protocol, target); | |
202 | connection->dock(this); | |
203 | connection->sslRequest(); | |
204 | } | |
205 | ||
206 | ||
207 | } // end namespace Network | |
208 | } // end namespace Security |