1 /* 2 * Copyright 2011, Axel Dörfler, axeld@pinc-software.de. 3 * Copyright 2010, Clemens Zeidler <haiku@clemens-zeidler.de> 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 #include <SecureSocket.h> 9 10 #ifdef OPENSSL_ENABLED 11 # include <openssl/ssl.h> 12 #endif 13 14 15 //#define TRACE_SOCKET 16 #ifdef TRACE_SOCKET 17 # define TRACE(x...) printf(x) 18 #else 19 # define TRACE(x...) ; 20 #endif 21 22 23 #ifdef OPENSSL_ENABLED 24 25 26 class BSecureSocket::Private { 27 public: 28 SSL_CTX* fCTX; 29 SSL* fSSL; 30 BIO* fBIO; 31 }; 32 33 34 BSecureSocket::BSecureSocket() 35 : 36 fPrivate(NULL) 37 { 38 } 39 40 41 BSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout) 42 : 43 fPrivate(NULL) 44 { 45 Connect(peer, timeout); 46 } 47 48 49 BSecureSocket::BSecureSocket(const BSecureSocket& other) 50 : 51 BSocket(other) 52 { 53 // TODO: this won't work this way! 54 fPrivate = (BSecureSocket::Private*)malloc(sizeof(BSecureSocket::Private)); 55 if (fPrivate != NULL) 56 memcpy(fPrivate, other.fPrivate, sizeof(BSecureSocket::Private)); 57 else 58 fInitStatus = B_NO_MEMORY; 59 } 60 61 62 BSecureSocket::~BSecureSocket() 63 { 64 free(fPrivate); 65 } 66 67 68 status_t 69 BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout) 70 { 71 if (fPrivate == NULL) { 72 fPrivate = (BSecureSocket::Private*)calloc(1, 73 sizeof(BSecureSocket::Private)); 74 if (fPrivate == NULL) 75 return B_NO_MEMORY; 76 } 77 78 status_t status = BSocket::Connect(peer, timeout); 79 if (status != B_OK) 80 return status; 81 82 fPrivate->fCTX = SSL_CTX_new(SSLv23_method()); 83 fPrivate->fSSL = SSL_new(fPrivate->fCTX); 84 fPrivate->fBIO = BIO_new_socket(fSocket, BIO_NOCLOSE); 85 SSL_set_bio(fPrivate->fSSL, fPrivate->fBIO, fPrivate->fBIO); 86 87 if (SSL_connect(fPrivate->fSSL) <= 0) { 88 TRACE("SSLConnection can't connect\n"); 89 BSocket::Disconnect(); 90 // TODO: translate ssl to Haiku error 91 return B_ERROR; 92 } 93 94 return B_OK; 95 } 96 97 98 void 99 BSecureSocket::Disconnect() 100 { 101 if (IsConnected()) { 102 if (fPrivate->fSSL != NULL) { 103 SSL_shutdown(fPrivate->fSSL); 104 fPrivate->fSSL = NULL; 105 } 106 if (fPrivate->fCTX != NULL) { 107 SSL_CTX_free(fPrivate->fCTX); 108 fPrivate->fCTX = NULL; 109 } 110 111 BSocket::Disconnect(); 112 // Must do this before freeing the BIO, to make sure any pending 113 // read or write gets unlocked properly. 114 if (fPrivate->fBIO != NULL) { 115 BIO_free(fPrivate->fBIO); 116 fPrivate->fBIO = NULL; 117 } 118 } 119 } 120 121 122 status_t 123 BSecureSocket::WaitForReadable(bigtime_t timeout) const 124 { 125 if (fInitStatus != B_OK) 126 return fInitStatus; 127 if (!IsConnected()) 128 return B_ERROR; 129 130 if (SSL_pending(fPrivate->fSSL) > 0) 131 return B_OK; 132 133 return BSocket::WaitForReadable(timeout); 134 } 135 136 137 // #pragma mark - BDataIO implementation 138 139 140 ssize_t 141 BSecureSocket::Read(void* buffer, size_t size) 142 { 143 if (!IsConnected()) 144 return B_ERROR; 145 146 int bytesRead = SSL_read(fPrivate->fSSL, buffer, size); 147 if (bytesRead >= 0) 148 return bytesRead; 149 150 // TODO: translate SSL error codes! 151 return B_ERROR; 152 } 153 154 155 ssize_t 156 BSecureSocket::Write(const void* buffer, size_t size) 157 { 158 if (!IsConnected()) 159 return B_ERROR; 160 161 int bytesWritten = SSL_write(fPrivate->fSSL, buffer, size); 162 if (bytesWritten >= 0) 163 return bytesWritten; 164 165 // TODO: translate SSL error codes! 166 return B_ERROR; 167 } 168 169 170 #else // OPENSSL_ENABLED 171 172 173 // #pragma mark - No-SSL stubs 174 175 176 BSecureSocket::BSecureSocket() 177 { 178 } 179 180 181 BSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout) 182 { 183 fInitStatus = B_UNSUPPORTED; 184 } 185 186 187 BSecureSocket::BSecureSocket(const BSecureSocket& other) 188 : 189 BSocket(other) 190 { 191 } 192 193 194 BSecureSocket::~BSecureSocket() 195 { 196 } 197 198 199 status_t 200 BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout) 201 { 202 return fInitStatus = B_UNSUPPORTED; 203 } 204 205 206 void 207 BSecureSocket::Disconnect() 208 { 209 } 210 211 212 status_t 213 BSecureSocket::WaitForReadable(bigtime_t timeout) const 214 { 215 return B_UNSUPPORTED; 216 } 217 218 219 // #pragma mark - BDataIO implementation 220 221 222 ssize_t 223 BSecureSocket::Read(void* buffer, size_t size) 224 { 225 return B_UNSUPPORTED; 226 } 227 228 229 ssize_t 230 BSecureSocket::Write(const void* buffer, size_t size) 231 { 232 return B_UNSUPPORTED; 233 } 234 235 236 #endif // !OPENSSL_ENABLED 237