Push Notification 발송을 위한 작업은 매우 까다로운 부분인것 같습니다. 생각만큼 쉽게 되지도 않고 APNS서버측에서 날라오는 오류들은 하나같이 무엇이 문제인지 판단을 내리기가 쉽지 않습니다.
그중에 하나인 Verify return code: 20 (unable to get local issuer certificate) 오류를 수정하는 방법에 대해서 정리해 보겠습니다. 우선적으로 이 문제는 대부분 인증서가 잘못되었거나 발송하는 서버의 루트 인증서가 없거나 혹은 디렉토리 설정등에 문제가 있을 경우입니다.
방확벽 확인
방화벽 설정에 막혀 APNS서버에 접속하지 못하는 경우가 있습니다. 이 경우 우선적으로 방화벽에 막히는것인지 확인이 필요합니다. 다음과 같이 접속을 시도하여 다음과 같이 나온다면(접속이 된다면) 방화벽 문제는 아닌것입니다.
$ telnet gateway.push.apple.com 2195 Trying 17.149.35.167... Connected to gateway.push-apple.com.akadns.net. Escape character is '^]'.
정상적으로 PEM인증서를 생성했는지 확인
다음과 같은 방법으로 인증서를 생성하였는지 확인합니다. 다른 방법으로 하셨다면 다음의 방법을 추천합니다.
- [iPhone Developer Program Portal]에 로그인합니다.
- App IDs 메뉴에 들어간 후 새로운 App ID를 생성합니다. 이때에 와일드카드(*)를 사용하면 안됩니다. 예) 3L223ZX9Y3.kr.pe.theeye.pushsample
- 새로 생성된 App ID의 Configure 링크를 클릭하여 Development/Production Push SSL Certificate를 생성하는 마법사를 구동합니다. 참고: [LINK]
- 위의 과정을 거쳐 생성된 인증서(aps_developer_identity.cer)를 다운받아 더블클릭을 하여 키체인에 추가해 줍니다.
- 키체인 접근(Keychain Assistant)를 실행하여 왼쪽에 보이는 내 인증서(My Certificates)를 선택합니다. (1)
- Apple Development/Production IOS Push Service 의 왼쪽에 화살표를 클릭하여 확장후에 이 푸시 인증서와 확장하여 나타난 개인키를 함께 선택합니다. (2)
- 마우스 오른쪽 클릭후에 “2개 항목 보내기(Export 2 elements…)”를 눌러 p12형태의 인증서로 저장을 합니다. 저장시에 비밀번호를 물어오는데 비밀번호 없이 그냥 엔터를 쳐야 합니다.
- 터미널(Terminal)을 실행하여 방금 저장한 인증서가 있는 위치로 이동하여 다음의 명령을 실행합니다. (apns_certificate.p12 라고 가정)
$ openssl pkcs12 -in apns_certificate.p12 -out apns_certificate.pem -nodes -clcerts
인증서가 정상인지 확인
다음과 같은 명령을 사용하여 해당 인증서를 이용하여 현재의 서버 환경에서 정상적으로 푸시를 발송할 수 있는지 여부를 확인할 수 있습니다. 다음의 예시는 Production용 서버에 접속할 경우의 예시이며 Development환경에서는 gateway.sandbox.push.apple.com으로 접속하시면 됩니다.
$ openssl s_client -connect gateway.push.apple.com:2195 -cert apns_certificate.pem CONNECTED(00000003) depth=1 /C=US/O=Entrust, Inc./OU=www.entrust.net/rpa is incorporated by reference/OU=(c) 2009 Entrust, Inc./CN=Entrust Certification Authority - L1C verify error:num=20:unable to get local issuer certificate verify return:0
위와 같은 오류가 발생하는 것을 확인할 수 있습니다. 현재 확인한 결과 위의 메시지는 특정한 서버환경에서만 발생하는것으로 추측되고 있습니다.
외부 ROOT인증서를 이용하여 문제 해결
다음의 Root CA 인증서를 다운받아 서버의 적절한 위치에 두도록 합니다. 이제 이 인증서를 사용하여 다시한번 테스트를 해보도록 하겠습니다. [인증서다운로드]
$ openssl s_client -connect gateway.push.apple.com:2195 -cert apns_certificate.pem -CAfile entrust_2048_ca.cer CONNECTED(00000003) depth=2 /O=Entrust.net/OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/OU=(c) 1999 Entrust.net Limited/CN=Entrust.net Certification Authority (2048) verify return:1 depth=1 /C=US/O=Entrust, Inc./OU=www.entrust.net/rpa is incorporated by reference/OU=(c) 2009 Entrust, Inc./CN=Entrust Certification Authority - L1C verify return:1 depth=0 /C=US/ST=California/L=Cupertino/O=Apple Inc./OU=iTMS Engineering/CN=gateway.push.apple.com verify return:1 --- Certificate chain 0 s:/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=iTMS Engineering/CN=gateway.push.apple.com i:/C=US/O=Entrust, Inc./OU=www.entrust.net/rpa is incorporated by reference/OU=(c) 2009 Entrust, Inc./CN=Entrust Certification Authority - L1C 1 s:/C=US/O=Entrust, Inc./OU=www.entrust.net/rpa is incorporated by reference/OU=(c) 2009 Entrust, Inc./CN=Entrust Certification Authority - L1C i:/O=Entrust.net/OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/OU=(c) 1999 Entrust.net Limited/CN=Entrust.net Certification Authority (2048)
문제 없이 잘 되는것을 확인하였습니다. 여기서 문제가 없다면 인증서는 더이상 의심하지 않으셔도 됩니다. PHP코드상에서 CA Root 인증서를 따로 지정하려면 다음의 코드를 사용하시면 됩니다.
stream_context_set_option($ctx, 'ssl', 'cafile', 'entrust_2048_ca.cer');
참고자료
http://code.google.com/p/apns-php/wiki/CertificateCreation#Verify_peer_using_Entrust_Root_Certification_Authority
http://stackoverflow.com/questions/10585283/apns-sandbox-connection-failed-error-0-in-php-file
https://www.entrust.net/downloads/root_request.cfm