일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- Swift 문법
- 데이터베이스 공부
- OS
- 네이버 부스트캠프
- ObservedObject
- 제앱소
- 애플 디벨로퍼 아카데미
- iOS 개발 오류
- 소프트웨어분석및설계
- 치지직
- global soop
- useReducer
- 네이버 치지직
- 애플 디벨로퍼 아카데미 후기
- Apple Developer Academy @ POSTECH
- 운영체제
- 애플 아카데미 후기
- react
- sqoop
- swift문법
- Swift 디자인패턴
- Swift 기능
- apple developer academy 후기
- 숭실대
- ObservableObject
- 데이터베이스
- SWIFT
- 애플 디벨로퍼 아카데미 21주차 회고
- 앱 비교 프로젝트
- StateObject
- Today
- Total
사과하는 제라스
16. Basic OpenSSL 본문
목차
- HTTP와 HTTPS의 차이 : TLS가 존재한다
- 대칭키 암호 알고리즘(Symmetric cipher)
: 암호화하는 송신자와 복호화하는 수신자는 동일한 키를 가지고 있어야 함.
- 공개키 암호 알고리즘(Asymmetric cipher or Public Key encryption Algorithm)
: 공개키와 개인키가 한쌍으로 존재하고 같지 않음.(수학적인 관계는 존재함.), 대칭키와 비교했을 때 속도는 느리나 키 교환 분야에서 활용가능.
공개키 crypto system
1) 암호화 하는 기술
2) 전자서명하는 기술
- 전자 서명
: 공개키 암호 알고리즘의 사용방법 중 하나임.
송신자의 개인키로 서명 : MSG -> MSG+Sign Value
수신자는 송신자의 공개키로 복호화하여 Sign Value확인.
이때 이 송신자의 공개키를 신뢰되게 알려주는 것이 PKI 이다.
- OpenSSL
: 오픈소스 라이브러리로서 Application에게 SSL/TLS서비스를 제공함.
OpenSSL을 하기 위해서 3가지 operation이 필요함.
SSL_library_init() : OpenSSL 라이브러리를 쓸 수 있도록 초기화 함.
OpenSSL_add_all_algorithm() : 사용할 알고리즘이 무엇인지 명시하기 힘들때 모든 가능한 알고리즘을 로드함.
SSL_load_error_strings() : 에러와 관련된 것들을 출력해 줌.(디버깅이 편해짐.)
일단, 위 3 operation들로 OpenSSL이 초기화되면 SSL context를 생성할 준비가 된 것임.
=> SSL_CTX_new() : SSL_CTX object를 만듦. 여기에 initial settings가 저장됨.
이건 connection동안 유지됨. ∴ connection 종료 시 메모리 할당 해제해야 함.
이 함수는 TLS_client_method()를 매개변수로 갖는데 이 함수는 TLS 메소드를 사용하기 위해서 쓰임.
이렇게 실행하면 ctx에 클라이언트가 자동적으로 가장 필요한 알고리즘과 그에 필요한 key를 세팅함.
=>
SSL_new() : SSL 객체를 만드는 함수. 만들어진 SSL 객체를 가지고서 SSL/TLS 통신을 트랙킹 가능함.
SSL_set_tlsext_host_name() : 접속하고자 하는 서버의 domain name 세팅하는 함수
SSL_set_fd() , SSL_connect() : 만든 TCP 소켓에 ssl 변수를 세팅하는 함수, 만든 SSL 객체를 이용해서 해당 서버에 커넥션을 만드는 함수
SSL_write(), SSL_read() : 데이터를 송수신할 때 쓰는 함수들
SSL_shutdown() : SSL 관련된 커넥션 변수들, ctx 변수들이 메모리에 계속 할당되어 있으면 메모리 누수 발생
=> SSL_free(), SSLCTX_free()를 해줘서 할당된 메모리를 해지함.
SSL_get_cipher() : ssl변수를 통해서 세팅했던 알고리즘 리스트를 모두 출력할 수 있음.
SSL_get_peer_certificate() : 접속한 서버의 인증서를 가져올 수 있고 이를 이용하여 만든 인증서 객체(ex) X509)에서 필요한 정보를 함수들을 이용하여 가져올 수 있음.
/*
* MIT License
*
* Copyright (c) 2018 Lewis Van Winkle
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <openssl/crypto.h> //SSL 관련 헤더들 선언됨.
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define ISVALIDSOCKET(s) ((s) >= 0)
#define CLOSESOCKET(s) close(s)
#define SOCKET int
#define GETSOCKETERRNO() (errno)
int main(int argc, char *argv[]) {
// SSL라이브러리 초기화하는 코드.
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
//SSL object를 관리할 수 있는 ctx.
SSL_CTX *ctx = SSL_CTX_new(TLS_client_method());
if (!ctx) {
fprintf(stderr, "SSL_CTX_new() failed.\n");
return 1;
}
//입력받은 argument로 hostname, port번호 받아옴.
if (argc < 3) {
fprintf(stderr, "usage: https_simple hostname port\n");
return 1;
}
char *hostname = argv[1];
char *port = argv[2];
//입력한 hostname을 통해 getaddrinfo로 ip주소 받아옴.
printf("Configuring remote address...\n");
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
struct addrinfo *peer_address;
if (getaddrinfo(hostname, port, &hints, &peer_address)) {
fprintf(stderr, "getaddrinfo() failed. (%d)\n", GETSOCKETERRNO());
exit(1);
}
//접속하고자 하는 서버에 대한 IP주소 출력.
printf("Remote address is: ");
char address_buffer[100];
char service_buffer[100];
getnameinfo(peer_address->ai_addr, peer_address->ai_addrlen,
address_buffer, sizeof(address_buffer),
service_buffer, sizeof(service_buffer),
NI_NUMERICHOST);
printf("%s %s\n", address_buffer, service_buffer);
//TCP 소켓 server 만듦
printf("Creating socket...\n");
SOCKET server;
server = socket(peer_address->ai_family,
peer_address->ai_socktype, peer_address->ai_protocol);
if (!ISVALIDSOCKET(server)) {
fprintf(stderr, "socket() failed. (%d)\n", GETSOCKETERRNO());
exit(1);
}
//TCP connection 진행.
printf("Connecting...\n");
if (connect(server,
peer_address->ai_addr, peer_address->ai_addrlen)) {
fprintf(stderr, "connect() failed. (%d)\n", GETSOCKETERRNO());
exit(1);
}
freeaddrinfo(peer_address);
printf("Connected.\n\n");
//SSL object 만들어서 초기화.
SSL *ssl = SSL_new(ctx);
if (!ctx) {
fprintf(stderr, "SSL_new() failed.\n");
return 1;
}
//접속하고자 하는 hostname을 설정해줌.
if (!SSL_set_tlsext_host_name(ssl, hostname)) {
fprintf(stderr, "SSL_set_tlsext_host_name() failed.\n");
ERR_print_errors_fp(stderr);
return 1;
}
//ssl 변수를 server 소켓에 세팅하고 SSL_connect()를 이용하여 ssl에 접근함.
SSL_set_fd(ssl, server);
if (SSL_connect(ssl) == -1) {
fprintf(stderr, "SSL_connect() failed.\n");
ERR_print_errors_fp(stderr);
return 1;
}
//어떤 알고리즘들이 쓰이는지 출력.
printf ("SSL/TLS using %s\n", SSL_get_cipher(ssl));
//cert라는 포인터에 원하는 것들을 세팅해서 출력가능.
X509 *cert = SSL_get_peer_certificate(ssl);
if (!cert) {
fprintf(stderr, "SSL_get_peer_certificate() failed.\n");
return 1;
}
char *tmp;
if ((tmp = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0))) {
printf("subject: %s\n", tmp);
OPENSSL_free(tmp);
}
if ((tmp = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0))) {
printf("issuer: %s\n", tmp);
OPENSSL_free(tmp);
}
X509_free(cert);
//HTTPS로 데이터를 보내기 위해서 데이터를 세팅함.
char buffer[2048];
sprintf(buffer, "GET / HTTP/1.1\r\n");
sprintf(buffer + strlen(buffer), "Host: %s:%s\r\n", hostname, port);
sprintf(buffer + strlen(buffer), "Connection: close\r\n");
sprintf(buffer + strlen(buffer), "User-Agent: https_simple\r\n");
sprintf(buffer + strlen(buffer), "\r\n");
//ssl 변수를 이용해서 SSL_write를 이용한 buffer값을 써주면 TCP 커넥션 위의 ssl 커넥션 위로 데이터가 오감.
//buffer가 모두 암호화되어서 전송됨.
SSL_write(ssl, buffer, strlen(buffer));
printf("Sent Headers:\n%s", buffer);
while(1) { //데이터를 받는 부분.
int bytes_received = SSL_read(ssl, buffer, sizeof(buffer));
if (bytes_received < 1) {
printf("\nConnection closed by peer.\n");
break;
}
//데이터를 받는 부분.
printf("Received (%d bytes): '%.*s'\n",
bytes_received, bytes_received, buffer);
} //end while(1)
printf("\nClosing socket...\n");
SSL_shutdown(ssl);
CLOSESOCKET(server);
SSL_free(ssl);
SSL_CTX_free(ctx);
printf("Finished.\n");
return 0;
}
----------------------------------------------------------------------------------------------------------------------
- TLS 서버를 만드려면 항상 인증서(Certificate)를 세팅해야 함.
- 인증서와 전자서명을 통해서 우리가 접속하고자 하는 서버를 인증함.
'대학 전공 공부 > 네트워크 프로그래밍' 카테고리의 다른 글
17. OpenSSL(TLS 서버 구축) (0) | 2022.06.09 |
---|---|
15. 네트워크 보안 (0) | 2022.06.08 |
14강. 보안 기본 개념 (0) | 2022.05.21 |
13강. HTTP and Web Client (0) | 2022.05.13 |
12강. DNS (0) | 2022.05.13 |