2011-08-16 4 views
1

이 코드는 a minimal SSL server 시작합니다OpenSSL이 코드는 XP에서 작동하지만 Vista에서 영원히 달려 최대

WSAStartup(MakeWord(1,1), WData); 
SSL_library_init; 
SSL_load_error_strings; 
ctx := SSL_CTX_new(SSLv23_server_method); 
SSL_CTX_use_certificate_chain_file(ctx, 'cert.pem'); 
SSL_CTX_use_PrivateKey_file(ctx, 'key.pem', 1); 
SSL_CTX_check_private_key(ctx); 
bio_ssl := BIO_new_ssl(ctx, 0); 
bio_in := BIO_new_accept('443'); 
BIO_set_accept_bios(bio_in, bio_ssl); 
BIO_do_accept(bio_in); // set up the socket 
BIO_do_accept(bio_in); // wait for connection 

모두가 XP에서 잘 작동합니다. 코드는 연결을 기다리는 두 번째 BIO_do_accept() 에 머무르고 브라우저에서 HTTPS 요청을 보내면 은 BIO_do_accept()를 반환합니다.

32 비트 Vista Home Premium 및 64 비트 Windows 7에서 두 번째 BIO_do_accept()는 영원히 멈추고 브라우저는 연결할 수 없습니다. 왜?

32 비트 .EXE의 다양한 호환 모드 (Windows XP, Windows NT 등)를 변경해도 아무런 효과가 없습니다. OpenSSL 1.0.0d를 사용하고 있습니다.

+2

모든 기능을합니다. 'BIO_do_accept' 함수를 호출하기 전에 문제가 제기 되었기 때문일 수 있습니다. – RRUZ

+0

실제 코드 check(); 모든 호출; 그들 중 누구도 오류를 반환하지 않습니다. check()는 위의 소스에서 빠져 나오지 않도록 제외되었습니다. –

+0

내 생각에 UAC와 관련이있을 것입니다. 아마도 Vista/Win7에서 포트를 열거 나 들으려면 추가 권한이 필요합니다. 관리자로 실행하면 작동합니까? – shunty

답변

1

아마 두 번의 BIO_do_accept() 호출과 관련이 있습니다.

나는 OpenSSL의 S_SERVER.C 코드를 가져 와서 몇 가지 변경을 가한 다음 아래의 간단한 버전으로 압축합니다. 그것은 비스타와 윈도우 7에서 작동합니다! 위의 문제 코드와 완전히 다른 BIO 호출 (비 차단 작업)을 사용합니다 (S_SERVER.C 및 대부분의 서버 예제와 달리). Google 크롬 POST는 question 7054471 당 시간 초과를 통해 올바르게 캡처됩니다. 당신은`BIO_do_accept` 호출하기 전에, 상태 코드 또는 부울 결과를 반환하여, 그래서 그 기능에 대한 값을 확인하려고하는

program s_server; 

uses sysutils, winsock, windows; 

const 
    SSLEAY32DLL = 'ssleay32.dll'; 
    SSL_FILETYPE_PEM = 1; 
    SSL_SENT_SHUTDOWN = 1; 
    SSL_RECEIVED_SHUTDOWN = 2; 

function BIO_f_ssl: pointer; cdecl; external SSLEAY32DLL; 
function SSL_CTX_check_private_key(ctx: pointer): BOOL; cdecl; external SSLEAY32DLL; 
function SSL_CTX_ctrl(ctx: pointer; cmd, i: integer; p: pointer): integer; cdecl; external SSLEAY32DLL; 
procedure SSL_CTX_free(ctx: pointer); cdecl; external SSLEAY32DLL; 
function SSL_CTX_new(meth: pointer): pointer; cdecl; external SSLEAY32DLL; 
procedure SSL_CTX_set_quiet_shutdown(ctx: pointer; mode: integer); cdecl; external SSLEAY32DLL; 
function SSL_CTX_use_certificate_chain_file(ctx: pointer; fname: pchar): integer; cdecl; external SSLEAY32DLL; 
function SSL_CTX_use_PrivateKey_file(ctx: pointer; fname: pchar; itype: integer): integer; cdecl; external SSLEAY32DLL; 
procedure SSL_library_init; cdecl; external SSLEAY32DLL; 
procedure SSL_load_error_strings; cdecl; external SSLEAY32DLL; 
function SSL_new(ctx: pointer): pointer; cdecl; external SSLEAY32DLL; 
procedure SSL_set_accept_state(b: pointer); cdecl; external SSLEAY32DLL; 
procedure SSL_set_bio(ssl, readbio, writebio: pointer); cdecl; external SSLEAY32DLL; 
procedure SSL_set_shutdown(ssl: pointer; mode: integer); cdecl; external SSLEAY32DLL; 
function SSLv23_server_method: pointer; cdecl; external SSLEAY32DLL; 

