/* Return value: * SSL_OK: the SSL connection is accepted * SSL_ERROR: failed, call ossSSLGetError() & ossSSLGetErrorMessage() for reason */ INT32 ossSSLAccept(SSLHandle* handle) { INT32 status; INT32 ret = SDB_OK; SSL_ASSERT(NULL != handle); SSL_ASSERT(NULL != handle->ssl); do { status = SSL_accept(handle->ssl); ret = _ossSSLCheckStatus(handle, status); } while (SSL_AGAIN == ret); return ret; }
/* Return value: * SSL_OK: the SSL connection is accepted * SSL_ERROR: failed, call ossSSLGetError() & ossSSLGetErrorMessage() for reason */ INT32 ossSSLShutdown(SSLHandle* handle) { INT32 status; INT32 ret = SSL_OK; SSL_ASSERT(NULL != handle); SSL_ASSERT(NULL != handle->ssl); do { status = SSL_shutdown(handle->ssl); ret = _ossSSLCheckStatus(handle, status); } while (SSL_AGAIN == ret); return ret; }
/* Return value: * >0: the number of bytes actually write to SSL connection * SSL_AGAIN: need to write again * SSL_ERROR: failed, call ossSSLGetError() & ossSSLGetErrorMessage() for reason * SSL_TIMEOUT: only in windows */ INT32 ossSSLWrite(SSLHandle* handle, const void* buf, INT32 num) { INT32 status; INT32 ret = SSL_OK; SSL_ASSERT(NULL != handle); SSL_ASSERT(NULL != handle->ssl); SSL_ASSERT(NULL != buf); status = SSL_write(handle->ssl, buf, num); ret = _ossSSLCheckStatus(handle, status); if (SSL_OK != ret) { status = ret; } return status; }
void ossSSLFreeContext(SSLContext** context) { SSL_ASSERT(NULL != context); if (NULL != *context) { SSL_CTX_free(*context); *context = NULL; } }
void ossSSLFreeHandle(SSLHandle** handle) { SSL_ASSERT(NULL != handle); if (NULL != *handle) { SSLHandle* h = *handle; /* h->bufferBIO will be freed by SSL_free() */ if (NULL != h->ssl) { SSL_free(h->ssl); } OPENSSL_free(h); *handle = NULL; } }
static INT32 _ossSSLCheckStatus(SSLHandle* handle, INT32 status) { INT32 err; INT32 ret = SDB_OK; SSL_ASSERT(NULL != handle); err = SSL_get_error(handle->ssl, status); handle->error = err; switch(err) { case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: ret = SSL_AGAIN; /* pass through */ case SSL_ERROR_NONE: if (NULL != handle->bufferBIO) { if (!BIO_flush(handle->bufferBIO)) { handle->error = SSL_ERROR_SYSCALL; ret = SSL_ERROR; } } break; default: #ifdef _WINDOWS { /* OPENSSL considers WSAETIMEDOUT as an error */ INT32 lastError = WSAGetLastError(); if (WSAETIMEDOUT == lastError) { ret = SSL_TIMEOUT; } } #else ret = SSL_ERROR; #endif } return ret; }
void drown_new(drown_ctx * dctx) { dctx->ctx = BN_CTX_new(); SSL_ASSERT(dctx->ctx != NULL); dctx->n = BN_new(); SSL_ASSERT(dctx->n != NULL); dctx->e = BN_new(); SSL_ASSERT(dctx->e != NULL); dctx->c = BN_new(); SSL_ASSERT(dctx->c != NULL); dctx->s = BN_new(); SSL_ASSERT(dctx->s != NULL); dctx->mt = BN_new(); SSL_ASSERT(dctx->mt != NULL); }
INT32 ossSSLGetError(SSLHandle* handle) { SSL_ASSERT(NULL != handle); return handle->error; }
/* Return value: * SSL_OK: the SSL handle is created * SSL_ERROR: failed, call ossSSLERRGetError() & ossSSLERRGetErrorMessage() for reason */ INT32 ossSSLNewHandle(SSLHandle** handle, SSLContext* ctx, SOCKET sock, const char* initialBytes, INT32 len) { SSLHandle* h = NULL; SSL* ssl = NULL; BIO* bufferBIO = NULL; BIO* socketBIO = NULL; INT32 ret = SSL_OK; SSL_ASSERT(NULL != handle); SSL_ASSERT(NULL != ctx); SSL_ASSERT(len >= 0); h = (SSLHandle*)OPENSSL_malloc(sizeof(SSLHandle)); if (NULL == h) { goto error; } _SSLHandleInit(h); h->sock = sock; ssl = SSL_new(ctx); if (NULL == ssl) { goto error; } h->ssl = ssl; if (0 == len) { /* there is no initial bytes, so we just set the socket to SSL */ ret = SSL_set_fd(ssl, sock); if (!ret) { goto error; } } else /* len > 0 */ { SSL_ASSERT(NULL != initialBytes); /* * There are initial SSL bytes, so we should give these bytes to SSL by some way. * Here we create a buffer BIO, and put these bytes to it. * Then we create a socket BIO, and set a BIO chain to link * the buffer and socket by BIO_push(). * Finally, we set the buffer to SSL instead of the socket. * * NOTE: when do SSL operations, it should explicitly flush the buffer. */ bufferBIO = BIO_new(BIO_f_buffer()); if (NULL == bufferBIO) { goto error; } ret = BIO_set_buffer_read_data(bufferBIO, (void*)initialBytes, len); if (!ret) { goto error; } socketBIO = BIO_new_socket(sock, BIO_NOCLOSE); if (NULL == socketBIO) { goto error; } /* link socket to the buffer */ if (NULL == BIO_push(bufferBIO, socketBIO)) { goto error; } /* SSL_free() will also free bufferBIO, * so it's no need to free bufferBIO later when free the SSL handle. */ SSL_set_bio(ssl, bufferBIO, bufferBIO); /* hold the bufferBIO pointer so we can flush it when do SSL operations */ h->bufferBIO = bufferBIO; } *handle = h; ret = SDB_OK; done: return ret; error: if (NULL != bufferBIO) { BIO_free(bufferBIO); } if (NULL != socketBIO) { BIO_free(socketBIO); } if (NULL != ssl) { SSL_free(ssl); } if (NULL != h) { OPENSSL_free(h); } ret = SSL_ERROR; goto done; }
INT32 ossSSLNewContext(SSLContext** context, SSLCertificate* cert, SSLKey* key) { SSLContext* ctx = NULL; INT32 ret = SDB_OK; SSL_ASSERT(NULL != context); SSL_ASSERT(NULL != key); SSL_ASSERT(NULL != cert); ctx = SSL_CTX_new(SSLv23_method ()); if (NULL == ctx) { goto error; } /* SSL_OP_ALL - Activate all bug workaround options, to support buggy client SSL's. * SSL_OP_NO_SSLv2 - Disable SSL v2 support */ SSL_CTX_set_options(ctx, (SSL_OP_ALL | SSL_OP_NO_SSLv2)); /* HIGH - Enable strong ciphers * !EXPORT - Disable export ciphers (40/56 bit) * !aNULL - Disable anonymous auth ciphers * @STRENGTH - Sort ciphers based on strength */ SSL_CTX_set_cipher_list(ctx, "HIGH:!EXPORT:!aNULL@STRENGTH"); /* If renegotiation is needed, don't return from recv() or send() until it's successful. * NOTE: this is for blocking sockets only. */ SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); /* disable session caching */ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); ret = SSL_CTX_use_certificate(ctx, cert); if (!ret) { goto error; } ret = SSL_CTX_use_PrivateKey(ctx, key); if (!ret) { goto error; } ret = SSL_CTX_check_private_key(ctx); if (!ret) { goto error; } *context = ctx; ret = SSL_OK; done: return ret; error: if (NULL != ctx) { SSL_CTX_free(ctx); } ret = SSL_ERROR; goto done; }