RSS듀오랩스
모바일 앱

WWDR 중간 인증서: 코드 서명 신원이 0개로 나오는 이유

작성자
듀오랩스 대표·7분 읽기
$ security import dist-cert.p12 -k ~/Library/Keychains/login.keychain-db
1 identity imported.

$ security find-identity -v -p codesigning
     0 valid identities found

한 명령은 신원을 넣었다고 하고, 바로 다음 명령은 없다고 합니다. 같은 키체인을 봅니다.

.p12 가 반쪽이라는 처음 짐작

.p12 는 인증서와 개인키를 함께 담는 봉투입니다. 인증서만 들어 있는 파일도 만들 수 있고, 그런 파일로는 서명하지 못합니다. 그쪽을 먼저 의심했습니다.

비밀번호 없이도 확인할 수 있습니다. PKCS#12 는 내용물을 종류별로 "가방(bag)"에 담는데, 개인키는 pkcs8ShroudedKeyBag(OID 1.2.840.113549.1.12.10.1.2)에 들어갑니다. 그 OID 가 있는지만 보면 됩니다.

openssl asn1parse -inform DER -in dist-cert.p12 | grep '1.2.840.113549.1.12.10.1.2'

0건이 나왔습니다. 개인키가 없다고 결론 내렸습니다. 틀렸습니다.

없다는 결과와 못 본다는 결과의 차이

asn1parse 는 겉껍질만 풉니다. 가방들은 암호화된 OCTET STRING 안에 들어 있어서, 그 안쪽 OID 는 화면에 점 표기로 나오지 않습니다. 제 grep 은 없는 것을 확인한 게 아니라 볼 수 없는 곳을 본 것이었습니다.

바이트에서 직접 찾으니 답이 달랐습니다.

h=$(xxd -p dist-cert.p12 | tr -d '\n')
case "$h" in *2a864886f70d010c0a0102*) echo "개인키 있음" ;; esac

certBagpkcs8ShroudedKeyBag 이 둘 다 있었습니다. 파일은 멀쩡했습니다.

여기서 배운 것은 인증서와 상관이 없습니다. 무언가를 찾았는데 안 나왔을 때, 그게 "없다"인지 "내 방법이 못 본다"인지 먼저 갈라야 합니다. 개인키가 확실히 든 다른 파일에 같은 명령을 걸어 봤다면 1분 만에 알았을 일입니다.

-v 가 세는 것은 있는 것이 아니라 유효한 것

-v 를 빼고 다시 물었습니다.

$ security find-identity -p codesigning
  1) BED5EA33...C0A04410 "iPhone Distribution: ..."
     1 identities found

신원은 처음부터 들어와 있었습니다. -v 는 valid 의 v 이고, 여기서 valid 는 인증서가 신뢰하는 뿌리까지 이어지는가를 뜻합니다. 개인키가 제대로 붙어 있어도 그 길이 끊기면 0으로 셉니다.

혼자 서지 못하는 인증서

애플은 개발자 인증서를 루트에서 직접 발급하지 않습니다. Apple Root CA 가 WWDR 이라는 중간 CA 를 발급하고, 그 중간 CA 가 개발자 인증서를 발급합니다. 검증하는 쪽은 손에 든 인증서에서 시작해 발급자를 따라 올라가면서 자기가 아는 뿌리에 닿아야 합니다.

루트는 OS 에 들어 있습니다. 맨 아래 인증서는 방금 제가 넣었습니다. 가운데 한 칸은 아무도 넣어 주지 않습니다. 평소에 이게 보이지 않는 이유는 Xcode 나 클라우드 빌드가 대신 채워 주기 때문입니다. 그 바깥에서 처음 서명하려 할 때 드러납니다.

키체인에 WWDR 이 하나 있기는 했습니다.

키체인에 있던 것 우리 인증서가 요구하는 것
OU=Apple Worldwide Developer Relations OU=G3
2023년 2월 7일 만료 2030년 2월 20일 만료

3년 전에 죽은 인증서 하나가 남아 있었고, 필요한 세대는 없었습니다.

이름이 같아도 세대가 다르면 다른 인증서

Apple Worldwide Developer Relations Certification Authority 라는 이름은 두 인증서가 같이 씁니다. 구분은 OU 에 있습니다. 어느 것이 필요한지는 짐작하지 않고 발급자 필드를 그대로 읽으면 됩니다.

$ openssl x509 -inform DER -in cert.der -noout -issuer
issuer= /CN=Apple Worldwide Developer Relations Certification Authority/OU=G3/O=Apple Inc./C=US

애플이 공개 배포하므로 받아서 넣으면 됩니다.

curl -O https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer
security import AppleWWDRCAG3.cer -k ~/Library/Keychains/login.keychain-db

넣기 전에 한 가지만 봅니다. 받은 중간 인증서의 주체(subject)가 내 인증서의 발급자(issuer)와 문자열까지 같아야 합니다. 다르면 다른 세대를 받은 것입니다.

$ security find-identity -v -p codesigning
  1) BED5EA33...C0A04410 "iPhone Distribution: ..."
     1 valid identities found

verify-cert 는 통과, find-identity 는 0

중간에 헷갈린 대목이 있습니다. 같은 인증서를 두 도구에 물었더니 답이 달랐습니다.

$ security verify-cert -c cert.der -p codeSign
...certificate verification successful.

인증서 안에는 발급자를 어디서 받을 수 있는지가 적혀 있습니다. 이 인증서의 AIA 확장에는 http://certs.apple.com/wwdrg3.der 이 들어 있습니다. 시스템 신뢰 평가는 중간 인증서가 없으면 그 주소에서 가져와 길을 잇습니다. find-identity 는 그러지 않고 키체인 안에 있는 것만으로 잇습니다.

그래서 검증은 통과하는데 서명은 안 되는 상태가 생깁니다. 네트워크가 있는 기계에서 확인하고 없는 기계에서 빌드하면 같은 어긋남을 만납니다.

남은 것

이 확인은 클라우드 빌드를 떠나려고 서명 자료를 모으다 만난 것입니다. 그 준비에서 남은 다른 항목들은 따로 적었습니다.

만료된 옛 WWDR 을 지우려다 SecKeychainItemDelete: Write permissions error 로 실패했습니다. 급한 일은 아닙니다. G3 가 들어온 뒤로 체인이 이어지고 서명도 됩니다.

다만 만료된 중간 인증서가 남아 있으면 체인을 만들 때 그쪽을 먼저 집는 사례가 보고돼 있습니다. 나중에 서명이 다시 흔들리면 여기부터 보려고 적어 둡니다.

참고: Apple PKI

마지막 수정:

공유하실 때는 출처(Duolabs)와 원문 주소를 표시해 주세요.