2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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
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.
20 // https-protocol - SSL based HTTP.
22 #include "https-protocol.h"
23 #include "netparameters.h"
31 // Construct the protocol object
33 SecureHTTPProtocol::SecureHTTPProtocol(Manager
&mgr
) : HTTPProtocol(mgr
, "https")
39 // Names and identifiers
41 const char *SecureHTTPProtocol::name() const
48 // Create a Transfer object for our protocol
50 SecureHTTPProtocol::SecureHTTPTransfer
*SecureHTTPProtocol::makeTransfer(const Target
&target
,
53 return new SecureHTTPTransfer(*this, target
, operation
, defaultHttpsPort
);
58 // Construct an HTTPConnection object
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)
67 // HTTPConnection already set up everything for talking to the server
68 deferSendRequest
= true; // interrupt HTTP state machine after connecting state
69 sslState
= sslConnecting
;
72 SecureHTTPProtocol::SecureHTTPConnection::~SecureHTTPConnection()
76 void SecureHTTPProtocol::SecureHTTPConnection::sslRequest()
79 case sslConnecting
: // new connection - wait for TL ready
81 case sslConnected
: // already set; go ahead HTTP
82 transfer().startRequest();
85 assert(false); // huh?
89 void SecureHTTPProtocol::SecureHTTPConnection::startSSL()
91 assert(sslState
== sslStartup
);
93 // from now on, perform I/O through the SSL layer
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.
100 // configure the SSL session
101 allowsExpiredCerts(getv
<bool>(kNetworkHttpAcceptExpiredCerts
, false));
102 allowsUnknownRoots(getv
<bool>(kNetworkHttpAcceptUnknownRoots
, false));
103 peerId(peerAddress());
105 // start SSL handshake
107 assert(SSL::state() == kSSLHandshake
); // there is no chance that we could already be done
108 sslState
= sslHandshaking
;
113 // Validate a connection retrieved from the cache
115 bool SecureHTTPProtocol::SecureHTTPConnection::validate()
117 return HTTPConnection::validate() && SSL::state() == kSSLConnected
;
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.
126 void SecureHTTPProtocol::SecureHTTPConnection::transit(Event event
,
127 char *input
, size_t inputLength
)
132 HTTPConnection::transit(event
, input
, inputLength
);
133 if (HTTPConnection::state
== idle
) { // transport level ready
134 sslState
= sslStartup
;
140 assert(event
== inputAvailable
);
141 SecureTransport
<Socket
>::open(); // advance handshake protocol
142 switch (SSL::state()) {
143 case kSSLHandshake
: // not yet done
145 case kSSLConnected
: // ready for HTTP
146 sslState
= sslConnected
;
147 transfer().startRequest();
150 assert(false); // can't happen - would have thrown
153 return HTTPConnection::transit(event
, input
, inputLength
);
155 assert(false); // huh?
158 // if SSL fails, we have to abandon the Connection
159 } catch (const CssmCommonError
&err
) {
160 setError("SSL failed", err
.osStatus());
163 setError("SSL failed");
170 // The I/O layer for SecureHTTPConnection objects.
172 size_t SecureHTTPProtocol::SecureHTTPConnection::read(void *data
, size_t length
)
174 return sslActive
? SSL::read(data
, length
) : Socket::read(data
, length
);
177 size_t SecureHTTPProtocol::SecureHTTPConnection::write(const void *data
, size_t length
)
179 return sslActive
? SSL::write(data
, length
) : Socket::write(data
, length
);
182 bool SecureHTTPProtocol::SecureHTTPConnection::atEnd() const
184 return sslActive
? SSL::atEnd() : Socket::atEnd();
189 // HTTPS Transfer objects.
191 SecureHTTPProtocol::SecureHTTPTransfer::SecureHTTPTransfer(Protocol
&proto
,
192 const Target
&tgt
, Operation operation
, IPPort defPort
)
193 : HTTPTransfer(proto
, tgt
, operation
, defPort
)
197 void SecureHTTPProtocol::SecureHTTPTransfer::start()
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();
208 } // end namespace Network
209 } // end namespace Security