PKCS#12 키스토어 분석기
`openssl pkcs12 -info`가 하는 일을 바이트 단위로 그대로 재현하되 전부 브라우저 안에서 처리합니다. 파일의 절반은 비밀번호 없이도 읽히며, 그 절반을 먼저 보여줍니다. PFX 버전, MAC 다이제스트와 반복 횟수·솔트 길이, 그리고 콘텐츠 블록마다 평문인지 암호화되어 있는지와 어떤 알고리즘인지가 표로 나옵니다. OpenSSL 3이 쓴 파일이면 PBES2·AES-256-CBC·PBKDF2-HMAC-SHA256이고, Java 21이나 최신 OpenSSL이 아예 거부하는 파일이면 pbeWithSHA1And40BitRC2-CBC 같은 값이 보입니다. 대개 이 한 줄이 궁금증의 전부입니다. 비밀번호를 넣으면 RFC 7292 부록 B의 PKCS#12 키 유도(PBKDF2가 아닙니다)로 MAC을 검증한 뒤 가방을 복호화해, 인증서마다 주체·발급자·일련번호·유효 기간·SAN·키 알고리즘·SHA-256 지문을 리프부터 체인 순서로 보여주고 friendlyName과 localKeyID도 함께 나열합니다. 그리고 사람들이 키스토어를 여는 진짜 이유에 답합니다. 개인 키가 들어 있는가, 그 키가 리프 인증서의 키인가. 개인 키에서 공개 키를 복원해 인증서의 SubjectPublicKeyInfo와 바이트 단위로 비교하므로 별칭이 같다는 이유로 추측하지 않습니다. 다만 RC2·RC4·DES·3DES는 WebCrypto에 없어 구형 파일은 복호화하지 못하고 구형이라고 분명히 알려줍니다. 이때도 MAC 검증은 되므로 비밀번호가 맞는지는 알 수 있습니다. 또한 신뢰 저장소와 대조하지 않으므로 알 수 없는 루트로 끝나는 체인과 정상 체인은 구분되지 않습니다.
사용법
- .p12 또는 .pfx 파일을 상자에 놓습니다. 비밀번호 없이도 MAC 알고리즘, 반복 횟수, 각 블록을 보호하는 암호 알고리즘이 바로 표시됩니다.
- 가져오기 실패를 조사하는 중이라면 블록 표부터 보세요. pbeWithSHA1And40BitRC2-CBC나 3-KeyTripleDES가 보이면 구형 키스토어이고, 그것이 Java 21·OpenSSL 3·Windows가 거부하는 이유입니다.
- 비밀번호를 입력하고 열기를 누릅니다. MAC 줄이 비밀번호가 맞는지, 파일이 작성 이후 변조되었는지를 한 번에 알려줍니다.
- "키와 인증서" 칩을 확인하세요. 개인 키에서 복원한 공개 키를 리프 인증서의 공개 키와 비교하므로, 이 키스토어로 TLS를 서비스할 수 있는지 실제로 검증됩니다.
- 인증서는 리프가 먼저, 그 위로 발급자 순서로 나옵니다. 중간 인증서가 빠져 있으면 방문 이력이 있는 브라우저에서만 되고 다른 곳에서는 실패하는 전형적인 증상이 됩니다.
자주 묻는 질문
- 왜 비밀번호를 넣기 전에 알고리즘과 MAC이 보이나요?
- 그 부분은 암호화 대상이 아니기 때문입니다. PFX는 버전 번호, authenticated safe, MacData로 이루어지고 safe는 콘텐츠 블록의 목록입니다. 각 블록은 평문 SafeContents이거나 PKCS#7 EncryptedData이며, 후자의 AlgorithmIdentifier에는 암호 알고리즘·솔트·반복 횟수가 평문으로 들어 있습니다. 보호되는 것은 가방 안의 내용뿐입니다. 그래서 비밀번호를 몰라도 이 파일이 구형 RC2 키스토어인지, 반복 횟수가 얼마나 약한지, 블록이 몇 개인지 알 수 있고, 반대로 비밀번호가 걸려 있다는 이유만으로 .p12를 불투명한 파일로 취급해서는 안 됩니다.
- 구형 알고리즘이라고 나오는데 무엇을 해야 하나요?
- OpenSSL로 한 번 변환하면 됩니다. `openssl pkcs12 -legacy -in old.p12 -nodes -out tmp.pem -passin pass:…`로 읽은 뒤 `openssl pkcs12 -export -in tmp.pem -out new.p12`로 다시 내보내면 OpenSSL 3 기본값인 PBES2·AES-256-CBC·PBKDF2-HMAC-SHA256으로 저장됩니다. tmp.pem에는 개인 키가 평문으로 들어 있으니 반드시 삭제하세요. -legacy 옵션이 필요한 이유는 OpenSSL 3이 RC2·RC4·단일 DES를 legacy 프로바이더로 옮겼고 Java도 같은 알고리즘을 기본 처리에서 제외했기 때문입니다. 2015년식 장비가 만든 파일은 손상된 것이 아니라 아무도 켜지 않는 알고리즘으로 암호화되어 있을 뿐입니다.
- MAC 비밀번호와 암호화 비밀번호는 다른가요?
- 원칙적으로는 다를 수 있습니다. RFC 7292는 무결성 MAC과 기밀성 암호화에 서로 다른 비밀번호를 허용하고 일부 기업용 도구가 실제로 그렇게 씁니다. 다만 일반적인 내보내기 도구는 모두 같은 문자열을 쓰기 때문에 MAC 실패는 거의 언제나 변조가 아니라 비밀번호 오류입니다. 키 유도 방식도 다릅니다. MAC 키는 부록 B의 PKCS#12 유도(ID 3)로 만들고, 최신 가방 암호화는 비밀번호 바이트에 PBKDF2를 적용합니다. 그래서 정말 두 개의 비밀번호로 만들어진 파일이라면 MAC은 통과하고 복호화만 실패할 수 있습니다.
- .p12는 열리는데 개인 키가 없습니다. 어디로 갔나요?
- 애초에 내보내지지 않았을 가능성이 큽니다. `openssl pkcs12 -export -nokeys`, 그리고 브라우저나 MMC 콘솔의 "인증서 체인 내보내기" 버튼 대부분은 certBag만 담긴 인증서 전용 키스토어를 만듭니다. 이 파일은 형식상 완전히 정상이라 웹 서버나 로드 밸런서가 불평 없이 가져온 뒤 TLS 핸드셰이크에서 키 불일치로 실패합니다. 이 도구의 가방 목록에는 어떤 가방이 있는지 그대로 나오므로 배포 전에 키 가방이 없다는 사실을 확인할 수 있습니다.
- 로컬 키 ID는 무엇에 쓰이나요?
- localKeyID는 인증서 가방과 키 가방을 짝지어 주는 속성입니다. 키스토어에는 인증서와 키가 여러 개 들어갈 수 있기 때문입니다. OpenSSL은 인증서 공개 키의 SHA-1 해시를 쓰고 Windows와 Java는 각자의 값을 쓰며, 규격이 특정 방식을 요구하지는 않습니다. friendlyName은 사람이 보는 별칭으로 keytool 목록과 Windows 인증서 저장소에 표시되며, 기존 별칭과 겹치는 키스토어를 가져오면 "alias already exists" 오류가 납니다. 두 값 모두 가방별로, 어느 블록에서 나왔는지와 함께 표시됩니다.
- 개인 키가 든 키스토어를 웹 페이지에서 열어도 안전한가요?
- 이 페이지는 파일도 비밀번호도 어디에도 보내지 않습니다. 파싱, MAC 검증, PBKDF2, AES-CBC 복호화, 키와 인증서 비교까지 모두 WebCrypto로 탭 안에서 실행되고 비밀번호는 컴포넌트 상태에만 있다가 탭을 닫으면 사라집니다. localStorage에는 파일 이름만 남습니다. 그렇더라도 운영용 키스토어라면 오프라인 `openssl pkcs12 -info`로 확인하는 습관이 가장 안전합니다. 이 도구는 디버깅 중인 파일에 쓰고, .p12 업로드를 요구하는 웹 도구는 마땅히 의심하세요.
관련 도구
CSR 디코더 (PKCS#10)
인증서 서명 요청을 보내기 전에 확인합니다. 주체, SAN, 키 길이, 서명 알고리즘, 그리고 자체 서명이 검증되는지까지.
JSON 스키마 검사기
JSON 문서를 JSON 스키마로 브라우저에서 검사합니다. 오류마다 JSON 포인터, 문서에서의 줄 번호, 실패한 키워드를 보여줍니다.
CRL 디코더 (X.509)
인증서 폐기 목록을 브라우저에서 읽습니다. 발급자, CRL 번호, 유효 구간, 폐기된 일련번호와 사유, 서명 검증까지.
랜덤 IP·MAC 생성기
테스트·목 데이터용 IPv4·IPv6·MAC 일괄 생성 — public·private·ULA·link-local·UAA·LAA 범위 지원.
Bcrypt 해시 / 검증
조정 가능한 cost로 bcrypt 해시 생성, 또는 기존 해시와 비밀번호 일치 검증 — 브라우저 안에서 실행.
PGP 공개키 검사기
ASCII 아머 형식 OpenPGP 공개키를 해석합니다. 전체 지문, 키 ID, 알고리즘, 길이, 생성·만료일, 사용자 ID와 서브키를 보여 줍니다.