기본 콘텐츠로 건너뛰기

라벨이 openssl인 게시물 표시

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...

OpenSSL supports Multi-threading

내가 스레드를 별로 좋아하지 않는데, 별 수 없이 써야할 경우가 종종 있다. 그와 별개로 OpenSSL 쓰기를 좋아하는데, OpenSSL을 멀티 스레딩 환경에서 쓰면 자칫 알 수 없는 이유로 죽곤한다. 이유는 OpenSSL 각종 알고리즘엔진이 멀티 스레딩 환경을 고려하지 않은 엔진이라, 경합이 발생하여 충돌이 발생하기 때문이다. 참조: https://www.openssl.org/docs/crypto/threads.html 멀티 스레딩 지원은 0.9.5b-dev부터 지원하였으니, 이하 버전은 포기하자. (응?) (사실 그 전에도 약간은 지원했으나, CentOS5 기준 0.9.8이니, 이전 버전은 포기하는게 정답이다) 맨페이지를 보면 "crypto/threads/mttest.c 파일에 예제가 있어요 뿌잉뿌잉~"이라는데 나중에 찾아보기 귀찮으니 블로그에 옮겨 놓...으려고 봤는데, 주석도 길고 모든 OS에 대한 전처리기도 있고, C++11도 나왔는데 구닥다리 코드를 쓸 생각이 없으니 내 맘대로 다시 구성했다. #include <openssl/crypto.h> #define OPENSSL_THREAD_DEFINES #include <openssl/opensslconf.h> #if !defined(OPENSSL_THREADS) # error "OpenSSL version is not supported multi-thread" #endif // C++11 mutex support #include <mutex> // Global locks for OpenSSL static std::mutex* g_locks(nullptr); // Locking callback function for OpenSSL static void funcLock(int mode, int type, char* file, int line) { if ( mode bitand CRYPTO_LOCK ) g_locks[...

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"를 사용할 수 있다.

OpenSSL 까보기 - EVP I/F에서 알고리즘 별 명세표는 어떻게 정의해놨나?

Block cipher를 Provider pattern으로 예쁘게 감싼 OpenSSL의 EVP interface를 쓰다가, 각 Cipher algorithm마다 Key, IV, Block 크기를 정해놨을껀데 어떻게 넣었을까 싶어서 소스를 까봤다. 사용 소스는 openssl-1.0.0-beta4 이다. 쉽게 찾기 위해 만만돌이 3DES를 찾아 가보자. 3DES 구현은 openssl/crypto/evp/e_des3.c에 구현하였다. 구현 방식 별로 함수를 만들고 BLOCK_CIPHER_defs라는 것에 항목을 일일이 상수로 넣었다. //...openssl/crypto/evp/e_des3.c 일부... BLOCK_CIPHER_defs(des_ede, DES_EDE_KEY, NID_des_ede, 8, 16, 8, 64, EVP_CIPH_RAND_KEY, des_ede_init_key, NULL, EVP_CIPHER_set_asn1_iv, EVP_CIPHER_get_asn1_iv, des3_ctrl) BLOCK_CIPHER는 openssl/crypto/evp/evp_locl.h 함수에 구현한 매크로함수이다. 하는 일은 다른 매크로를 사용하지만, 최종 목적은 해당 알고리즘 명세표를 구조체 인스턴스를 하나 만들어 초기화하는 것이다. //...openssl/crypto/evp/evp_locl.h 일부... #define BLOCK_CIPHER_defs(cname, kstruct, \ nid, block_size, key_len, iv_len, cbits, flags, \ init_key, cleanup, set_asn1, get_asn1, ctrl) \ BLOCK_CIPHER_def_cbc(cname, kstruct, nid, block_size, key_len, iv_len, flags, \ ini...