const 
    LIBEAY32DLL = 'libeay32.dll'; 
    BIO_NOCLOSE = $00; 
    BIO_CLOSE = $01; 

function BIO_ctrl(bp: pointer; cmd: integer; larg: integer; parg: pointer): integer; cdecl; external LIBEAY32DLL; 
function BIO_f_buffer: pointer; cdecl; external LIBEAY32DLL; 
procedure BIO_free_all(bp: pointer); cdecl; external LIBEAY32DLL; 
function BIO_gets(b: pointer; buf: pchar; size: integer): integer; cdecl; external LIBEAY32DLL; 
function BIO_int_ctrl(bp: pointer; cmd: integer; i1, i2: integer): integer; cdecl; external LIBEAY32DLL; 
function BIO_new(t: pointer): pointer; cdecl; external LIBEAY32DLL; 
function BIO_new_socket(sock, flag: integer): pointer; cdecl; external LIBEAY32DLL; 
function BIO_push(b: pointer; append: pointer): pointer; cdecl; external LIBEAY32DLL; 
function BIO_socket_ioctl(sock: integer; ctl: cardinal; p: pointer): integer; cdecl; external LIBEAY32DLL; 
function BIO_test_flags(bp: pointer; flags: integer): integer; cdecl; external LIBEAY32DLL; 
function BIO_write(bp, buffer: pointer; size: integer): integer; cdecl; external LIBEAY32DLL; 
procedure OPENSSL_load_builtin_modules; cdecl; external LIBEAY32DLL; 

function BIO_flush(b: pointer): integer; const BIO_CTRL_FLUSH = 11; begin result := BIO_ctrl(b, BIO_CTRL_FLUSH, 0, nil); end; 
function BIO_set_ssl(b, ssl: pointer; c: integer): integer; const BIO_C_SET_SSL = 109; begin result := BIO_ctrl(b, BIO_C_SET_SSL, c, ssl); end; 
function BIO_should_retry(b: pointer): boolean; const BIO_FLAGS_SHOULD_RETRY = 8; begin result := BIO_test_flags(b, BIO_FLAGS_SHOULD_RETRY) <> 0; end; 
function SSL_CTX_set_options(ctx: pointer; op: integer): integer; const SSL_CTRL_OPTIONS = 32; begin result := SSL_CTX_ctrl(ctx, SSL_CTRL_OPTIONS, op, nil); end; 

procedure confirm(b: boolean); begin {$WARN SYMBOL_PLATFORM OFF} win32check(b); {$WARN SYMBOL_PLATFORM ON} end; 

const 
    DEFAULTPORT = 443; 
    MAXWAIT = 500; // 500ms max for read 

function getresponse(const ip, request: string): string; 
var body: string; 
begin // ignore request and just announce ip 
body := '<HTML><HEAD><TITLE>Hello!</TITLE></HEAD><H1>Your IP is...</H1><BODY>' + ip + '</BODY></HTML>'; 
result := 'HTTP/1.0 200 OK'#13#10'Connection: Close'#13#10'Content-Type: text/HTML'#13#10'Content-Length: ' + IntToStr(length(body)) + #13#10#13#10 + body; 
end; 

const BUFSIZE = 16*1024; // used in openssl s_server.c 

var 
    buf: packed array[0..BUFSIZE-1] of char; 
    request, response: string; 
    ctx: pointer; 

procedure read_and_respond(const ip: string; sock: integer); 
var 
    i, j, k: integer; start: cardinal; 
    con, io, ssl_bio, sbio: pointer; 
