]>
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 | |
29654253 A |
101 | allowsExpiredCerts(getv<bool>(kNetworkHttpAcceptExpiredCerts, false)); |
102 | allowsUnknownRoots(getv<bool>(kNetworkHttpAcceptUnknownRoots, false)); | |
103 | peerId(peerAddress()); | |
104 | ||
bac41a7b A |
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 | |
29654253 | 159 | } catch (const CssmCommonError &err) { |
bac41a7b A |
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 |