1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <sys/socket.h>
5 #include <arpa/inet.h>
6 #include <netinet/in.h>
7 #include <sys/types.h>
8 #include <unistd.h>
9 #include <netdb.h>
10 #include <stdbool.h>
11 #include <strings.h>
12
13 #include <openssl/bio.h>
14 #include <openssl/err.h>
15 #include <openssl/rand.h>
16 #include <openssl/evp.h>
17 #include <openssl/crypto.h>
18 #include <openssl/ssl.h>
19 //#include <openssl/applink.c>
20
21
22 #define FILE_BUFSIZES 4096
23 #define PORT 9001
24 #define SERVER_ADDRESS "210.118.75.59"
25
26 // 서버 인증서와 개인키 파일 정의
27 #define CERT_FILE "rootcert.pem"
28 #define PRIVKEY_FILE "rootkey.pem"
29
30 #include "common.h"
31
32 // SSL 핸드쉐이크 메시지교환 과정을 알려주는 콜벡함수
33 void ssl_info_callback(const SSL *s, int where, int ret);
34 int recvn(SSL* ssl, char *buf, int len, int flags, struct sockaddr* addr, int* addrlen);
35 int SendFile(SSL* ssl, struct sockaddr* addr, int* addrlen );
36 int ReceiveFile(int Type, SSL* ssl, char* mf_fileName, int fm_fileSize);
37 int SendFile(int Type, SSL* ssl, char* fm_fileName, int fm_fileSize);
38 //DWORD Get_SendListFileSize(char* fm_Path);
39
40 // 화면에 표시 하기 위한 파일 BIO생성
41 BIO * errBIO;
42
43 typedef unsigned int SOCKET;
44
45 int main( void )
46 {
47
48 unsigned short port = PORT;
49 char * serverAddress = SERVER_ADDRESS;
50 // 서버의 소켓 타입은 TCP 같은 연결형이다.
51 int socket_type = SOCK_STREAM;
52 struct sockaddr_in server_add, client_add;
53 //SOCKET
54 int server_socket, client_socket;
55
56 socket_type = SOCK_STREAM;
57
58 // SSL 구조체 생성
59 SSL_METHOD *meth;
60 SSL_CTX* ctx;
61 SSL* ssl;
62
63 ///////////////////
64 // 파일 전송 관련 변수
65 int TotalFielSize;
66 int addrlen;
67 char filename[256];
68
69
70 ///////////////////
71
72 int retval;
73 /*
74 // 윈속 DLL을 초기화 하고, 소켓 버전 2.2를 사용 한다는 것을 알린다.
75 if ((retval = WSAStartup(0x202,&wsaData)) != 0) {
76 fprintf(stderr,"WSAStartup 함수에서 에러 발생.");
77 WSACleanup();
78 exit(1);
79 }
80 // 버전이 2.2가 아니면 종료한다.
81 if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 ) {
82 WSACleanup();
83 exit(1);
84 }
85 */
86 // 화면 출력 BIO생성
87 if ((errBIO=BIO_new(BIO_s_file())) != NULL)
88 BIO_set_fp(errBIO,stderr,BIO_NOCLOSE|BIO_FP_TEXT);
89
90 // 모든 에러 스트링 로드
91 SSL_load_error_strings();
92 // 모든 알고리즘 로드
93 SSLeay_add_ssl_algorithms();
94
95 // SSL 버전3 프로토콜 사용
96 meth = SSLv3_method();
97 // SSL 컨텍스트 생성
98 ctx = SSL_CTX_new(meth);
99 if (ctx==NULL) {
100 BIO_printf(errBIO,"SSL_CTX 생성 에러");
101 ERR_print_errors(errBIO);
102 exit(1);
103 }
104 // SSL 핸드쉐이크 메시지교환 과정을 알려주는 콜벡함수를 셋팅
105 SSL_CTX_set_info_callback(ctx,ssl_info_callback);
106 // 자신의 인증서를 파일에서 로딩한다.
107 if (SSL_CTX_use_certificate_file(ctx, CERT_FILE, SSL_FILETYPE_PEM) <= 0) {
108 ERR_print_errors(errBIO);
109 exit(1);
110 }
111 // 자신의 개인키를 파일에서 로딩한다.
112 if (SSL_CTX_use_PrivateKey_file(ctx, PRIVKEY_FILE, SSL_FILETYPE_PEM) <= 0) {
113 ERR_print_errors(errBIO);
114 exit(1);
115 }
116 // 읽은 인증서와 개인키가 맞는지 확인 한다.
117 if (!SSL_CTX_check_private_key(ctx)) {
118 BIO_printf(errBIO,"인증서와 개인키가 맞지 않습니다.\n");
119 ERR_print_errors(errBIO);
120 exit(1);
121 }
122
123 // 서버의 소켓 생성
124 server_socket = socket(PF_INET, socket_type, 0);
125 if(server_socket == -1)
126 {
127 printf("소켓생성 에러");
128 exit(1);
129 }
130
131 // sockaddr_in 구조체의 주소체계를 인터넷 주소체계로 한다.
132 server_add.sin_family = AF_INET;
133 // 서버의 주소를 인터넷32비트 주소로 변환하여 sockaddr_in에 넣는다.
134 server_add.sin_addr.s_addr = inet_addr(serverAddress);
135 // 네트워크 형식으로 포트번호를 변환 하여 sockaddr_in에 넣는다.
136 server_add.sin_port = htons(port);
137
138 // bind 를 실행 하여 서버 소켓과 서버 주소를 연결 한다.
139 retval = bind( server_socket, (struct sockaddr*)&server_add, sizeof(server_add) );
140 if (retval == -1 ) {
141 fprintf(stderr,"bind 에러");
142 // WSACleanup();
143 exit(1);
144 }
145 // listen 함수를 실행 하여 클라이언트가 접속 할 수 있는 최대 버퍼수를 5로 정한다.
146 retval = listen(server_socket,5);
147 if (retval == -1 ) {
148 fprintf(stderr,"listen 에러");
149 // WSACleanup();
150 exit(1);
151 }
152
153 printf("주소 %s , 포트 %d 에서 클라이언트의 연결 기다림.\n",serverAddress,port);
154
155 int client_addlen = sizeof(client_add);
156 // accept함수를 실행 하여 클라이언트로부터의 접속을 기다린다.
157 client_socket = accept( server_socket, (struct sockaddr*)&client_add, (socklen_t*)&client_addlen );
158 if (client_socket == -1 )
159 {
160 fprintf(stderr,"accept 에러");
161 //WSACleanup();
162 exit(1);
163 }
164 // 클라이언트로 부터의 접속, 연결
165 printf("클라이언트 연결, 주소: %s, 포트: %d\n",inet_ntoa(client_add.sin_addr),htons(client_add.sin_port)) ;
166
167 // SSL 구조체 생성
168 ssl = SSL_new (ctx);
169 if (ssl == NULL) {
170 BIO_printf(errBIO,"SSL 생성 에러");
171 ERR_print_errors(errBIO);
172 exit(1);
173 }
174 // 연결된 소켓과 SSL과의 연결
175 SSL_set_fd(ssl, client_socket);
176 // 가장 중요한 함수, 클라이언트와의 초기 협상과정, 즉 핸드쉐이크 과정을 수행
177 retval = SSL_accept(ssl);
178 if (retval == -1)
179 {
180 BIO_printf(errBIO,"SSL accept 에러");
181 ERR_print_errors(errBIO);
182 exit(1);
183 }
184 // 현재 클라이언트와 정의된 암호화 파라메터정보를 얻음
185 const char * currentChipher = SSL_CIPHER_get_name(SSL_get_current_cipher(ssl));
186 printf("SSL 연결, 사용 알고리즘 파라메터: [%s]\n",SSL_get_cipher(ssl));
187 printf("SSL 연결, 사용 알고리즘 파라메터: [%s]\n",currentChipher);
188
189
190 //////////////////////////////////////////////////////////////////////////
191 // 연결완료 통신시작.
192 //////////////////////////////////////////////////////////////////////////
193
194 //////////////////////////////////////////////////////////////////////////
195 // 파일 수신 - 컴파일할 정책 데이터를 받음
196 //////////////////////////////////////////////////////////////////////////
197 addrlen = sizeof (server_add);
198
199 // 파일 이름 받기
200 //ZeroMemory(filename, 256);
201 memset( filename, 0, sizeof(filename) );
202 /*
203 retval = recvn(ssl, filename, 256, 0, (SOCKADDR*) &server_add, &addrlen);
204 if(retval == SOCKET_ERROR)
205 {
206 printf("recv()");
207 close(client_socket);
208 }
209 printf("-> 받을 파일 이름: %s\n", filename);
210
211 // 파일 크기 받기
212 retval = recvn(ssl, (char *)&TotalFielSize, sizeof(TotalFielSize), 0, (SOCKADDR*) &server_add, &addrlen);
213 if(retval == SOCKET_ERROR)
214 {
215 printf("recv()");
216 close(client_socket);
217 }
218 printf("-> 받을 파일 크기: %d\n", TotalFielSize);
219 */
220 retval = SSL_read( ssl, filename, sizeof(filename) );
221 if(retval == SOCKET_ERROR)
222 {
223 printf("파일이름 수신에 실패했습니다.");
224 close(client_socket);
225 exit(1);
226 }
227 printf("->받은 파일 이름: %s\n", filename);
228
229 retval = SSL_read( ssl, (char *)&TotalFielSize, sizeof( int ) );
230 if(retval == SOCKET_ERROR)
231 {
232 printf("파일크기 수신에 실패했습니다.");
233 close(client_socket);
234 exit(1);
235 }
236 printf("->받은 파일 크기: %d\n", TotalFielSize);
237
238 // 파일 수신
239 ReceiveFile(0, ssl, filename, TotalFielSize );
240 //////////////////////////////////////////////////////////////////////////
241 // 정책 컴파일 루틴
242 //////////////////////////////////////////////////////////////////////////
243
244 // ....
245
246 //////////////////////////////////////////////////////////////////////////
247 // 파일 송신 - 컴파일한 정책 이미지를 전송
248 //////////////////////////////////////////////////////////////////////////
249
250 // 전송할 파일의 크기를 구함.
251 //TotalFielSize = Get_SendListFileSize( "log.txt" );
252 FILE* file_size;
253 file_size = fopen( "log.txt", "rb" );
254 if( file_size == NULL )
255 {
256 printf(" file open error ");
257 return 0;
258 }
259
260 fseek( file_size, 0, SEEK_END );
261 TotalFielSize = ftell( file_size );
262 fclose( file_size );
263
264
265 // 파일 이름 보내기
266 //ZeroMemory(filename, 256);
267 memset( filename, 0, sizeof(filename) );
268 retval = SSL_write (ssl, "log.txt", 256);
269 if(retval == SOCKET_ERROR) printf("send()");
270
271 // 파일 크기 보내기
272 retval = SSL_write (ssl, (char *)&TotalFielSize, sizeof(TotalFielSize));
273 if(retval == SOCKET_ERROR) printf("send()");
274
275 SendFile( 0, ssl, "log.txt", TotalFielSize );
276
277 // 연결 해제 및 객체 제거
278 printf("연결 해제\n");
279 close(client_socket);
280 SSL_free (ssl);
281 SSL_CTX_free (ctx);
282
283 system("pause");
284 return 0;
285 }
286
287 // SSL 핸드쉐이크 메시지교환 과정을 알려주는 콜벡함수
288 void ssl_info_callback(const SSL *s, int where, int ret)
289 {
290 char * writeString;
291 int w;
292 // 현재 어떤 메시지 교환 과정인지를 나타냄
293 w = where & ~SSL_ST_MASK;
294
295 // 클라이언트가 연결 했을 때
296 if (w & SSL_ST_CONNECT)
297 writeString="SSL_connect";
298 // 서버가 연결을 받았을 때
299 else if (w & SSL_ST_ACCEPT)
300 writeString="SSL_accept";
301 // 알 수 없는 경우
302 else
303 writeString="undefined";
304
305 // 일반적인 핸드쉐이크 프로토콜 메시지일 경우
306 if (where & SSL_CB_LOOP)
307 {
308 // SSL_state_string_long(s) 함수로 부터 현재 진행되는 메시지가 무엇인지 표시
309 BIO_printf(errBIO,"%s:%s\n",writeString,SSL_state_string_long(s));
310 }
311 else if (where & SSL_CB_ALERT)
312 { // alert 프로토콜일 경우
313 //writeString=(where & SSL_CB_READ)?"read":"write";
314 //BIO_printf(errBIO,"SSL3 alert %s:%s:%s\n",writeString,SSL_alert_type_string_long(ret),SSL_alert_desc_string_ long(ret));
315 }
316 else if (where & SSL_CB_EXIT)
317 { // 종료 과정일 경우
318 if (ret == 0)
319 BIO_printf(errBIO,"%s:failed in %s\n",writeString,SSL_state_string_long(s));
320 else if (ret < 0)
321 {
322 BIO_printf(errBIO,"%s:error in %s\n",writeString,SSL_state_string_long(s));
323 }
324 }
325 }
326
327 int SendFile(SSL* ssl, struct sockaddr* addr, int* addrlen )
328 {
329
330 return 0;
331 }
332
333 // 사용자 정의 데이터 수신 함수
334 int recvn(SSL* ssl, char *buf, int len, int flags, struct sockaddr* addr, int* addrlen)
335 {
336 int received;
337 char *ptr = buf;
338 int left = len;
339
340 while(left > 0){
341 received = SSL_read (ssl, ptr, left);
342 // received = recvfrom(s, ptr, left, flags, addr, addrlen);
343 if(received == SOCKET_ERROR)
344 return SOCKET_ERROR;
345 else if(received == 0)
346 break;
347 left -= received;
348 ptr += received;
349 }
350
351 return (len - left);
352 }
353
354 ////////////////////////////////////////////////////////
355 //
356 // Receive File
357 //
358 ////////////////////////////////////////////////////////
359 int ReceiveFile(int Type, SSL* ssl, char* mf_fileName, int fm_fileSize)
360 {
361 int retval;
362
363 struct sockaddr_in clientaddr;
364 int addrlen;
365 int nblock = 0, endblock, size;
366 char buf [FILE_BUFSIZES];
367
368 // 저장 경로 지정.
369 // CString S_Directory;
370 // S_Directory = Standard_Path + "\\certmanage\\policyserver\\embeddedcert\\";
371 // S_Directory += (CString)mf_fileName;
372
373 addrlen = sizeof(clientaddr);
374
375 while(1)
376 {
377 endblock = fm_fileSize / 4096;
378
379 // 파일 열기
380 FILE *fp = fopen( "log.txt", "wb");
381 if(fp == NULL){
382 perror("파일 입출력 오류");
383 SSL_free (ssl);
384 continue;
385 }
386
387 int numtotal = 0;
388
389 // 파일 데이터 받기
390 while (1)
391 {
392 if (nblock == endblock)
393 size = fm_fileSize % 4096;
394 else
395 size = 4096;
396 retval = recvn(ssl, (char*)&buf, size, 0, (struct sockaddr*) &clientaddr, &addrlen);
397 if (retval == SOCKET_ERROR)
398 {
399 break;
400 }
401 else if(retval == 0)
402 break;
403 else
404 {
405 int written = fwrite(buf, 1, size, fp);
406 if(ferror(fp))
407 {
408 printf("파일 입출력 오류");
409 break;
410 }
411 if (written != size)
412 {
413 printf("파일 입출력 오류");
414 break;
415 }
416
417 // Sleep(1000);
418 retval = SSL_write (ssl, (char*) &nblock, sizeof (int));
419 if (retval == SOCKET_ERROR)
420 {
421 // err_display ("sendto()");
422 break;
423 }
424 else if (retval == 0)
425 break;
426
427 nblock ++;
428 numtotal += size;
429 printf("%d ", nblock);
430
431 if (nblock > endblock)
432 break;
433 }
434 }
435 fclose(fp);
436
437 // 전송 결과 출력
438 if(numtotal == fm_fileSize)
439 {
440 printf(" 수신 성공 ");
441 return 1;
442 }
443 else
444 {
445 printf(" 수신 실패 ");
446 return -1;
447 }
448
449 break;
450 }
451 return 0;
452 }
453
454
455 ////////////////////////////////////////////////////////
456 //
457 // Send File - 사용.
458 //
459 ////////////////////////////////////////////////////////
460 int SendFile(int Type, SSL* ssl, char* fm_fileName, int fm_fileSize)
461 {
462 int retval;
463
464 // 파일 열기
465 FILE *fp = fopen( fm_fileName, "rb");
466 if(fp == NULL){
467 printf("파일 입출력 오류");
468 return -1;
469 }
470
471 // 파일 데이터 전송에 사용할 변수
472 char buf[FILE_BUFSIZES];
473 int numread;
474 int numtotal = 0;
475 int ack, nblock = 0, endblock = fm_fileSize / 4096, size;
476
477
478
479 // 파일 데이터 보내기
480 rewind(fp); // 파일 포인터를 제일 앞으로 이동
481 while(1){
482 if (nblock == endblock)
483 size = fm_fileSize % 4096;
484 else
485 size = 4096;
486
487 numread = fread(buf, 1, size, fp);
488
489 if(numread > 0)
490 {
491 retval = SSL_write (ssl, (char*) &buf, numread);
492 if(retval == SOCKET_ERROR){
493 printf("sendto()");
494 break;
495 }
496 retval = SSL_read (ssl, (char*) &ack, sizeof (int));
497 if (retval == SOCKET_ERROR)
498 {
499 printf("recvfrom()");
500 break;
501 }
502 if (ack == nblock)
503 {
504 nblock ++;
505 numtotal += numread;
506 printf ( "nblock = %d, numtotal = %d\n", nblock, numtotal );
507 }
508 }
509 else if(numread == 0 && numtotal == fm_fileSize)
510 {
511 break;
512 }
513 else{
514 break;
515 }
516 }
517 fclose(fp);
518
519 return 0;
520 }
|