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 if (fPrivate->fBIO != NULL) { 111 BIO_free(fPrivate->fBIO); 112 fPrivate->fBIO = NULL; 113 } 114 } 115 return BSocket::Disconnect(); 116 } 117 118 119 status_t 120 BSecureSocket::WaitForReadable(bigtime_t timeout) const 121 { 122 if (fInitStatus != B_OK) 123 return fInitStatus; 124 if (!IsConnected()) 125 return B_ERROR; 126 127 if (SSL_pending(fPrivate->fSSL) > 0) 128 return B_OK; 129 130 return BSocket::WaitForReadable(timeout); 131 } 132 133 134 // #pragma mark - BDataIO implementation 135 136 137 ssize_t 138 BSecureSocket::Read(void* buffer, size_t size) 139 { 140 if (!IsConnected()) 141 return B_ERROR; 142 143 int bytesRead = SSL_read(fPrivate->fSSL, buffer, size); 144 if (bytesRead > 0) 145 return bytesRead; 146 147 // TODO: translate SSL error codes! 148 return B_ERROR; 149 } 150 151 152 ssize_t 153 BSecureSocket::Write(const void* buffer, size_t size) 154 { 155 if (!IsConnected()) 156 return B_ERROR; 157 158 int bytesWritten = SSL_write(fPrivate->fSSL, buffer, size); 159 if (bytesWritten > 0) 160 return bytesWritten; 161 162 // TODO: translate SSL error codes! 163 return B_ERROR; 164 } 165 166 167 #else // OPENSSL_ENABLED 168 169 170 // #pragma mark - No-SSL stubs 171 172 173 BSecureSocket::BSecureSocket() 174 { 175 } 176 177 178 BSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout) 179 { 180 fInitStatus = B_UNSUPPORTED; 181 } 182 183 184 BSecureSocket::BSecureSocket(const BSecureSocket& other) 185 : 186 BSocket(other) 187 { 188 } 189 190 191 BSecureSocket::~BSecureSocket() 192 { 193 } 194 195 196 status_t 197 BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout) 198 { 199 return fInitStatus = B_UNSUPPORTED; 200 } 201 202 203 void 204 BSecureSocket::Disconnect() 205 { 206 } 207 208 209 status_t 210 BSecureSocket::WaitForReadable(bigtime_t timeout) const 211 { 212 return B_UNSUPPORTED; 213 } 214 215 216 // #pragma mark - BDataIO implementation 217 218 219 ssize_t 220 BSecureSocket::Read(void* buffer, size_t size) 221 { 222 return B_UNSUPPORTED; 223 } 224 225 226 ssize_t 227 BSecureSocket::Write(const void* buffer, size_t size) 228 { 229 return B_UNSUPPORTED; 230 } 231 232 233 #endif // !OPENSSL_ENABLED 234