기본 콘텐츠로 건너뛰기

글

라벨이 ssl인 게시물 표시

Google 서비스 계정 액세스토큰을 C/C++로 얻어내기

OAuth2에서 인증을 흔히 3단계 과정으로 얻어내는데, 이것을 "three-legged OAuth(줄여서 3LO)"라고 한다. 여기에서 반드시 사람이 OAuth를 제공하는 측 인증화면에 인증질을 하는게 보통이다. 그러나 서비스를 개발하면서 자동인증이 필요할 때가 있다. 서비스 감사 등의 부분에서 말이다. 이때 구글 OAuth2는 2LO를 지원한다. 단, 특수 계정이 필요하고, 지원 API가 한정적이다. (보안이슈 등) 참조:  Using OAuth 2.0 for Server to Server Applications 위 문서에서 다른 건 필요 없고, 개발 콘솔에서 <서비스 계정>을 생성하고, P12(PKCS#12) 파일을 다운로드 받아놓는 것에 주목하자. 문서에 보면 OAuth 주소 어찌고 저찌고... 요청응답 순서는 이렇지만, 그러지 말고 구글에서 미리 만들어놓은 클라이언트 라이브러리 가져다 써라 어쩌라 되어 있다. 좋다. 구글은 미리 예쁘게 Java, Python, PHP 등으로 클라이언트 라이브러리를 짜놨다. 하지만 C/C++은 없더라. 그래서 구글이 만들어놓은 PHP 클라이언트 라이브러리 소스 뜯어 보면서 액세스 토큰을 C/C++로 얻어내보았다. 사용라이브러리는 아래와 같다. OpenSSL >= 1.0.0 : http://openssl.org JsonCpp:  https://github.com/open-source-parsers/jsoncpp cURL:  http://curl.haxx.se 그러나 예제 소스에는 거의 의사코드 수준으로만... ㅋㅋㅋ Google OAuth2에 서비스 계정을 만드려면, JWT(Json Web Token, 발음 주의: 좃)이라는 포맷으로 요청을 해야한다. JWT 참조:  http://jwt.io/ (여기에서도 C/C++ 라이브러리는 찾아 볼 수가 없다) 영어 다시 해석하려면 어려우니까 미리 말을 남겨놔야겠다. ㅋㅋ...

EVP_DigestSign/Verify 예제

비대칭 알고리즘을 이용하여, 사인/검증 하는 API를 OpenSSL 1.0.0부터 쓸 수 있다. 문제는 아직 예쁜 예제가 없다는 것. 그래서 낑낑끙끙 하며 만들어 봤다. #include <openssl/rsa.h> #include <openssl/evp.h> #include <iostream> using namespace std; void testSignVerify(void) { EVP_PKEY* pkey(/* 이미 만들어놓은 키 */); char src[] = "Hello, world!"; unsigned char sign[1024] = {0x00}; size_t signlen(sizeof(sign)); do { EVP_MD_CTX md; EVP_MD_CTX_init(&md); if ( EVP_DigestSignInit(&md, nullptr, EVP_sha256(), nullptr, pkey) <= 0 ) { cerr << "EVP_DigestSignInit" << endl; break; } if ( EVP_DigestSignUpdate(&md, src, strlen(src)) <= 0 ) { cerr << "EVP_DigestSignUpdate" << endl; break; } if ( EVP_DigestSignFinal(&md, sign, &signlen) <= 0 ) { cerr << "EVP_DigestSignFinal" << endl; break; } cerr << "Sign: "; PWEnc::encodeHex(cerr, sign, signlen) << endl; EVP_MD...

Apple's APNS drops SSLv3 with Poodle bug

아침부터 개발하고 있는 서비스가 난리법석이다. 고친 것도 없고, 어뷰징도 딱히 보이지 않았는데, Apple 푸쉬서비스 APNS에서 자꾸 끊긴다. 아름답게도 접속은 잘 하는데, SSL_read/write할 때 매번 접속이 끊긴다. 그래서 무한 재접속... 지금은 개발하고 있는 서비스 이슈를 해결하긴 했지만, 최근 OpenSSL SSLv3 Poodle 버그로 이 바닥이 난리난 적이 있다. 딱히 패치는 나오지 않고 SSLv3를 제거하라는 가이드만 나와 있는 상황인데, Apple이 오늘 아침에 그걸 적용한 듯 싶다. 접속 유지하고 있던 커넥션이 끊기고 다시 붙으면 Handshake과정에서 끊기는게 아니라 read/write할 때 끊겨서 더욱 찾기 애매했다. 그리고 뒤늦게 찾은 Apple의 공지사항:  https://developer.apple.com/news/?id=10222014a

PKCS12을 PEM으로 암호 없이 변환하기

인증서나 개인키 등을 담는 파일포맷인 PKCS12(*p12)를 openssl에서 자주 쓰이는 파일포맷인 PEM으로 변환할 때, 개인키 암호화를 위해 암호입력을 받는다. 물론 암호를 입력하는 것이 보안에 조금이나마 낫지만, 크게 이슈가 없는 것이라면 그냥 암호 없이 쓸 수도 있다. $ openssl pkcs12 -in [INPUT_FILE.p12] -out [OUTPUT_FILE.pem] -nodes 필요에 따라 인증서만 내보낼 때는 "-nokeys", 개인키만 내보낼 때는 "-nocerts"를 사용할 수 있다.

Self-signed Certificate CMakeLists.txt

CMake의 Source와 Build를 나누겠다는 철학을 받아 전에 만든 CMakeLists.txt를 변경하였다. 이전버전 cmake_minimum_required(VERSION 2.8) project(myproject_certs) set(CERT_TARGET myproject_certs) add_custom_command(OUTPUT privatekey.key COMMAND openssl genrsa -passout pass:1111 -des3 -out privatekey.key 1024 2> /dev/null COMMENT "${CERT_TARGET}: Generating privatekey" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) add_custom_command(OUTPUT privatekey.pem COMMAND openssl rsa -passin pass:1111 -in ${CMAKE_CURRENT_BINARY_DIR}/privatekey.key -out ${CMAKE_CURRENT_BINARY_DIR}/privatekey.pem 2> /dev/null COMMENT "${CERT_TARGET}: Convert privatekey to PEM style" DEPENDS privatekey.key WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) add_custom_command(OUTPUT certificate.pem COMMAND openssl req -batch -utf8 -new -x509 -nodes -sha1 -days 365 -key ${CMAKE_CURRENT_BINARY_DIR}/privatekey.pem -out ${CMAKE_CURRENT_BINARY_DIR}/certificate.pem 2> /dev/null COMMENT "${CERT_TARGET}: G...

Self-signed Certificate Makefile(CMake)

매번 self-signed 인증서 만들기 귀찮고 해서 Makefile로 만들어 보았다. Makefile: TARGETS=certificate.pem privatekey.pem intermediate.pem privatekey.key all: $(TARGETS) clean: $(RM) $(TARGETS) privatekey.key: openssl genrsa -passout pass:1111 -des3 -out $@ 1024 privatekey.pem:privatekey.key openssl rsa -passin pass:1111 -in $< -out $@ certificate.pem:privatekey.pem openssl req -batch -utf8 -new -x509 -nodes -sha1 -days 365 -key privatekey.pem -out $@ intermediate.pem:certificate.pem cp $< $@ 약간 응용해서 CMake 버전도 만들어 보았다. CMakeLists.txt: cmake_minimum_required(VERSION 2.8) project(certs) add_custom_command(OUTPUT privatekey.key COMMAND openssl genrsa -passout pass:1111 -des3 -out privatekey.key 1024 COMMENT "Generating privatekey" ) add_custom_command(OUTPUT privatekey.pem COMMAND openssl rsa -passin pass:1111 -in privatekey.key -out privatekey.pem COMMENT "Convert privatekey to PEM style" DEPENDS privatekey.key ) add_custom_co...

Microsoft Crypto Library Endian Problem

Note that if we were using the Win32 API, we would retrieve a PUBLICKEYBLOB (or PRIVATEKEYBLOB) which would house the public or private key blob. The Win32 blob would be in Little Endian order, which we would later have to convert to Big Endian. When we access the RSAParameters using C#, it is returned in Big Endian format so we do not need to reverse the byte ordering before serialization. 출처: http://www.codeproject.com/KB/security/CryptoInteropKeys.aspx OpenSSL에서 보낸(export) RSAPublicKey를 MS CAPI로 받아(import) 암호화한 데이터를 OpenSSL에서 풀 수 없는 일이 발생하였다. 회사 분 도움(그분도 5년 전에 같은 골머리를 썩힌 적이 있다고)으로 MS CAPI에서 RSA연산할 때, Big Integer를 Little Endian으로 놓고 계산하므로 CAPI와 다른 라이브러리 사이에서 암호화/복화화를 할 때는 결과값을 반전해서 처리하도록 하자. 역시 경험과 문서화가 중요하다. * 추신: C#은 제대로 Big Endian으로 계산한다. * 추신2: MS가 첫 단추를 잘못 끼우긴 했지만, 이미 많은 윈도우 어플이 해당 상황을 고려햐서 만들었기 때문에 이제 와서 MS에서 함부러 고치는 것도 무리일 듯 하다. 원본 위치: http://purewell.egloos.com/5036207

Java에서 클라이언트 인증받는 TLS/SSL 연결 만들기

열심히 OpenSSL 소스 까보면서 공부해서 Java로(??!) 소켓 연결 맺기 해보는 중이다... 물론 Java에서 SSLSocketFactory에서 SSLSocket을 만들어 Buffer 연결하고 깔작거리면 얼마나 좋으련만, 세상이 녹록치 않더라. TLS/SSL은 클라이언트가 서버를 인증하는 것도 있지만, 서버가 클라이언트 인증을 필요로 할 때도 있다. 그래서 이땐 클라이언트가 사전에 서버쪽이랑 깔짝거려서 발급받은 인증서를 미리 쥐고 있다가, 서버에 접속(정확히는 접속해서 Handshake과정에서)할 때 넘겨줘야한다. SSLSocketFactory에서 그냥 깔짝깔짝 하는 걸로는 어림 반푼어치가 없더라고... SSLSocket부터 올라가보니, SSLContext라는 익숙한 놈이 있고, 이놈을 만들려면 KeyManagerFactory가 있어야 하고 TrustManagerFactory도 있어야 하는데, 각각은 KeyStore를 필요로 하고, KeyStore는 PKCS12 인증서를 필요로 하더라... 학학학 일단 잡다한 소리 집어치우고, 암호 설정한 PKCS12 인증서를 준비하자. 참고로 암호 안 걸리면 인증서 읽다가 널뽀인따 맞고 죽더라. 인증서 내보내기(export)할 때 꼭 6자 이상 암호 걸어서 내보내자. 순서는 아래와 같다. KeyStore 객체를 PKCS12 알고리즘으로 생성하고, 준비한 인증서 파일을 읽는다. KeyManagerFactory 객체를 SunX509 알고리즘으로 생성하고, 1에서 만들어진 KeyStore로 초기화한다. TrustManagerFactory 객체를 SunX509 알고리즘으로 생성하고, 1에서 만들어진 KeyStore로 초기화한다. SSLContext를 TLS 알고리즘(또는 필요에 따라 다른 것도 가능)으로 생성하고, 2, 3에서 만들어진 KeyManagerFactory와 TrustManagerFactory를 통해 만든 KeyManager[]와 TrustManager[]로 초기화한다. S...

Wireshark에서 TLS/SSL 까보기

TLS/SSL 작업을 할 때 갑갑한 것 중에 하나가 - 당연하겠지만 - 트래픽 내용을 볼 수 없다는 것이다. 기껏 볼 수 있는 정보는 인증서를 포함한 몇몇 보여도 상관 없는 인증 과정 중에 일부분이다. 물론  NULL cipher 를 서버와 클라이언트 모두 우선순위로 지원하도록 설정한다면, 인증이 끝난 뒤에도 트래픽을 볼 수 있지만, 그것도 최초 개발시기 이야기 . 배포 바로 전에 QA하기 위한 클라이언트를 수정할 수는 없지 않은가. 클라이언트 수정 없이 패킷만 덤프해서 볼 수 있으면 얼마나 좋을까... 만약 서버측 PrivateKey를 알고 있다면, 트래픽을 까서 볼 수 있다. ( 이래서 PrivateKey 관리가 중요하다. ) ssldump 라는 유틸리티도 있지만, GUI를 깔꼼하게 사용할 수 있는 Wireshark 에도 TLS/SSL을 까서 볼 수 있는 기능을 제공한다. 일단 Wireshark는 암호가 걸리지 않은 PEM규격 PrivateKey 만 읽을 수 있으니, 암호가 걸린 PrivateKey를 변환해서 보도록 하자. 변환 방법은 공식위키 사이트 를 애용해보자. (추측컨데 TLS/SSL 네고과정을 PrivateKey를 이용해서 SessionKey를 비롯한 패킷을 깔 때 필요한 정보를 얻어내어 덤프한 것을 바로 까서 보여주는 듯 하다. Proxy/MITM attack을 예상했는데, 그건 아닌 듯.) 키를 준비했다면, Edit-Preference를 들어가자. 왼쪽에 Protocol 트리가 보일 것이고, 거기에서 SSL을 선택하자. 여기서부터 중요한데, 이 부분이 Wireshark에서 불편한 부분이다. Wireshark에서 이 부분을 살짝 수정해준다면 좋으련만... 오른쪽 속성창에 RSA key list 항목이 보일 것이고, 그곳에 아래와 같은 형식으로 내용을 채워넣으면 패킷을 까볼 수 있다. <IP>,<PORT>,<PROTOCOL>,<KEY_FILE_PATH>;<반복> IP, ...

OpenSSL을 비동기 소켓에 적용하기 - 세션 맺기

SSL을 처음부터 구현하는 것은 결코 쉽지 않다. 각종 형식과 암호 알고리즘을 이해하고 짜더라도 검증은 누가 할 것인가! 그래서 이미 많은 선지자가 SSL 라이브러리를 잘 만들어 놓았다. 그 가운데 POSIX 시스템에서 자주 쓰이는 OpenSSL 이 있다. 어지간한 오픈소스로 유지하는 POSIX 시스템에서 기본 패키지로 사용할 정도로 매우 유용하고 검증 또한 잘 되어 있다. 아~ 이것만 갖다 쓰면 만사 오케이로구나!!...라고 생각했는데, 그것은 나의 착각. Layer 라이브러리답게 모든걸 추상화 해놓고 대부분 자동화... 게다가 처음에 SSL 세션 맺는 과정(handshake)에서 "SSL_connect/SSL_accept만 쓰세염~ 데헷~♡" 이라고만 쓰여 있다. SSL 세션을 맺는 과정을 잠깐 살펴보자. 아잉... 화살표가 도대체 몇개여... 대충 간추리면, SSL 쓸꺼라고 서로 인사하고(1, 2), 서버에서 공개키 내려주고(4), 클라이언트에서 사용할 암호키를 공개키로 암호화 해서 보내고(8), 서버에서 그거 풀어서 암호키를 얻어내면(13) 그 다음부터는 암호키로 암호화 해서 데이터를 전송(14, 15)한다. 대충 간추려도 저런 작업이고, 세션마다 프로세스를 할당해주는 방식이 아니라면, 보통 비동기 소켓을 열어서 이벤트(select, epoll, kqueue 등을 통해)가 있을 때마다 상태값에 따라 행동을 분기해야할텐데 OpenSSL에서는 "SSL_connect/SSL_accept만 쓰세염~ 데헷~♡" 이라고만 써 있는데... 아쒸... 물론 OpenSSL에서 저 Handshake 과정을 따로따로 구현할 수는 있다. 그런데 소스 까보니까 그것도 사람이 할 짓은 아닌 것 같더라. (급 나약해지게 만드는 수 많은 case문...) 그렇다고 SSL을 포기할 것인가? 그렇지 않다. 레퍼런스에 있는대로 SSL_connect/SSL_accept만 쓰면 해결할 수 있다. 두 함수는 비동기 소켓에 대해 오류를 반환할 때, SSL...

FreeBSD SSL 컴파일

$ g++ ssltest.cpp -o ssltest -lssl /usr/lib/libssl.so: undefined reference to `BIO_find_type' /usr/lib/libssl.so: undefined reference to `EVP_enc_null' /usr/lib/libssl.so: undefined reference to `EVP_CIPHER_CTX_init' ... Linux에선 ssl 만 링크해도 괜찮은데, FreeBSD에선 crypto 도 링크해야 한다. orz OTL 원본 위치: http://purewell.egloos.com/3863211