label err, endlabel, write_error; 
begin 
io := BIO_new(BIO_f_buffer); 
ssl_bio := BIO_new(BIO_f_ssl); if (io = nil) or (ssl_bio = nil) then goto err; 
// enable non-blocking 
i := 1; if BIO_socket_ioctl(sock, FIONBIO, @i) < 0 then writeln('Can''t unblock!'); 
con := SSL_new(ctx); if con = nil then goto err; 
sbio := BIO_new_socket(sock, BIO_NOCLOSE); 
SSL_set_bio(con, sbio, sbio); 
SSL_set_accept_state(con); 
BIO_set_ssl(ssl_bio, con, BIO_CLOSE); 
BIO_push(io, ssl_bio); 
request := ''; start := gettickcount; 
repeat 
    i := BIO_gets(io, @buf, bufsize-1); 
    if i < 0 then // error 
    if not BIO_should_retry(io) then goto err 
    else continue 
    else if i > 0 then 
    begin 
    buf[i] := #0; 
    request := request + buf; 
    if length(request) > BUFSIZE then break; // stop malicious request 
    end; 
until (gettickcount - start) > MAXWAIT; // could also stop if post body == content-length 
response := getresponse(ip, request); 
i := 1; j := length(response); 
while i <= j do 
    begin 
    k := BIO_write(io, @response[i], j-i+1); 
    if k <= 0 then 
    if BIO_should_retry(io) then continue 
    else break 
    else inc(i, k); 
    end; 
while BIO_flush(io) <= 0 do 
    if not BIO_should_retry(io) then break; 
SSL_set_shutdown(con, SSL_SENT_SHUTDOWN or SSL_RECEIVED_SHUTDOWN); // re-use session 
err: if io <> nil then BIO_free_all(io); // including ssl_bio 
end; 

var listen_socket: integer; 

procedure do_server; 
var server, client: TSockAddr; sock, clientlen: integer; 
begin 
listen_socket := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
confirm(listen_socket <> INVALID_SOCKET); 
fillchar(server, sizeof(server), 0); 
server.sin_family := AF_INET; 
server.sin_port := htons(DEFAULTPORT); 
server.sin_addr.s_addr := INADDR_ANY; 
confirm(bind(listen_socket, server, sizeof(server)) <> INVALID_SOCKET); 
confirm(listen(listen_socket, 128) <> INVALID_SOCKET); 
while TRUE do 
    begin 
    fillchar(client, sizeof(client), 0); 
    clientlen := sizeof(client); 
    sock := accept(listen_socket, @client, @clientlen); 
    if sock <> INVALID_SOCKET then 
    begin 
    read_and_respond(inet_ntoa(client.sin_addr), sock); 
    shutdown(sock, SD_BOTH); 
    closesocket(sock); 
    end; 
    end; 
end; 

procedure shutdownserver; 
begin 
closesocket(listen_socket); 
SSL_CTX_free(ctx); 
WSAcleanup; 
end; 

function consolehandler(signal: DWORD): BOOL; stdcall; 
begin // handle some console events 
case signal of 
    CTRL_C_EVENT, CTRL_BREAK_EVENT: result := TRUE; // handle these by ignoring them 
    CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, CTRL_SHUTDOWN_EVENT: 
    begin 
    shutdownserver; 
    result := FALSE; // avoid popup 
    end 
    else result := FALSE; // not handling 
    end; // case 
end; 

procedure main; 
var WData: TWSAData; 
begin 
allocconsole; 
confirm(SetConsoleCtrlHandler(@ConsoleHandler, TRUE)); 
if WSAStartup(MakeWord(2, 2), WData) <> 0 then 
    confirm(WSAStartup(MakeWord(1,1), WData) = 0); 
SSL_library_init; 
SSL_load_error_strings; 
OPENSSL_load_builtin_modules; 
ctx := SSL_CTX_new(SSLv23_server_method); confirm(ctx <> nil); 
confirm(SSL_CTX_use_certificate_chain_file(ctx, 'cert.pem') > 0); 
confirm(SSL_CTX_use_PrivateKey_file(ctx, 'key.pem', SSL_FILETYPE_PEM) > 0); 
confirm(SSL_CTX_check_private_key(ctx)); 
SSL_CTX_set_quiet_shutdown(ctx, 1); 
SSL_CTX_set_options(ctx, 0); 
repeat 
    try 
    do_server 
    except 
    on E: Exception do writeln(E.Message); 
    end; 
until FALSE; 
end; 

begin 
main 
end. 
관련 문제